Skip to content

Commit 5c3f921

Browse files
DanTupcommit-bot@chromium.org
authored andcommitted
Filter LSP completions (fuzzily) by prefix to reduce payload size
Bug: #42152. Bug: #40026. Change-Id: I4c921ddff3224d736c4236861d0ff156f58be595 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/150628 Commit-Queue: Danny Tuppeny <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 9e2f112 commit 5c3f921

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ import 'package:analysis_server/src/provisional/completion/completion_core.dart'
1616
import 'package:analysis_server/src/services/completion/completion_core.dart';
1717
import 'package:analysis_server/src/services/completion/completion_performance.dart';
1818
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
19+
import 'package:analysis_server/src/services/completion/filtering/fuzzy_matcher.dart';
1920
import 'package:analyzer/dart/analysis/results.dart';
21+
import 'package:analyzer/dart/ast/ast.dart' show SimpleIdentifier;
22+
import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor;
2023
import 'package:analyzer/source/line_info.dart';
2124
import 'package:analyzer/src/services/available_declarations.dart';
2225
import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -189,6 +192,10 @@ class CompletionHandler
189192

190193
final completionRequest = CompletionRequestImpl(
191194
unit, offset, server.options.useNewRelevance, performance);
195+
final directiveInfo =
196+
server.getDartdocDirectiveInfoFor(completionRequest.result);
197+
final dartCompletionRequest =
198+
await DartCompletionRequestImpl.from(completionRequest, directiveInfo);
192199

193200
Set<ElementKind> includedElementKinds;
194201
Set<String> includedElementNames;
@@ -201,8 +208,7 @@ class CompletionHandler
201208

202209
try {
203210
CompletionContributor contributor = DartCompletionManager(
204-
dartdocDirectiveInfo:
205-
server.getDartdocDirectiveInfoFor(completionRequest.result),
211+
dartdocDirectiveInfo: directiveInfo,
206212
includedElementKinds: includedElementKinds,
207213
includedElementNames: includedElementNames,
208214
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
@@ -312,12 +318,21 @@ class CompletionHandler
312318
results.addAll(setResults);
313319
});
314320

321+
// Perform fuzzy matching based on the identifier in front of the caret to
322+
// reduce the size of the payload.
323+
final fuzzyPattern = _prefixMatchingPattern(dartCompletionRequest);
324+
final fuzzyMatcher =
325+
FuzzyMatcher(fuzzyPattern, matchStyle: MatchStyle.TEXT);
326+
327+
final matchingResults =
328+
results.where((e) => fuzzyMatcher.score(e.label) > 0).toList();
329+
315330
performance.notificationCount = 1;
316331
performance.suggestionCountFirst = results.length;
317332
performance.suggestionCountLast = results.length;
318333
performance.complete();
319334

320-
return success(results);
335+
return success(matchingResults);
321336
} on AbortCompletion {
322337
return success([]);
323338
}
@@ -342,4 +357,29 @@ class CompletionHandler
342357
);
343358
});
344359
}
360+
361+
/// Return the pattern to match suggestions against, from the identifier
362+
/// to the left of the caret. Return the empty string if cannot find the
363+
/// identifier.
364+
String _prefixMatchingPattern(DartCompletionRequestImpl request) {
365+
final nodeAtOffsetVisitor =
366+
_IdentifierEndingAtOffsetVisitor(request.offset);
367+
request.target.containingNode.accept(nodeAtOffsetVisitor);
368+
369+
return nodeAtOffsetVisitor.matchingNode?.name ?? '';
370+
}
371+
}
372+
373+
/// An AST visitor to locate a [SimpleIdentifier] that ends at the provided offset.
374+
class _IdentifierEndingAtOffsetVisitor extends RecursiveAstVisitor<void> {
375+
final int offset;
376+
SimpleIdentifier _matchingNode;
377+
_IdentifierEndingAtOffsetVisitor(this.offset);
378+
SimpleIdentifier get matchingNode => _matchingNode;
379+
@override
380+
void visitSimpleIdentifier(SimpleIdentifier node) {
381+
if (node.end == offset) {
382+
_matchingNode = node;
383+
}
384+
}
345385
}

pkg/analysis_server/test/lsp/completion_test.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,26 @@ class CompletionTest extends AbstractLspAnalysisServerTest {
374374
expect(updated, contains('a.abcdefghij'));
375375
}
376376

377+
Future<void> test_prefixFilter() async {
378+
final content = '''
379+
class UniqueNamedClassForLspOne {}
380+
class UniqueNamedClassForLspTwo {}
381+
class UniqueNamedClassForLspThree {}
382+
383+
main() {
384+
// Should match only Two and Three
385+
class UniqueNamedClassForLspT^
386+
}
387+
''';
388+
389+
await initialize();
390+
await openFile(mainFileUri, withoutMarkers(content));
391+
final res = await getCompletion(mainFileUri, positionFromMarker(content));
392+
expect(res.any((c) => c.label == 'UniqueNamedClassForLspOne'), isFalse);
393+
expect(res.any((c) => c.label == 'UniqueNamedClassForLspTwo'), isTrue);
394+
expect(res.any((c) => c.label == 'UniqueNamedClassForLspThree'), isTrue);
395+
}
396+
377397
Future<void> test_suggestionSets() async {
378398
newFile(
379399
join(projectFolderPath, 'other_file.dart'),

0 commit comments

Comments
 (0)