Skip to content
This repository has been archived by the owner on Jul 30, 2020. It is now read-only.

More options for completion filtering #786

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@
[submodule "third_party/reproc"]
path = third_party/reproc
url = https://github.com/DaanDeMeyer/reproc.git
[submodule "third_party/lib_fts"]
path = third_party/lib_fts
url = https://github.com/forrestthewoods/lib_fts.git
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ target_include_directories(cquery PRIVATE
third_party/pugixml/src
third_party/rapidjson/include
third_party/sparsepp
third_party/lib_fts/code
)

### Install
Expand Down Expand Up @@ -304,6 +305,8 @@ target_sources(cquery PRIVATE
src/file_contents.cc
src/file_types.cc
src/fuzzy_match.cc
src/fts_match.cc
src/prefix_match.cc
src/iindexer.cc
src/import_manager.cc
src/import_pipeline.cc
Expand Down
10 changes: 10 additions & 0 deletions src/completion_matcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <string_view.h>

class CompletionMatcher {
public:
virtual ~CompletionMatcher() = default;
virtual int Match(std::string_view text) = 0;
virtual int MinScore() const = 0;
};
11 changes: 10 additions & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ struct Config {
// For example, to hide all files in a /CACHE/ folder, use ".*/CACHE/.*"
std::vector<std::string> includeBlacklist;
std::vector<std::string> includeWhitelist;

// Matcher type to filter completion candidates.
// Available matchers are:
// "cqueryMatcher": default cquery fuzzy matching algorithm
// "ftsMatcher": fuzzy matching algorithm powered by
// lib_fts "caseSensitivePrefixMatcher": simple case sensitive prefix
// matcher "caseInsensitivePrefixMatcher": simple case insensitive prefix
std::string matcherType = "cqueryMatcher";
};
Completion completion;

Expand Down Expand Up @@ -261,7 +269,8 @@ MAKE_REFLECT_STRUCT(Config::Completion,
includeMaxPathSize,
includeSuffixWhitelist,
includeBlacklist,
includeWhitelist);
includeWhitelist,
matcherType);
MAKE_REFLECT_STRUCT(Config::Formatting, enabled)
MAKE_REFLECT_STRUCT(Config::Diagnostics,
blacklist,
Expand Down
23 changes: 23 additions & 0 deletions src/fts_match.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "fts_match.h"

#define FTS_FUZZY_MATCH_IMPLEMENTATION 1
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#include <fts_fuzzy_match.h>
#pragma clang diagnostic pop

FtsMatcher::FtsMatcher(std::string_view pattern) {
original_pattern = pattern;
}

int FtsMatcher::Match(std::string_view text) {
int result = 0;
if (fts::fuzzy_match(original_pattern.data(), text.data(), result)) {
return result;
}
return MinScore();
}

int FtsMatcher::MinScore() const {
return -100000;
}
13 changes: 13 additions & 0 deletions src/fts_match.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "completion_matcher.h"

class FtsMatcher : public CompletionMatcher {
public:
FtsMatcher(std::string_view pattern);
int Match(std::string_view text) override;
int MinScore() const override;

private:
std::string_view original_pattern;
};
9 changes: 9 additions & 0 deletions src/fuzzy_match.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdio.h>
#include <algorithm>
#include <vector>
#include "lex_utils.h"

enum CharClass { Other, Lower, Upper };
enum CharRole { None, Tail, Head };
Expand Down Expand Up @@ -73,6 +74,7 @@ int FuzzyMatcher::MatchScore(int i, int j, bool last) {
}

FuzzyMatcher::FuzzyMatcher(std::string_view pattern) {
original_pattern = pattern;
CalculateRoles(pattern, pat_role, &pat_set);
size_t n = 0;
for (size_t i = 0; i < pattern.size(); i++)
Expand All @@ -85,6 +87,9 @@ FuzzyMatcher::FuzzyMatcher(std::string_view pattern) {
}

int FuzzyMatcher::Match(std::string_view text) {
if (!CaseFoldingSubsequenceMatch(original_pattern, text).first) {
return MinScore();
}
int n = int(text.size());
if (n > kMaxText)
return kMinScore + 1;
Expand Down Expand Up @@ -123,6 +128,10 @@ int FuzzyMatcher::Match(std::string_view text) {
return ret;
}

int FuzzyMatcher::MinScore() const {
return kMinScore;
}

TEST_SUITE("fuzzy_match") {
bool Ranks(std::string_view pat, std::vector<const char*> texts) {
FuzzyMatcher fuzzy(pat);
Expand Down
7 changes: 5 additions & 2 deletions src/fuzzy_match.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

#include <limits.h>
#include <string>
#include "completion_matcher.h"

class FuzzyMatcher {
class FuzzyMatcher : public CompletionMatcher {
public:
constexpr static int kMaxPat = 100;
constexpr static int kMaxText = 200;
Expand All @@ -14,9 +15,11 @@ class FuzzyMatcher {
constexpr static int kMinScore = INT_MIN / 4;

FuzzyMatcher(std::string_view pattern);
int Match(std::string_view text);
int Match(std::string_view text) override;
int MinScore() const override;

private:
std::string_view original_pattern;
std::string pat;
std::string_view text;
int pat_set, text_set;
Expand Down
25 changes: 17 additions & 8 deletions src/messages/text_document_completion.cc
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#include "clang_complete.h"
#include "code_complete_cache.h"
#include "fuzzy_match.h"
#include "fts_match.h"
#include "prefix_match.h"
#include "include_complete.h"
#include "message_handler.h"
#include "queue_manager.h"
#include "timer.h"
#include "working_files.h"
#include "config.h"

#include "lex_utils.h"

Expand Down Expand Up @@ -221,17 +224,23 @@ void FilterAndSortCompletionResponse(
item.filterText = item.label;
}

// Fuzzy match and remove awful candidates.
FuzzyMatcher fuzzy(complete_text);
// Match and remove awful candidates.
std::unique_ptr<CompletionMatcher> matcher;
if (g_config->completion.matcherType == "cqueryMatcher") {
matcher = std::make_unique<FuzzyMatcher>(complete_text);
} else if (g_config->completion.matcherType == "ftsMatcher") {
matcher = std::make_unique<FtsMatcher>(complete_text);
} else if (g_config->completion.matcherType == "caseSensitivePrefixMatcher") {
matcher = std::make_unique<PrefixMatcher>(complete_text, true);
} else if (g_config->completion.matcherType == "caseInsensitivePrefixMatcher") {
matcher = std::make_unique<PrefixMatcher>(complete_text, false);
}
for (auto& item : items) {
item.score_ =
CaseFoldingSubsequenceMatch(complete_text, *item.filterText).first
? fuzzy.Match(*item.filterText)
: FuzzyMatcher::kMinScore;
item.score_ = matcher->Match(*item.filterText);
}
items.erase(std::remove_if(items.begin(), items.end(),
[](const lsCompletionItem& item) {
return item.score_ <= FuzzyMatcher::kMinScore;
[&matcher](const lsCompletionItem& item) {
return item.score_ <= matcher->MinScore();
}),
items.end());
std::sort(items.begin(), items.end(),
Expand Down
22 changes: 22 additions & 0 deletions src/prefix_match.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "prefix_match.h"

#include "utils.h"
#include <algorithm>
#include <cctype>

PrefixMatcher::PrefixMatcher(std::string_view pattern, bool case_sensitive) {
original_pattern = pattern;
this->case_sensitive = case_sensitive;
}

int PrefixMatcher::Match(std::string_view text) {
if (case_sensitive) {
return ::StartsWith(text, original_pattern) ? 1 : MinScore();
} else {
return ::StartsWithIgnoreCase(text, original_pattern) ? 1 : MinScore();
}
}

int PrefixMatcher::MinScore() const {
return -1;
}
14 changes: 14 additions & 0 deletions src/prefix_match.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "completion_matcher.h"

class PrefixMatcher : public CompletionMatcher {
public:
PrefixMatcher(std::string_view pattern, bool case_sensitive);
int Match(std::string_view text) override;
int MinScore() const override;

private:
std::string_view original_pattern;
bool case_sensitive;
};
6 changes: 6 additions & 0 deletions src/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ bool StartsWith(std::string_view value, std::string_view start) {
return std::equal(start.begin(), start.end(), value.begin());
}

bool StartsWithIgnoreCase(std::string_view value, std::string_view start) {
if (start.size() > value.size())
return false;
return std::equal(start.begin(), start.end(), value.begin(), [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); });
}

bool AnyStartsWith(const std::vector<std::string>& values,
const std::string& start) {
return std::any_of(
Expand Down
3 changes: 2 additions & 1 deletion src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ uint64_t HashUsr(std::string_view s);

// Returns true if |value| starts/ends with |start| or |ending|.
bool StartsWith(std::string_view value, std::string_view start);
bool StartsWithIgnoreCase(std::string_view value, std::string_view start);
bool EndsWith(std::string_view value, std::string_view ending);
bool AnyStartsWith(const std::vector<std::string>& values,
const std::string& start);
Expand Down Expand Up @@ -146,4 +147,4 @@ bool IsWindowsAbsolutePath(const std::string& path);

bool IsDirectory(const std::string& path);

size_t HashArguments(const std::vector<std::string>& args);
size_t HashArguments(const std::vector<std::string>& args);
4 changes: 4 additions & 0 deletions third_party/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
DisableFormat: true
SortIncludes: false
...
1 change: 1 addition & 0 deletions third_party/lib_fts
Submodule lib_fts added at 80f3f8