[ty] Improve autocomplete suppressions of keywords in variable bindings

Autocomplete suggestions were not suppressed correctly during
some variable bindings if the parameter name was currently
matching a keyword. E.g. `def f(foo<CURSOR>` was handled
correctly but not `def f(in<CURSOR>`.
This commit is contained in:
Rasmus Nygren 2025-11-22 12:40:51 +01:00 committed by Andrew Gallant
parent de32247f30
commit 4628180fac
1 changed files with 57 additions and 0 deletions

View File

@ -1407,6 +1407,24 @@ fn is_in_variable_binding(parsed: &ParsedModuleRef, offset: TextSize, typed: Opt
type_param.name.range.contains_range(range) type_param.name.range.contains_range(range)
} }
ast::AnyNodeRef::StmtFor(stmt_for) => stmt_for.target.range().contains_range(range), ast::AnyNodeRef::StmtFor(stmt_for) => stmt_for.target.range().contains_range(range),
// The AST does not produce `ast::AnyNodeRef::Parameter` nodes for keywords
// or otherwise invalid syntax. Rather they are captured in a
// `ast::AnyNodeRef::Parameters` node as "empty space". To ensure
// we still suppress suggestions even when the syntax is technically
// invalid we extract the token under the cursor and check if it makes
// up that "empty space" inside the Parameters Node. If it does, we know
// that we are still binding variables, just that the current state is
// syntatically invalid. Hence we suppress autocomplete suggestons
// also in those cases.
ast::AnyNodeRef::Parameters(params) => {
if !params.range.contains_range(range) {
return false;
}
params
.iter()
.map(|param| param.range())
.all(|r| !r.contains_range(range))
}
_ => false, _ => false,
}) })
} }
@ -5363,6 +5381,45 @@ def foo(p<CURSOR>
); );
} }
#[test]
fn no_completions_in_function_param_keyword() {
let builder = completion_test_builder(
"\
def foo(in<CURSOR>
",
);
assert_snapshot!(
builder.build().snapshot(),
@"<No completions found>",
);
}
#[test]
fn no_completions_in_function_param_multi_keyword() {
let builder = completion_test_builder(
"\
def foo(param, in<CURSOR>
",
);
assert_snapshot!(
builder.build().snapshot(),
@"<No completions found>",
);
}
#[test]
fn no_completions_in_function_param_multi_keyword_middle() {
let builder = completion_test_builder(
"\
def foo(param, in<CURSOR>, param_two
",
);
assert_snapshot!(
builder.build().snapshot(),
@"<No completions found>",
);
}
#[test] #[test]
fn no_completions_in_function_type_param() { fn no_completions_in_function_type_param() {
let builder = completion_test_builder( let builder = completion_test_builder(