Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit 573d3db

Browse files
jakebaileyMikhail Arkhipov
authored and
Mikhail Arkhipov
committed
Add loose fuzzy matching for workspace symbol queries (#1950)
* Add loose fuzzy matching for workspace symbol queries * Make function static (cherry picked from commit d3dff55)
1 parent 7636d3b commit 573d3db

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/LanguageServer/Impl/Indexing/SymbolIndex.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private IEnumerable<FlatSymbol> WorkspaceSymbolsQuery(string path, string query,
9898
var sym = symAndPar.symbol;
9999
return DecorateWithParentsName((sym.Children ?? Enumerable.Empty<HierarchicalSymbol>()).ToList(), sym.Name);
100100
});
101-
return treeSymbols.Where(sym => sym.symbol.Name.ContainsOrdinal(query, ignoreCase: true))
101+
return treeSymbols.Where(sym => FuzzyMatch(query, sym.symbol.Name))
102102
.Select(sym => new FlatSymbol(sym.symbol.Name, sym.symbol.Kind, path, sym.symbol.SelectionRange, sym.parentName, sym.symbol._existInAllVariable));
103103
}
104104

@@ -114,5 +114,19 @@ private IMostRecentDocumentSymbols MakeMostRecentDocSymbols(string path) {
114114
public void Dispose() {
115115
_disposables.TryDispose();
116116
}
117+
118+
private static bool FuzzyMatch(string pattern, string name) {
119+
var patternPos = 0;
120+
var namePos = 0;
121+
122+
while (patternPos < pattern.Length && namePos < name.Length) {
123+
if (char.ToLowerInvariant(pattern[patternPos]) == char.ToLowerInvariant(name[namePos])) {
124+
patternPos++;
125+
}
126+
namePos++;
127+
}
128+
129+
return patternPos == pattern.Length;
130+
}
117131
}
118132
}

src/LanguageServer/Test/SymbolIndexTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,23 @@ public async Task IndexWorkspaceSymbolsCaseInsensitiveAsync() {
160160
}
161161
}
162162

163+
[TestMethod, Priority(0)]
164+
public async Task IndexWorkspaceSymbolsFuzzyAsync() {
165+
const string code = @"class FXoo(object):
166+
def foxo(self, x): ...";
167+
168+
using (var index = MakeSymbolIndex()) {
169+
var path = TestData.GetDefaultModulePath();
170+
index.Add(path, DocumentWithAst(code));
171+
172+
var symbols = await index.WorkspaceSymbolsAsync("foo", maxSymbols);
173+
symbols.Should().BeEquivalentToWithStrictOrdering(new[] {
174+
new FlatSymbol("FXoo", SymbolKind.Class, path, new SourceSpan(1, 7, 1, 11)),
175+
new FlatSymbol("foxo", SymbolKind.Method, path, new SourceSpan(2, 9, 2, 13), "FXoo"),
176+
});
177+
}
178+
}
179+
163180
[TestMethod, Priority(0)]
164181
public void MarkAsPendingWaitsForUpdates() {
165182
using (var index = MakeSymbolIndex()) {

0 commit comments

Comments
 (0)