mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-29 19:07:08 +00:00
Rename SubstringMatch to SubsequenceMatch and use it to pre-filter completion items
Fix #321
This commit is contained in:
parent
2e0f14bef8
commit
c36eda70f9
@ -188,31 +188,17 @@ std::string LexWordAroundPos(lsPosition position, const std::string& content) {
|
||||
return content.substr(start, end - start + 1);
|
||||
}
|
||||
|
||||
bool SubstringMatch(const std::string& search, const std::string& content) {
|
||||
if (search.empty())
|
||||
return true;
|
||||
|
||||
size_t search_index = 0;
|
||||
char search_char = tolower(search[search_index]);
|
||||
|
||||
size_t content_index = 0;
|
||||
|
||||
while (true) {
|
||||
char content_char = tolower(content[content_index]);
|
||||
|
||||
if (content_char == search_char) {
|
||||
search_index += 1;
|
||||
if (search_index >= search.size())
|
||||
return true;
|
||||
search_char = tolower(search[search_index]);
|
||||
}
|
||||
|
||||
content_index += 1;
|
||||
if (content_index >= content.size())
|
||||
bool SubsequenceMatch(const std::string& search, const std::string& content) {
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < search.size(); i++) {
|
||||
char search_char = tolower(search[i]);
|
||||
while (j < content.size() && tolower(content[j]) != search_char)
|
||||
j++;
|
||||
if (j == content.size())
|
||||
return false;
|
||||
j++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_SUITE("Offset") {
|
||||
@ -239,32 +225,32 @@ TEST_SUITE("Offset") {
|
||||
TEST_SUITE("Substring") {
|
||||
TEST_CASE("match") {
|
||||
// Sanity.
|
||||
REQUIRE(SubstringMatch("a", "aa"));
|
||||
REQUIRE(SubstringMatch("aa", "aa"));
|
||||
REQUIRE(SubsequenceMatch("a", "aa"));
|
||||
REQUIRE(SubsequenceMatch("aa", "aa"));
|
||||
|
||||
// Empty string matches anything.
|
||||
REQUIRE(SubstringMatch("", ""));
|
||||
REQUIRE(SubstringMatch("", "aa"));
|
||||
REQUIRE(SubsequenceMatch("", ""));
|
||||
REQUIRE(SubsequenceMatch("", "aa"));
|
||||
|
||||
// Match in start/middle/end.
|
||||
REQUIRE(SubstringMatch("a", "abbbb"));
|
||||
REQUIRE(SubstringMatch("a", "bbabb"));
|
||||
REQUIRE(SubstringMatch("a", "bbbba"));
|
||||
REQUIRE(SubstringMatch("aa", "aabbb"));
|
||||
REQUIRE(SubstringMatch("aa", "bbaab"));
|
||||
REQUIRE(SubstringMatch("aa", "bbbaa"));
|
||||
REQUIRE(SubsequenceMatch("a", "abbbb"));
|
||||
REQUIRE(SubsequenceMatch("a", "bbabb"));
|
||||
REQUIRE(SubsequenceMatch("a", "bbbba"));
|
||||
REQUIRE(SubsequenceMatch("aa", "aabbb"));
|
||||
REQUIRE(SubsequenceMatch("aa", "bbaab"));
|
||||
REQUIRE(SubsequenceMatch("aa", "bbbaa"));
|
||||
|
||||
// Capitalization.
|
||||
REQUIRE(SubstringMatch("aa", "aA"));
|
||||
REQUIRE(SubstringMatch("aa", "Aa"));
|
||||
REQUIRE(SubstringMatch("aa", "AA"));
|
||||
REQUIRE(SubsequenceMatch("aa", "aA"));
|
||||
REQUIRE(SubsequenceMatch("aa", "Aa"));
|
||||
REQUIRE(SubsequenceMatch("aa", "AA"));
|
||||
|
||||
// Token skipping.
|
||||
REQUIRE(SubstringMatch("ad", "abcd"));
|
||||
REQUIRE(SubstringMatch("ad", "ABCD"));
|
||||
REQUIRE(SubsequenceMatch("ad", "abcd"));
|
||||
REQUIRE(SubsequenceMatch("ad", "ABCD"));
|
||||
|
||||
// Ordering.
|
||||
REQUIRE(!SubstringMatch("ad", "dcba"));
|
||||
REQUIRE(!SubsequenceMatch("ad", "dcba"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,4 +24,5 @@ void LexFunctionDeclaration(const std::string& buffer_content,
|
||||
|
||||
std::string LexWordAroundPos(lsPosition position, const std::string& content);
|
||||
|
||||
bool SubstringMatch(const std::string& search, const std::string& content);
|
||||
// Case-insensitive subsequence matching.
|
||||
bool SubsequenceMatch(const std::string& search, const std::string& content);
|
||||
|
@ -128,6 +128,13 @@ void FilterAndSortCompletionResponse(
|
||||
return;
|
||||
}
|
||||
|
||||
items.erase(std::remove_if(items.begin(), items.end(),
|
||||
[&](const lsCompletionItem& item) {
|
||||
return !SubsequenceMatch(complete_text,
|
||||
item.label);
|
||||
}),
|
||||
items.end());
|
||||
|
||||
// Find the appearance of |complete_text| in all candidates.
|
||||
bool found = false;
|
||||
for (auto& item : items) {
|
||||
@ -187,7 +194,6 @@ void FilterAndSortCompletionResponse(
|
||||
// Find fuzzy matches if we haven't found all of the literal matches.
|
||||
if (filtered_result.size() < kMaxResultSize) {
|
||||
for (const auto& item : items) {
|
||||
if (SubstringMatch(complete_text, item.label)) {
|
||||
// Don't insert the same completion entry.
|
||||
if (!inserted.insert(item.InsertedContent()).second)
|
||||
continue;
|
||||
@ -197,7 +203,6 @@ void FilterAndSortCompletionResponse(
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items = filtered_result;
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ struct WorkspaceSymbolHandler : BaseMessageHandler<Ipc_WorkspaceSymbol> {
|
||||
query_without_space += c;
|
||||
|
||||
for (int i = 0; i < db->short_names.size(); ++i) {
|
||||
if (SubstringMatch(query_without_space, db->short_names[i])) {
|
||||
if (SubsequenceMatch(query_without_space, db->short_names[i])) {
|
||||
// Do not show the same entry twice.
|
||||
if (!inserted_results.insert(db->detailed_names[i]).second)
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user