Browse Source

Add caseSensitivity to config->{completion,workspaceSymbol}

pull/517/head
Fangrui Song 7 years ago
parent
commit
73bd987b1a
  1. 15
      CMakeLists.txt
  2. 3
      src/clang_indexer.cc
  3. 9
      src/config.h
  4. 15
      src/file_consumer.cc
  5. 2
      src/file_consumer.h
  6. 22
      src/fuzzy_match.cc
  7. 3
      src/fuzzy_match.h
  8. 7
      src/indexer.h
  9. 2
      src/lsp.cc
  10. 2
      src/messages/text_document_completion.cc
  11. 2
      src/messages/workspace_symbol.cc
  12. 37
      src/query.cc

15
CMakeLists.txt

@ -6,7 +6,7 @@ include(DefaultCMakeBuildType)
# Required libclang version
set(LIBCLANG_VERSION 6.0.0 CACHE STRING "libclang version")
set(LIBCLANG_DOWNLOAD_LOCATION ${CMAKE_BINARY_DIR}
set(LIBCLANG_DOWNLOAD_LOCATION ${CMAKE_BINARY_DIR}
CACHE STRING "Downloaded libclang location")
option(SYSTEM_LIBCLANG "Use system installation of libclang instead of \
downloading libclang" OFF)
@ -33,7 +33,8 @@ if(NOT CYGWIN)
set_property(TARGET ccls PROPERTY CXX_EXTENSIONS OFF)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL Windows)
# CMake sets MSVC for both MSVC and Clang(Windows)
if(MSVC)
# Common MSVC/Clang(Windows) options
target_compile_options(ccls PRIVATE
/nologo
@ -87,7 +88,7 @@ endif()
### Libraries
# See cmake/FindClang.cmake
find_package(Clang ${CLANG_VERSION} REQUIRED)
find_package(Clang ${LIBCLANG_VERSION} REQUIRED)
target_link_libraries(ccls PRIVATE Clang::Clang)
# Enable threading support
@ -97,7 +98,7 @@ target_link_libraries(ccls PRIVATE Threads::Threads)
if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
target_link_libraries(ccls PRIVATE -lc++experimental)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows)
elseif(MSVC)
else()
target_link_libraries(ccls PRIVATE -lstdc++fs)
endif()
@ -161,8 +162,8 @@ endif()
if(NOT SYSTEM_LIBCLANG AND ${CMAKE_SYSTEM_NAME} STREQUAL Windows)
add_custom_command(TARGET ccls
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${DOWNLOADED_CLANG_DIR}/bin/libclang.dll
COMMAND ${CMAKE_COMMAND} -E copy
${DOWNLOADED_CLANG_DIR}/bin/libclang.dll
$<TARGET_FILE_DIR:ccls>
COMMENT "Copying libclang.dll to build directory ...")
endif()
@ -190,7 +191,7 @@ else()
support clang-format 6.0.0")
endif()
add_custom_target(format
add_custom_target(format
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold
${Clang_FORMAT_ERROR})
endif()

3
src/clang_indexer.cc

@ -15,9 +15,6 @@
#include <cassert>
#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
#define CINDEX_HAVE_PRETTY 1
#endif

9
src/config.h

@ -89,6 +89,11 @@ struct Config {
} codeLens;
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,
// display completion item label and detail side by side.
// This does not look right, when you see things like:
@ -209,6 +214,7 @@ struct Config {
} index;
struct WorkspaceSymbol {
int caseSensitivity = 1;
// Maximum workspace search results.
int maxNum = 1000;
// 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::CodeLens, localVariables);
MAKE_REFLECT_STRUCT(Config::Completion,
caseSensitivity,
detailedLabel,
filterAndSort,
includeBlacklist,
@ -248,7 +255,7 @@ MAKE_REFLECT_STRUCT(Config::Index,
onDidChange,
threads,
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,
compilationDatabaseCommand,

15
src/file_consumer.cc

@ -81,7 +81,11 @@ IndexFile* FileConsumer::TryConsumeFile(
CXFileUniqueID file_id;
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;
}
@ -126,12 +130,3 @@ std::vector<std::unique_ptr<IndexFile>> FileConsumer::TakeLocalState() {
}
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_;
}
}

2
src/file_consumer.h

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

22
src/fuzzy_match.cc

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

3
src/fuzzy_match.h

@ -12,10 +12,11 @@ class FuzzyMatcher {
// overflow.
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);
private:
int case_sensitivity;
std::string pat;
std::string_view text;
int pat_set, text_set;

7
src/indexer.h

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

2
src/lsp.cc

@ -49,7 +49,7 @@ std::optional<std::string> ReadJsonRpcContentFrom(
return opt_c && *opt_c == expected;
};
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;
}

2
src/messages/text_document_completion.cc

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

2
src/messages/workspace_symbol.cc

@ -129,7 +129,7 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
int longest = 0;
for (int i : result_indices)
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());
for (int i = 0; i < int(result_indices.size()); i++) {
permutation[i] = {

37
src/query.cc

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

Loading…
Cancel
Save