[ty] Add ty.inlayHints.variableTypes server option (#19780)

## Summary

This PR adds a new `ty.inlayHints.variableTypes` server setting to
configure ty to include / exclude inlay hints at variable position.

Currently, we only support inlay hints at this position so this option
basically translates to enabling / disabling inlay hints for now :)

The VS Code extension PR is
https://github.com/astral-sh/ty-vscode/pull/112.

closes: astral-sh/ty#472

## Test Plan

Add E2E tests.
This commit is contained in:
Dhruv Manilawala 2025-08-07 19:16:51 +05:30 committed by GitHub
parent c401a6d86e
commit b22586fa0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 181 additions and 20 deletions

View file

@ -51,8 +51,13 @@ impl fmt::Display for DisplayInlayHint<'_, '_> {
}
}
pub fn inlay_hints(db: &dyn Db, file: File, range: TextRange) -> Vec<InlayHint<'_>> {
let mut visitor = InlayHintVisitor::new(db, file, range);
pub fn inlay_hints<'db>(
db: &'db dyn Db,
file: File,
range: TextRange,
settings: &InlayHintSettings,
) -> Vec<InlayHint<'db>> {
let mut visitor = InlayHintVisitor::new(db, file, range, settings);
let ast = parsed_module(db, file).load(db);
@ -61,20 +66,34 @@ pub fn inlay_hints(db: &dyn Db, file: File, range: TextRange) -> Vec<InlayHint<'
visitor.hints
}
struct InlayHintVisitor<'db> {
/// Settings to control the behavior of inlay hints.
#[derive(Clone, Default, Debug)]
pub struct InlayHintSettings {
/// Whether to show variable type hints.
///
/// For example, this would enable / disable hints like the ones quoted below:
/// ```python
/// x": Literal[1]" = 1
/// ```
pub variable_types: bool,
}
struct InlayHintVisitor<'a, 'db> {
model: SemanticModel<'db>,
hints: Vec<InlayHint<'db>>,
in_assignment: bool,
range: TextRange,
settings: &'a InlayHintSettings,
}
impl<'db> InlayHintVisitor<'db> {
fn new(db: &'db dyn Db, file: File, range: TextRange) -> Self {
impl<'a, 'db> InlayHintVisitor<'a, 'db> {
fn new(db: &'db dyn Db, file: File, range: TextRange, settings: &'a InlayHintSettings) -> Self {
Self {
model: SemanticModel::new(db, file),
hints: Vec::new(),
in_assignment: false,
range,
settings,
}
}
@ -86,7 +105,7 @@ impl<'db> InlayHintVisitor<'db> {
}
}
impl SourceOrderVisitor<'_> for InlayHintVisitor<'_> {
impl SourceOrderVisitor<'_> for InlayHintVisitor<'_, '_> {
fn enter_node(&mut self, node: AnyNodeRef<'_>) -> TraversalSignal {
if self.range.intersect(node.range()).is_some() {
TraversalSignal::Traverse
@ -104,6 +123,10 @@ impl SourceOrderVisitor<'_> for InlayHintVisitor<'_> {
match stmt {
Stmt::Assign(assign) => {
if !self.settings.variable_types {
return;
}
self.in_assignment = true;
for target in &assign.targets {
self.visit_expr(target);
@ -213,8 +236,21 @@ mod tests {
}
impl InlayHintTest {
/// Returns the inlay hints for the given test case.
///
/// All inlay hints are generated using the applicable settings. Use
/// [`inlay_hints_with_settings`] to generate hints with custom settings.
///
/// [`inlay_hints_with_settings`]: Self::inlay_hints_with_settings
fn inlay_hints(&self) -> String {
let hints = inlay_hints(&self.db, self.file, self.range);
self.inlay_hints_with_settings(&InlayHintSettings {
variable_types: true,
})
}
/// Returns the inlay hints for the given test case with custom settings.
fn inlay_hints_with_settings(&self, settings: &InlayHintSettings) -> String {
let hints = inlay_hints(&self.db, self.file, self.range, settings);
let mut buf = source_text(&self.db, self.file).as_str().to_string();
@ -276,4 +312,18 @@ mod tests {
y = 2
");
}
#[test]
fn disabled_variable_types() {
let test = inlay_hint_test("x = 1");
assert_snapshot!(
test.inlay_hints_with_settings(&InlayHintSettings {
variable_types: false,
}),
@r"
x = 1
"
);
}
}