mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:49:43 +00:00
Filter LSP completion requests when offset is mid-symbol
Change-Id: I28bf5ddda1d7d6f1177a602d9f2dd3091f35966d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151847 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Danny Tuppeny <danny@tuppeny.com>
This commit is contained in:
parent
f0c87e9f21
commit
2d73cb53a1
|
@ -362,26 +362,38 @@ class CompletionHandler
|
|||
}
|
||||
|
||||
/// Return the pattern to match suggestions against, from the identifier
|
||||
/// to the left of the caret. Return the empty string if cannot find the
|
||||
/// identifier.
|
||||
/// to the left of (or spanning) the caret. Return the empty string if cannot
|
||||
/// find the identifier.
|
||||
///
|
||||
/// If the caret is within the identifier, the returned pattern will be truncated
|
||||
/// to the position of the caret. For example at:
|
||||
///
|
||||
/// new MyClass^Foo
|
||||
///
|
||||
/// will return "MyClass" as the search pattern.
|
||||
String _prefixMatchingPattern(DartCompletionRequestImpl request) {
|
||||
final nodeAtOffsetVisitor =
|
||||
_IdentifierEndingAtOffsetVisitor(request.offset);
|
||||
request.target.containingNode.accept(nodeAtOffsetVisitor);
|
||||
final nodeSpanningOffsetVisitor =
|
||||
_IdentifierSpanningOffsetVisitor(request.offset);
|
||||
request.target.containingNode.accept(nodeSpanningOffsetVisitor);
|
||||
final node = nodeSpanningOffsetVisitor.matchingNode;
|
||||
|
||||
return nodeAtOffsetVisitor.matchingNode?.name ?? '';
|
||||
final prefix = node != null && request.offset - node.offset < node.length
|
||||
? node.name.substring(0, request.offset - node.offset)
|
||||
: node?.name;
|
||||
|
||||
return prefix ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
/// An AST visitor to locate a [SimpleIdentifier] that ends at the provided offset.
|
||||
class _IdentifierEndingAtOffsetVisitor extends RecursiveAstVisitor<void> {
|
||||
/// An AST visitor to locate a [SimpleIdentifier] that spans the provided offset.
|
||||
class _IdentifierSpanningOffsetVisitor extends RecursiveAstVisitor<void> {
|
||||
final int offset;
|
||||
SimpleIdentifier _matchingNode;
|
||||
_IdentifierEndingAtOffsetVisitor(this.offset);
|
||||
_IdentifierSpanningOffsetVisitor(this.offset);
|
||||
SimpleIdentifier get matchingNode => _matchingNode;
|
||||
@override
|
||||
void visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
if (node.end == offset) {
|
||||
if (node.offset <= offset && node.end >= offset) {
|
||||
_matchingNode = node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,7 +417,7 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
expect(updated, contains('a.abcdefghij'));
|
||||
}
|
||||
|
||||
Future<void> test_prefixFilter() async {
|
||||
Future<void> test_prefixFilter_endOfSymbol() async {
|
||||
final content = '''
|
||||
class UniqueNamedClassForLspOne {}
|
||||
class UniqueNamedClassForLspTwo {}
|
||||
|
@ -425,7 +425,7 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
|
||||
main() {
|
||||
// Should match only Two and Three
|
||||
class UniqueNamedClassForLspT^
|
||||
UniqueNamedClassForLspT^
|
||||
}
|
||||
''';
|
||||
|
||||
|
@ -437,6 +437,46 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
|
|||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
|
||||
}
|
||||
|
||||
Future<void> test_prefixFilter_midSymbol() async {
|
||||
final content = '''
|
||||
class UniqueNamedClassForLspOne {}
|
||||
class UniqueNamedClassForLspTwo {}
|
||||
class UniqueNamedClassForLspThree {}
|
||||
|
||||
main() {
|
||||
// Should match only Two and Three
|
||||
UniqueNamedClassForLspT^hree
|
||||
}
|
||||
''';
|
||||
|
||||
await initialize();
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isFalse);
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspTwo'), isTrue);
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
|
||||
}
|
||||
|
||||
Future<void> test_prefixFilter_startOfSymbol() async {
|
||||
final content = '''
|
||||
class UniqueNamedClassForLspOne {}
|
||||
class UniqueNamedClassForLspTwo {}
|
||||
class UniqueNamedClassForLspThree {}
|
||||
|
||||
main() {
|
||||
// Should match all three
|
||||
^UniqueNamedClassForLspT
|
||||
}
|
||||
''';
|
||||
|
||||
await initialize();
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
final res = await getCompletion(mainFileUri, positionFromMarker(content));
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isTrue);
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspTwo'), isTrue);
|
||||
expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
|
||||
}
|
||||
|
||||
Future<void> test_suggestionSets() async {
|
||||
newFile(
|
||||
join(projectFolderPath, 'other_file.dart'),
|
||||
|
|
Loading…
Reference in a new issue