diff --git a/src/messages/text_document_definition.cc b/src/messages/text_document_definition.cc index d7fc869a..e6e4caf7 100644 --- a/src/messages/text_document_definition.cc +++ b/src/messages/text_document_definition.cc @@ -128,10 +128,15 @@ struct Handler_TextDocumentDefinition lsPosition position = request->params.position; const std::string& buffer = working_file->buffer_content; std::string_view query = LexIdentifierAroundPos(position, buffer); - bool has_scope = query.find(':') != std::string::npos; + std::string_view short_query = query; + { + auto pos = query.rfind(':'); + if (pos != std::string::npos) + short_query = query.substr(pos + 1); + } // For symbols whose short/detailed names contain |query| as a - // substring, we use the tuple to find the best match. std::tuple best_score{INT_MAX, 0, true, 0}; int best_i = -1; @@ -139,21 +144,28 @@ struct Handler_TextDocumentDefinition if (db->symbols[i].kind == SymbolKind::Invalid) continue; - std::string_view name = has_scope ? db->GetSymbolDetailedName(i) - : db->GetSymbolShortName(i); - auto pos = name.find(query); + std::string_view name = short_query.size() < query.size() + ? db->GetSymbolDetailedName(i) + : db->GetSymbolShortName(i); + auto pos = name.rfind(short_query); if (pos == std::string::npos) continue; - Maybe use = GetDefinitionSpell(db, db->symbols[i]); - if (!use) - continue; - - std::tuple score{ - int(name.size() - query.size()), int(pos), use->file != file_id, - std::abs(use->range.start.line - position.line)}; - if (score < best_score) { - best_score = score; - best_i = i; + if (Maybe use = GetDefinitionSpell(db, db->symbols[i])) { + std::tuple score{ + int(name.size() - short_query.size()), -pos, + use->file != file_id, + std::abs(use->range.start.line - position.line)}; + // Update the score with qualified name if the qualified name + // occurs in |name|. + pos = name.rfind(query); + if (pos != std::string::npos) { + std::get<0>(score) = int(name.size() - query.size()); + std::get<1>(score) = -pos; + } + if (score < best_score) { + best_score = score; + best_i = i; + } } } if (best_i != -1) { diff --git a/src/utils.cc b/src/utils.cc index 5d3cda96..38080abf 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -77,13 +77,13 @@ uint64_t HashUsr(const char* s, size_t n) { } // See http://stackoverflow.com/a/2072890 -bool EndsWith(const std::string& value, const std::string& ending) { +bool EndsWith(std::string_view value, std::string_view ending) { if (ending.size() > value.size()) return false; return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } -bool StartsWith(const std::string& value, const std::string& start) { +bool StartsWith(std::string_view value, std::string_view start) { if (start.size() > value.size()) return false; return std::equal(start.begin(), start.end(), value.begin()); diff --git a/src/utils.h b/src/utils.h index a602c760..da54e338 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -22,8 +23,8 @@ uint64_t HashUsr(const char* s); uint64_t HashUsr(const char* s, size_t n); // Returns true if |value| starts/ends with |start| or |ending|. -bool StartsWith(const std::string& value, const std::string& start); -bool EndsWith(const std::string& value, const std::string& ending); +bool StartsWith(std::string_view value, std::string_view start); +bool EndsWith(std::string_view value, std::string_view ending); bool AnyStartsWith(const std::vector& values, const std::string& start); bool StartsWithAny(const std::string& value,