Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion crates/ty_ide/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,8 @@ fn find_typed_text(
if last.end() < offset || last.range().is_empty() {
return None;
}
Some(source[last.range()].to_string())
let range = TextRange::new(last.start(), offset);
Some(source[range].to_string())
}

/// Whether the last token is in a place where we should not provide completions.
Expand Down Expand Up @@ -1406,6 +1407,24 @@ fn is_in_variable_binding(parsed: &ParsedModuleRef, offset: TextSize, typed: Opt
type_param.name.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))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me. Nice find!

_ => false,
})
}
Expand Down Expand Up @@ -1633,6 +1652,21 @@ mod tests {
);
}

#[test]
fn inside_token() {
let test = completion_test_builder(
"\
foo_bar_baz = 1
x = foo<CURSOR>bad
",
);

assert_snapshot!(
test.skip_builtins().build().snapshot(),
@"foo_bar_baz",
);
}

#[test]
fn type_keyword_dedup() {
let test = completion_test_builder(
Expand Down Expand Up @@ -5347,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]
fn no_completions_in_function_type_param() {
let builder = completion_test_builder(
Expand Down
Loading