Add caseSensitivity to config->{completion,workspaceSymbol}

This commit is contained in:
Fangrui Song 2018-04-14 11:57:23 -07:00
parent e522ce8179
commit 73bd987b1a
12 changed files with 57 additions and 62 deletions

View File

@ -33,7 +33,8 @@ if(NOT CYGWIN)
set_property(TARGET ccls PROPERTY CXX_EXTENSIONS OFF) set_property(TARGET ccls PROPERTY CXX_EXTENSIONS OFF)
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) # CMake sets MSVC for both MSVC and Clang(Windows)
if(MSVC)
# Common MSVC/Clang(Windows) options # Common MSVC/Clang(Windows) options
target_compile_options(ccls PRIVATE target_compile_options(ccls PRIVATE
/nologo /nologo
@ -87,7 +88,7 @@ endif()
### Libraries ### Libraries
# See cmake/FindClang.cmake # See cmake/FindClang.cmake
find_package(Clang ${CLANG_VERSION} REQUIRED) find_package(Clang ${LIBCLANG_VERSION} REQUIRED)
target_link_libraries(ccls PRIVATE Clang::Clang) target_link_libraries(ccls PRIVATE Clang::Clang)
# Enable threading support # Enable threading support
@ -97,7 +98,7 @@ target_link_libraries(ccls PRIVATE Threads::Threads)
if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
target_link_libraries(ccls PRIVATE -lc++experimental) target_link_libraries(ccls PRIVATE -lc++experimental)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) elseif(MSVC)
else() else()
target_link_libraries(ccls PRIVATE -lstdc++fs) target_link_libraries(ccls PRIVATE -lstdc++fs)
endif() endif()

View File

@ -15,9 +15,6 @@
#include <cassert> #include <cassert>
#include <chrono> #include <chrono>
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
// |Foobar| in DISALLOW_COPY(Foobar)
#if CINDEX_VERSION >= 47 #if CINDEX_VERSION >= 47
#define CINDEX_HAVE_PRETTY 1 #define CINDEX_HAVE_PRETTY 1
#endif #endif

View File

@ -89,6 +89,11 @@ struct Config {
} codeLens; } codeLens;
struct Completion { struct Completion {
// 0: case-insensitive
// 1: case-folded, i.e. insensitive if no input character is uppercase.
// 2: case-sensitive
int caseSensitivity = 2;
// Some completion UI, such as Emacs' completion-at-point and company-lsp, // Some completion UI, such as Emacs' completion-at-point and company-lsp,
// display completion item label and detail side by side. // display completion item label and detail side by side.
// This does not look right, when you see things like: // This does not look right, when you see things like:
@ -209,6 +214,7 @@ struct Config {
} index; } index;
struct WorkspaceSymbol { struct WorkspaceSymbol {
int caseSensitivity = 1;
// Maximum workspace search results. // Maximum workspace search results.
int maxNum = 1000; int maxNum = 1000;
// If true, workspace search results will be dynamically rescored/reordered // If true, workspace search results will be dynamically rescored/reordered
@ -227,6 +233,7 @@ struct Config {
MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport); MAKE_REFLECT_STRUCT(Config::ClientCapability, snippetSupport);
MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables); MAKE_REFLECT_STRUCT(Config::CodeLens, localVariables);
MAKE_REFLECT_STRUCT(Config::Completion, MAKE_REFLECT_STRUCT(Config::Completion,
caseSensitivity,
detailedLabel, detailedLabel,
filterAndSort, filterAndSort,
includeBlacklist, includeBlacklist,
@ -248,7 +255,7 @@ MAKE_REFLECT_STRUCT(Config::Index,
onDidChange, onDidChange,
threads, threads,
whitelist); whitelist);
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, maxNum, sort); MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum); MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
MAKE_REFLECT_STRUCT(Config, MAKE_REFLECT_STRUCT(Config,
compilationDatabaseCommand, compilationDatabaseCommand,

View File

@ -81,7 +81,11 @@ IndexFile* FileConsumer::TryConsumeFile(
CXFileUniqueID file_id; CXFileUniqueID file_id;
if (clang_getFileUniqueID(file, &file_id) != 0) { if (clang_getFileUniqueID(file, &file_id) != 0) {
EmitError(file); std::string file_name = FileName(file);
if (!file_name.empty()) {
LOG_S(ERROR) << "Could not get unique file id for " << file_name
<< " when parsing " << parse_file_;
}
return nullptr; return nullptr;
} }
@ -126,12 +130,3 @@ std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() {
} }
return result; return result;
} }
void FileConsumer::EmitError(CXFile file) const {
std::string file_name = ToString(clang_getFileName(file));
// TODO: Investigate this more, why can we get an empty file name?
if (!file_name.empty()) {
LOG_S(ERROR) << "Could not get unique file id for " << file_name
<< " when parsing " << parse_file_;
}
}

View File

@ -68,8 +68,6 @@ struct FileConsumer {
std::vector<std::unique_ptr<IndexFile>> TakeLocalState(); std::vector<std::unique_ptr<IndexFile>> TakeLocalState();
private: private:
void EmitError(CXFile file) const;
std::unordered_map<CXFileUniqueID, std::unique_ptr<IndexFile>> local_; std::unordered_map<CXFileUniqueID, std::unique_ptr<IndexFile>> local_;
FileConsumerSharedState* shared_; FileConsumerSharedState* shared_;
std::string parse_file_; std::string parse_file_;

View File

@ -78,8 +78,11 @@ int FuzzyMatcher::MatchScore(int i, int j, bool last) {
return s; return s;
} }
FuzzyMatcher::FuzzyMatcher(std::string_view pattern) { FuzzyMatcher::FuzzyMatcher(std::string_view pattern, int sensitivity) {
CalculateRoles(pattern, pat_role, &pat_set); CalculateRoles(pattern, pat_role, &pat_set);
if (sensitivity == 1)
sensitivity = pat_set & 1 << Upper ? 2 : 0;
case_sensitivity = sensitivity;
size_t n = 0; size_t n = 0;
for (size_t i = 0; i < pattern.size(); i++) for (size_t i = 0; i < pattern.size(); i++)
if (pattern[i] != ' ') { if (pattern[i] != ' ') {
@ -112,12 +115,13 @@ int FuzzyMatcher::Match(std::string_view text) {
cur[j][1] + MissScore(j, true)); cur[j][1] + MissScore(j, true));
// For the first char of pattern, apply extra restriction to filter bad // For the first char of pattern, apply extra restriction to filter bad
// candidates (e.g. |int| in |PRINT|) // candidates (e.g. |int| in |PRINT|)
if (low_pat[i] == low_text[j] && cur[j + 1][1] = (case_sensitivity ? pat[i] == text[j]
(i || text_role[j] != Tail || pat[i] == text[j])) { : low_pat[i] == low_text[j] &&
cur[j + 1][1] = std::max(pre[j][0] + MatchScore(i, j, false), (i || text_role[j] != Tail ||
pre[j][1] + MatchScore(i, j, true)); pat[i] == text[j]))
} else ? std::max(pre[j][0] + MatchScore(i, j, false),
cur[j + 1][1] = kMinScore * 2; pre[j][1] + MatchScore(i, j, true))
: cur[j + 1][1] = kMinScore * 2;
} }
} }
@ -131,7 +135,7 @@ int FuzzyMatcher::Match(std::string_view text) {
TEST_SUITE("fuzzy_match") { TEST_SUITE("fuzzy_match") {
bool Ranks(std::string_view pat, std::vector<const char*> texts) { bool Ranks(std::string_view pat, std::vector<const char*> texts) {
FuzzyMatcher fuzzy(pat); FuzzyMatcher fuzzy(pat, 0);
std::vector<int> scores; std::vector<int> scores;
for (auto text : texts) for (auto text : texts)
scores.push_back(fuzzy.Match(text)); scores.push_back(fuzzy.Match(text));
@ -150,7 +154,7 @@ TEST_SUITE("fuzzy_match") {
} }
TEST_CASE("test") { TEST_CASE("test") {
FuzzyMatcher fuzzy(""); FuzzyMatcher fuzzy("", 0);
CHECK(fuzzy.Match("") == 0); CHECK(fuzzy.Match("") == 0);
CHECK(fuzzy.Match("aaa") < 0); CHECK(fuzzy.Match("aaa") < 0);

View File

@ -12,10 +12,11 @@ class FuzzyMatcher {
// overflow. // overflow.
constexpr static int kMinScore = INT_MIN / 4; constexpr static int kMinScore = INT_MIN / 4;
FuzzyMatcher(std::string_view pattern); FuzzyMatcher(std::string_view pattern, int case_sensitivity);
int Match(std::string_view text); int Match(std::string_view text);
private: private:
int case_sensitivity;
std::string pat; std::string pat;
std::string_view text; std::string_view text;
int pat_set, text_set; int pat_set, text_set;

View File

@ -188,9 +188,6 @@ struct TypeDef : NameMixin<TypeDef<F>> {
types == o.types && funcs == o.funcs && vars == o.vars && types == o.types && funcs == o.funcs && vars == o.vars &&
kind == o.kind && hover == o.hover && comments == o.comments; kind == o.kind && hover == o.hover && comments == o.comments;
} }
bool operator!=(const TypeDef& o) const {
return !(*this == o);
}
}; };
template <typename TVisitor, typename Family> template <typename TVisitor, typename Family>
void Reflect(TVisitor& visitor, TypeDef<Family>& value) { void Reflect(TVisitor& visitor, TypeDef<Family>& value) {
@ -269,9 +266,6 @@ struct FuncDef : NameMixin<FuncDef<F>> {
kind == o.kind && storage == o.storage && hover == o.hover && kind == o.kind && storage == o.storage && hover == o.hover &&
comments == o.comments; comments == o.comments;
} }
bool operator!=(const FuncDef& o) const {
return !(*this == o);
}
}; };
template <typename TVisitor, typename Family> template <typename TVisitor, typename Family>
@ -359,7 +353,6 @@ struct VarDef : NameMixin<VarDef<F>> {
extent == o.extent && type == o.type && kind == o.kind && extent == o.extent && type == o.type && kind == o.kind &&
storage == o.storage && hover == o.hover && comments == o.comments; storage == o.storage && hover == o.hover && comments == o.comments;
} }
bool operator!=(const VarDef& o) const { return !(*this == o); }
}; };
template <typename TVisitor, typename Family> template <typename TVisitor, typename Family>

