Skip to content

Commit

Permalink
No completions in comments (#1999)
Browse files Browse the repository at this point in the history
Suppress completions inside comments like

```qsharp
import Foo;
// Hello there |
import Bar;
```
  • Loading branch information
minestarks authored Nov 1, 2024
1 parent 424ea6d commit b700869
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 20 deletions.
20 changes: 20 additions & 0 deletions language_service/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ fn expected_word_kinds(
source_contents: &str,
cursor_offset: u32,
) -> WordKinds {
// We should not retun any completions in comments.
// This compensates for a bug in [`possible_words_at_offset_in_source`] .
// Ideally, that function would be aware of the comment context and not
// return any completions, however this is difficult to do today because
// of the parser's unawareness of comment tokens.
// So we do a simple check here where we have access to the full source contents.
if in_comment(source_contents, cursor_offset) {
return WordKinds::empty();
}

match &compilation.kind {
CompilationKind::OpenProject {
package_graph_sources,
Expand All @@ -121,6 +131,16 @@ fn expected_word_kinds(
}
}

fn in_comment(source_contents: &str, cursor_offset: u32) -> bool {
// find the last newline before the cursor
let last_line_start = source_contents[..cursor_offset as usize]
.rfind('\n')
.unwrap_or(0);
// find the last comment start before the cursor
let last_comment_start = source_contents[last_line_start..cursor_offset as usize].rfind("//");
last_comment_start.is_some()
}

/// Collects hardcoded completions from the given set of parser predictions.
///
/// Hardcoded words are actual keywords (`let`, etc) as well as other words that are
Expand Down
60 changes: 40 additions & 20 deletions language_service/src/completion/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ fn check_with_dependency(
assert_no_duplicates(actual_completions);
}

fn check_no_completions(source_with_cursor: &str) {
let (compilation, cursor_position, _) = compile_with_markers(source_with_cursor, true);
let actual_completions =
get_completions(&compilation, "<source>", cursor_position, Encoding::Utf8);
assert_eq!(actual_completions.items, Vec::default());
}

fn assert_no_duplicates(mut actual_completions: CompletionList) {
actual_completions
.items
Expand Down Expand Up @@ -4075,42 +4082,55 @@ fn incomplete_return_type_in_partial_callable_signature() {

#[test]
fn no_path_segment_completion_inside_attr() {
check(
check_no_completions(
"namespace Test {
@Config(FakeStdLib.↘)
function Main() : Unit {
}
}",
&["Fake", "not", "Test"],
&expect![[r#"
[
None,
None,
None,
]
"#]],
);
}

#[test]
fn no_completion_inside_attr() {
check(
check_no_completions(
"namespace Test {
@Config(↘)
function Main() : Unit {
let FakeStdLib = new Foo { bar = 3 };
FakeStdLib.↘
}
}",
&["Fake", "not", "Test"],
&expect![[r#"
[
None,
None,
None,
]
"#]],
);
}

#[test]
fn in_comment() {
check_no_completions(
"namespace Test {
import Foo;
// Hello there ↘
import Bar;
}",
);
}

#[test]
fn in_doc_comment() {
check_no_completions(
"namespace Test {
import Foo;
/// Hello there ↘
import Bar;
}",
);
}

#[test]
fn in_trailing_comment() {
check_no_completions(
"namespace Test {
import Foo; // Hello there ↘
}",
);
}

0 comments on commit b700869

Please sign in to comment.