diff --git a/src/message_handler.hh b/src/message_handler.hh index ed2ab136..e5e07844 100644 --- a/src/message_handler.hh +++ b/src/message_handler.hh @@ -119,10 +119,9 @@ struct CompletionItem { std::string label; CompletionItemKind kind = CompletionItemKind::Text; std::string detail; - std::optional documentation; + std::string documentation; std::string sortText; - std::optional filterText; - std::string insertText; + std::string filterText; InsertTextFormat insertTextFormat = InsertTextFormat::PlainText; TextEdit textEdit; std::vector additionalTextEdits; diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index 5748b8bd..bb656298 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -34,9 +34,23 @@ using namespace llvm; MAKE_REFLECT_TYPE_PROXY(InsertTextFormat); MAKE_REFLECT_TYPE_PROXY(CompletionItemKind); -MAKE_REFLECT_STRUCT(CompletionItem, label, kind, detail, documentation, - sortText, filterText, insertText, insertTextFormat, - textEdit, additionalTextEdits); + +void Reflect(Writer &vis, CompletionItem &v) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(label); + REFLECT_MEMBER(kind); + REFLECT_MEMBER(detail); + if (v.documentation.size()) + REFLECT_MEMBER(documentation); + REFLECT_MEMBER(sortText); + if (v.filterText.size()) + REFLECT_MEMBER(filterText); + REFLECT_MEMBER(insertTextFormat); + REFLECT_MEMBER(textEdit); + if (v.additionalTextEdits.size()) + REFLECT_MEMBER(additionalTextEdits); + REFLECT_MEMBER_END(); +} namespace { struct CompletionList { @@ -67,7 +81,6 @@ void DecorateIncludePaths(const std::smatch &match, item.textEdit.newText = prefix + quote0 + item.textEdit.newText + quote1 + suffix; item.label = prefix + quote0 + item.label + quote1 + suffix; - item.filterText = std::nullopt; } } @@ -124,8 +137,8 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text, std::string sort(4, ' '); for (auto &item : items) { item.textEdit.range = lsRange{begin_pos, end_pos}; - if (has_open_paren && item.filterText) - item.textEdit.newText = *item.filterText; + if (has_open_paren) + item.textEdit.newText = item.filterText; // https://github.com/Microsoft/language-server-protocol/issues/543 // Order of textEdit and additionalTextEdits is unspecified. auto &edits = item.additionalTextEdits; @@ -133,48 +146,44 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text, Position start = edits[0].range.start, end = edits[0].range.end; item.textEdit.range.start = start; item.textEdit.newText = edits[0].newText + item.textEdit.newText; - if (start.line == begin_pos.line && item.filterText) { + if (start.line == begin_pos.line) { item.filterText = buffer_line.substr(start.character, end.character - start.character) + - *item.filterText; + item.filterText; } edits.erase(edits.begin()); } + if (item.filterText == item.label) + item.filterText.clear(); for (auto i = sort.size(); i && ++sort[i - 1] == 'A';) sort[--i] = ' '; item.sortText = sort; - // Compatibility - item.insertText = item.textEdit.newText; } }; - // No complete text; don't run any filtering logic except to trim the items. - if (!g_config->completion.filterAndSort || complete_text.empty()) { + if (!g_config->completion.filterAndSort) { finalize(); return; } - // Make sure all items have |filterText| set, code that follow needs it. - for (auto &item : items) { - if (!item.filterText) - item.filterText = item.label; + if (complete_text.size()) { + // Fuzzy match and remove awful candidates. + bool sensitive = g_config->completion.caseSensitivity; + FuzzyMatcher fuzzy(complete_text, sensitive); + for (CompletionItem &item : items) { + const std::string &filter = + item.filterText.size() ? item.filterText : item.label; + item.score_ = ReverseSubseqMatch(complete_text, filter, sensitive) >= 0 + ? fuzzy.Match(filter) + : FuzzyMatcher::kMinScore; + } + items.erase(std::remove_if(items.begin(), items.end(), + [](const CompletionItem &item) { + return item.score_ <= FuzzyMatcher::kMinScore; + }), + items.end()); } - - // Fuzzy match and remove awful candidates. - bool sensitive = g_config->completion.caseSensitivity; - FuzzyMatcher fuzzy(complete_text, sensitive); - for (auto &item : items) { - item.score_ = - ReverseSubseqMatch(complete_text, *item.filterText, sensitive) >= 0 - ? fuzzy.Match(*item.filterText) - : FuzzyMatcher::kMinScore; - } - items.erase(std::remove_if(items.begin(), items.end(), - [](const CompletionItem &item) { - return item.score_ <= FuzzyMatcher::kMinScore; - }), - items.end()); std::sort(items.begin(), items.end(), [](const CompletionItem &lhs, const CompletionItem &rhs) { int t = int(lhs.additionalTextEdits.size() - @@ -185,9 +194,13 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text, return lhs.score_ > rhs.score_; if (lhs.priority_ != rhs.priority_) return lhs.priority_ < rhs.priority_; - if (lhs.filterText->size() != rhs.filterText->size()) - return lhs.filterText->size() < rhs.filterText->size(); - return *lhs.filterText < *rhs.filterText; + t = lhs.textEdit.newText.compare(rhs.textEdit.newText); + if (t) + return t < 0; + t = lhs.label.compare(rhs.label); + if (t) + return t < 0; + return lhs.filterText < rhs.filterText; }); // Trim result. @@ -293,8 +306,7 @@ void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS, case CodeCompletionString::CK_TypedText: text = Chunk.Text; for (auto i = first; i < out.size(); i++) - if (Kind == CodeCompletionString::CK_TypedText && !out[i].filterText) - out[i].filterText = text; + out[i].filterText = text; break; case CodeCompletionString::CK_Placeholder: text = Chunk.Text; @@ -414,7 +426,7 @@ public: ls_items[j].priority_ = CCS->getPriority(); if (!g_config->completion.detailedLabel) { ls_items[j].detail = ls_items[j].label; - ls_items[j].label = ls_items[j].filterText.value_or(""); + ls_items[j].label = ls_items[j].filterText; } } #if LLVM_VERSION_MAJOR >= 7