View File

@ -49,7 +49,7 @@ std::optional<std::string> ReadJsonRpcContentFrom(
return opt_c && *opt_c == expected; return opt_c && *opt_c == expected;
}; };
if (!expect_char('\r') || !expect_char('\n')) { if (!expect_char('\r') || !expect_char('\n')) {
LOG_S(INFO) << "Unexpected token (expected \r\n sequence)"; LOG_S(INFO) << "Unexpected token (expected \\r\\n sequence)";
return std::nullopt; return std::nullopt;
} }

View File

@ -214,7 +214,7 @@ void FilterAndSortCompletionResponse(
} }
// Fuzzy match and remove awful candidates. // Fuzzy match and remove awful candidates.
FuzzyMatcher fuzzy(complete_text); FuzzyMatcher fuzzy(complete_text, g_config->completion.caseSensitivity);
for (auto& item : items) { for (auto& item : items) {
item.score_ = item.score_ =
CaseFoldingSubsequenceMatch(complete_text, *item.filterText).first CaseFoldingSubsequenceMatch(complete_text, *item.filterText).first

View File

@ -129,7 +129,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
int longest = 0; int longest = 0;
for (int i : result_indices) for (int i : result_indices)
longest = std::max(longest, int(db->GetSymbolName(i, true).size())); longest = std::max(longest, int(db->GetSymbolName(i, true).size()));
FuzzyMatcher fuzzy(query); FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
std::vector<std::pair<int, int>> permutation(result_indices.size()); std::vector<std::pair<int, int>> permutation(result_indices.size());
for (int i = 0; i < int(result_indices.size()); i++) { for (int i = 0; i < int(result_indices.size()); i++) {
permutation[i] = { permutation[i] = {

View File

@ -625,15 +625,15 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
/*onFound:*/ /*onFound:*/
[this, &previous_id_map, &current_id_map](IndexType* previous, [this, &previous_id_map, &current_id_map](IndexType* previous,
IndexType* current) { IndexType* current) {
std::optional<QueryType::Def> previous_remapped_def = std::optional<QueryType::Def> prev_remapped =
ToQuery(previous_id_map, previous->def); ToQuery(previous_id_map, previous->def);
std::optional<QueryType::Def> current_remapped_def = std::optional<QueryType::Def> current_remapped =
ToQuery(current_id_map, current->def); ToQuery(current_id_map, current->def);
if (current_remapped_def && if (current_remapped &&
previous_remapped_def != current_remapped_def && !(prev_remapped == current_remapped) &&
!current_remapped_def->detailed_name.empty()) { !current_remapped->detailed_name.empty()) {
types_def_update.push_back(QueryType::DefUpdate( types_def_update.push_back(QueryType::DefUpdate(
current->usr, std::move(*current_remapped_def))); current->usr, std::move(*current_remapped)));
} }
PROCESS_UPDATE_DIFF(QueryTypeId, types_declarations, declarations, Use); PROCESS_UPDATE_DIFF(QueryTypeId, types_declarations, declarations, Use);
@ -686,15 +686,15 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
/*onFound:*/ /*onFound:*/
[this, &previous_id_map, &current_id_map](IndexFunc* previous, [this, &previous_id_map, &current_id_map](IndexFunc* previous,
IndexFunc* current) { IndexFunc* current) {
std::optional<QueryFunc::Def> previous_remapped_def = std::optional<QueryFunc::Def> prev_remapped =
ToQuery(previous_id_map, previous->def); ToQuery(previous_id_map, previous->def);
std::optional<QueryFunc::Def> current_remapped_def = std::optional<QueryFunc::Def> current_remapped =
ToQuery(current_id_map, current->def); ToQuery(current_id_map, current->def);
if (current_remapped_def && if (current_remapped &&
previous_remapped_def != current_remapped_def && !(prev_remapped == current_remapped) &&
!current_remapped_def->detailed_name.empty()) { !current_remapped->detailed_name.empty()) {
funcs_def_update.push_back(QueryFunc::DefUpdate( funcs_def_update.push_back(QueryFunc::DefUpdate(
current->usr, std::move(*current_remapped_def))); current->usr, std::move(*current_remapped)));
} }
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_declarations, declarations, Use); PROCESS_UPDATE_DIFF(QueryFuncId, funcs_declarations, declarations, Use);
@ -736,15 +736,14 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
/*onFound:*/ /*onFound:*/
[this, &previous_id_map, &current_id_map](IndexVar* previous, [this, &previous_id_map, &current_id_map](IndexVar* previous,
IndexVar* current) { IndexVar* current) {
std::optional<QueryVar::Def> previous_remapped_def = std::optional<QueryVar::Def> prev_remapped =
ToQuery(previous_id_map, previous->def); ToQuery(previous_id_map, previous->def);
std::optional<QueryVar::Def> current_remapped_def = std::optional<QueryVar::Def> current_remapped =
ToQuery(current_id_map, current->def); ToQuery(current_id_map, current->def);
if (current_remapped_def && if (current_remapped && !(prev_remapped == current_remapped) &&
previous_remapped_def != current_remapped_def && !current_remapped->detailed_name.empty())
!current_remapped_def->detailed_name.empty()) vars_def_update.push_back(
vars_def_update.push_back(QueryVar::DefUpdate( QueryVar::DefUpdate(current->usr, std::move(*current_remapped)));
current->usr, std::move(*current_remapped_def)));
PROCESS_UPDATE_DIFF(QueryVarId, vars_declarations, declarations, Use); PROCESS_UPDATE_DIFF(QueryVarId, vars_declarations, declarations, Use);
PROCESS_UPDATE_DIFF(QueryVarId, vars_uses, uses, Use); PROCESS_UPDATE_DIFF(QueryVarId, vars_uses, uses, Use);