diff --git a/src/clang_complete.cc b/src/clang_complete.cc index d30f1ac2..c5ce5066 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -46,6 +46,18 @@ unsigned GetCompletionPriority(const CXCompletionString& str, return priority; } +bool CompareLsCompletionItem(const lsCompletionItem &item1, + const lsCompletionItem &item2) +{ + if (item1.pos_ != item2.pos_) + return item1.pos_ < item2.pos_; + if (item1.priority_ != item2.priority_) + return item1.priority_ < item2.priority_; + if (item1.label.length() != item2.label.length()) + return item1.label.length() < item2.label.length(); + return item1.label < item2.label; +} + template char* tofixedbase64(T input, char* out) { const char* digits = @@ -464,15 +476,22 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) { ls_completion_item.documentation = ToString( clang_getCompletionBriefComment(result.CompletionString)); - char buf[16]; - ls_completion_item.sortText = - tofixedbase64(GetCompletionPriority(result.CompletionString, - result.CursorKind, - ls_completion_item.label), - buf); + ls_completion_item.pos_ = + ls_completion_item.label.find(request->existing_text); + + ls_completion_item.priority_ = + GetCompletionPriority(result.CompletionString, result.CursorKind, + ls_completion_item.label); ls_result.push_back(ls_completion_item); } + + // order all items and set |sortText| + std::sort(ls_result.begin(), ls_result.end(), CompareLsCompletionItem); + char buf[16]; + for (size_t i = 0; i < ls_result.size(); ++i) + ls_result[i].sortText = tofixedbase64(i, buf); + timer.ResetAndPrint("[complete] Building " + std::to_string(ls_result.size()) + " completion results"); @@ -569,6 +588,7 @@ ClangCompleteManager::~ClangCompleteManager() {} void ClangCompleteManager::CodeComplete( const lsTextDocumentPositionParams& completion_location, + const std::string &existing_text, const OnComplete& on_complete) { completion_request_.WithLock( [&](std::unique_ptr& request_storage) { @@ -579,6 +599,7 @@ void ClangCompleteManager::CodeComplete( // Make the request send out code completion information. request_storage->document = completion_location.textDocument; request_storage->position = completion_location.position; + request_storage->existing_text = existing_text; request_storage->on_complete = on_complete; }); } diff --git a/src/clang_complete.h b/src/clang_complete.h index fda498d6..2b3cbb95 100644 --- a/src/clang_complete.h +++ b/src/clang_complete.h @@ -57,6 +57,7 @@ struct ClangCompleteManager { struct CompletionRequest { lsTextDocumentIdentifier document; optional position; + std::string existing_text; OnComplete on_complete; // May be null/empty. bool emit_diagnostics = false; }; @@ -71,6 +72,7 @@ struct ClangCompleteManager { // Start a code completion at the given location. |on_complete| will run when // completion results are available. |on_complete| may run on any thread. void CodeComplete(const lsTextDocumentPositionParams& completion_location, + const std::string &existing_text, const OnComplete& on_complete); // Request a diagnostics update. void DiagnosticsUpdate(const lsTextDocumentIdentifier& document); diff --git a/src/language_server_api.h b/src/language_server_api.h index 8169f6ef..cd139ede 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -356,6 +356,10 @@ struct lsCompletionItem { // A human-readable string that represents a doc-comment. std::string documentation; + // Internal information to order candidates. + std::string::size_type pos_; + unsigned priority_; + // A string that shoud be used when comparing this item // with other items. When `falsy` the label is used. std::string sortText; diff --git a/src/messages/text_document_completion.cc b/src/messages/text_document_completion.cc index 33081501..2e583de1 100644 --- a/src/messages/text_document_completion.cc +++ b/src/messages/text_document_completion.cc @@ -69,15 +69,16 @@ void FilterCompletionResponse(Out_TextDocumentComplete* complete_response, // find the exact text const bool found = !complete_text.empty() && - std::find_if(items.begin(), items.end(), - [&](const lsCompletionItem& item) { - return item.label == complete_text; - }) != items.end(); + std::any_of(items.begin(), items.end(), + [&](const lsCompletionItem& item) { + return item.pos_ == 0 && + item.label.length() == complete_text.length(); + }); // If found, remove all candidates that do not start with it. if (found) { items.erase(std::remove_if(items.begin(), items.end(), [&](const lsCompletionItem& item) { - return item.label.find(complete_text) != 0; + return item.pos_ != 0; }), items.end()); } @@ -242,7 +243,7 @@ struct TextDocumentCompletionHandler : MessageHandler { callback(global_code_complete_cache->cached_results_, true /*is_cached_result*/); }); - clang_complete->CodeComplete(request->params, freshen_global); + clang_complete->CodeComplete(request->params, existing_completion, freshen_global); } else if (non_global_code_complete_cache->IsCacheValid( request->params)) { non_global_code_complete_cache->WithLock([&]() { @@ -250,7 +251,7 @@ struct TextDocumentCompletionHandler : MessageHandler { true /*is_cached_result*/); }); } else { - clang_complete->CodeComplete(request->params, callback); + clang_complete->CodeComplete(request->params, existing_completion, callback); } } } diff --git a/src/messages/text_document_signature_help.cc b/src/messages/text_document_signature_help.cc index 54d14605..32dd01ee 100644 --- a/src/messages/text_document_signature_help.cc +++ b/src/messages/text_document_signature_help.cc @@ -160,9 +160,9 @@ struct TextDocumentSignatureHelpHandler : MessageHandler { callback(signature_cache->cached_results_, true /*is_cached_result*/); }); } else { - clang_complete->CodeComplete(params, std::move(callback)); + clang_complete->CodeComplete(params, search, std::move(callback)); } } }; REGISTER_MESSAGE_HANDLER(TextDocumentSignatureHelpHandler); -} // namespace \ No newline at end of file +} // namespace