diff --git a/dsymbol/dub.json b/dsymbol/dub.json index 8e2c5e2b..86efe2d1 100644 --- a/dsymbol/dub.json +++ b/dsymbol/dub.json @@ -7,6 +7,7 @@ "targetType": "library", "dependencies": { "libdparse": ">=0.20.0 <1.0.0", - "emsi_containers": "~>0.9.0" + "emsi_containers": "~>0.9.0", + "fuzzymatch": "~>1.0" } } diff --git a/dsymbol/src/dsymbol/ufcs.d b/dsymbol/src/dsymbol/ufcs.d index 96d43775..e2b52372 100644 --- a/dsymbol/src/dsymbol/ufcs.d +++ b/dsymbol/src/dsymbol/ufcs.d @@ -231,12 +231,12 @@ private DSymbol*[] getUFCSSymbolsForDotCompletion(const(DSymbol)* symbolType, Sc // local appender FilteredAppender!((DSymbol* a) => a.isCallableWithArg(symbolType) - && toUpper(a.name.data).startsWith(toUpper(partial)), + && prettyFuzzyMatch(a.name.data, partial), DSymbol*[]) localAppender; // global appender FilteredAppender!((DSymbol* a) => a.isCallableWithArg(symbolType, true) - && toUpper(a.name.data).startsWith(toUpper(partial)), + && prettyFuzzyMatch(a.name.data, partial), DSymbol*[]) globalAppender; getUFCSSymbols(localAppender, globalAppender, completionScope, cursorPosition); diff --git a/dsymbol/src/dsymbol/utils.d b/dsymbol/src/dsymbol/utils.d index b2c88d8d..02de25cb 100644 --- a/dsymbol/src/dsymbol/utils.d +++ b/dsymbol/src/dsymbol/utils.d @@ -153,3 +153,19 @@ unittest i = skipParenReverseBefore(t, i, tok!")", tok!"("); assert(i == 1); } + +/// Checks if `doesThis` roughly starts with `matchThis`, case-insensitive +bool prettyFuzzyMatch(scope const(char)[] doesThis, scope const(char)[] matchThis) @safe pure nothrow @nogc +{ + import fuzzymatch; + + if (!matchThis.length) + return true; + + // return false if identifier starts with _, but search doesn't or vice-versa + if (doesThis.length && (doesThis[0] == '_' && matchThis[0] != '_' + || doesThis[0] != '_' && matchThis[0] == '_')) + return false; + + return fuzzyMatchesString(doesThis, matchThis); +} diff --git a/dub.selections.json b/dub.selections.json index 072114b6..ac88801d 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -3,6 +3,7 @@ "versions": { "dsymbol": "0.14.1", "emsi_containers": "0.9.0", + "fuzzymatch": "1.0.0", "libdparse": "0.22.0", "msgpack-d": "1.0.4", "stdx-allocator": "2.77.5" diff --git a/src/dcd/server/autocomplete/complete.d b/src/dcd/server/autocomplete/complete.d index 4363bf05..010f65e0 100644 --- a/src/dcd/server/autocomplete/complete.d +++ b/src/dcd/server/autocomplete/complete.d @@ -188,7 +188,6 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray, { partial = t.text[0 .. cursorPosition - t.index]; // issue 442 - prevent `partial` to start in the middle of a MBC - // since later there's a non-nothrow call to `toUpper` import std.utf : validate, UTFException; try validate(partial); catch (UTFException) @@ -513,7 +512,7 @@ void setCompletions(T)(ref AutocompleteResponse response, foreach (sym; s.opSlice()) { if (sym.name !is null && sym.name.length > 0 && isPublicCompletionKind(sym.kind) - && (p is null ? true : toUpper(sym.name.data).startsWith(toUpper(p))) + && prettyFuzzyMatch(sym.name.data, p) && !r.completions.canFind!(a => a.identifier == sym.name) && sym.name[0] != '*' && mightBeRelevantInCompletionScope(sym, completionScope)) @@ -531,7 +530,7 @@ void setCompletions(T)(ref AutocompleteResponse response, { auto currentSymbols = completionScope.getSymbolsInCursorScope(cursorPosition); foreach (s; currentSymbols.filter!(a => isPublicCompletionKind(a.kind) - && toUpper(a.name.data).startsWith(toUpper(partial)) + && prettyFuzzyMatch(a.name.data, partial) && mightBeRelevantInCompletionScope(a, completionScope))) { response.completions ~= makeSymbolCompletionInfo(s, s.kind); @@ -549,8 +548,7 @@ void setCompletions(T)(ref AutocompleteResponse response, && a.kind != CompletionKind.importSymbol && a.kind != CompletionKind.dummy && a.symbolFile == "stdin" - && (partial !is null && toUpper(a.name.data).startsWith(toUpper(partial)) - || partial is null) + && prettyFuzzyMatch(a.name.data, partial) && mightBeRelevantInCompletionScope(a, completionScope))) { response.completions ~= makeSymbolCompletionInfo(s, s.kind); diff --git a/tests/tc021/expected.txt b/tests/tc021/expected.txt index 5ca5907f..93759409 100644 --- a/tests/tc021/expected.txt +++ b/tests/tc021/expected.txt @@ -3,3 +3,6 @@ idouble k ifloat k int k ireal k +string l +uint k +void k diff --git a/tests/tc029/expected1.txt b/tests/tc029/expected1.txt index 10b84c98..e6e33c72 100644 --- a/tests/tc029/expected1.txt +++ b/tests/tc029/expected1.txt @@ -6,3 +6,6 @@ cfloat k char k complicatedLess l creal k +dchar k +ucent k +wchar k diff --git a/tests/tc051/expected.txt b/tests/tc051/expected.txt index 16cf9193..f4764bba 100644 --- a/tests/tc051/expected.txt +++ b/tests/tc051/expected.txt @@ -1,3 +1,5 @@ identifiers Foo s +cfloat k float k +ifloat k diff --git a/tests/tc_accesschain_type/expected.txt b/tests/tc_accesschain_type/expected.txt index 0d369462..89295373 100644 --- a/tests/tc_accesschain_type/expected.txt +++ b/tests/tc_accesschain_type/expected.txt @@ -1,2 +1,7 @@ identifiers +alignof k foo f +mangleof k +sizeof k +stringof k +tupleof k diff --git a/tests/tc_complete_kw/expected3.txt b/tests/tc_complete_kw/expected3.txt index 2c6ad481..0808c655 100644 --- a/tests/tc_complete_kw/expected3.txt +++ b/tests/tc_complete_kw/expected3.txt @@ -1,2 +1,3 @@ identifiers +init k internal v diff --git a/tests/tc_extended_ditto/expected1.txt b/tests/tc_extended_ditto/expected1.txt index df0cd3d2..39597e1d 100644 --- a/tests/tc_extended_ditto/expected1.txt +++ b/tests/tc_extended_ditto/expected1.txt @@ -1,3 +1,6 @@ identifiers +cfloat k cfloat +float k float foo f void foo() stdin 26 my documentation void foo f void foo(int i) stdin 49 my documentation void +ifloat k ifloat