#include "./symbol.hpp" #include #include #include #include "../../protocol/transform/facade.hpp" #include "../../service/document.hpp" #include "../../service/symbol.hpp" namespace lsp::provider::workspace { std::string Symbol::GetMethod() const { return "workspace/symbol"; } std::string Symbol::GetProviderName() const { return "WorkSpaceSymbol"; } std::string Symbol::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) { spdlog::debug("WorkspaceSymbolProvider: Providing response for method {}", request.method); if (!request.params.has_value()) { spdlog::warn("{}: Missing params in request", GetProviderName()); return BuildErrorResponseMessage( request, protocol::ErrorCodes::InvalidParams, "Missing params"); } protocol::WorkspaceSymbolParams params = transform::FromLSPAny.template operator()(request.params.value()); auto symbols = BuildSymbolResponse(params, context); protocol::ResponseMessage response; response.id = request.id; response.result = transform::ToLSPAny(symbols); std::optional json = transform::Serialize(response); if (!json.has_value()) return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Failed to serialize response"); return json.value(); } std::vector Symbol::BuildSymbolResponse( const protocol::WorkspaceSymbolParams& params, ExecutionContext& context) { spdlog::trace("{}: Searching for symbols matching '{}'", GetProviderName(), params.query); auto symbols = SearchSymbols(params.query, context); // 按匹配分数排序 std::sort(symbols.begin(), symbols.end(), [¶ms](const protocol::SymbolInformation& a, const protocol::SymbolInformation& b) { // 可以实现更复杂的排序逻辑 return a.name < b.name; }); // 限制返回数量(避免返回太多结果) const size_t max_results = 100; if (symbols.size() > max_results) { symbols.resize(max_results); spdlog::debug("{}: Limited results to {} symbols", GetProviderName(), max_results); } spdlog::info("{}: Found {} symbols matching '{}'", GetProviderName(), symbols.size(), params.query); return symbols; } std::vector Symbol::SearchSymbols( const std::string& query, ExecutionContext& context) { std::vector results; // 从容器获取服务 auto document_service = context.GetService(); auto symbol_service = context.GetService(); // 获取所有打开的文档 auto document_uris = document_service->GetAllDocumentUris(); for (const auto& uri : document_uris) { // 获取文档符号 auto doc_symbols = symbol_service->GetDocumentSymbols(uri); // 递归转换并过滤符号 for (const auto& symbol : doc_symbols) { ConvertToSymbolInformation(symbol, uri, query, results); } } return results; } void Symbol::ConvertToSymbolInformation( const protocol::DocumentSymbol& doc_symbol, const protocol::DocumentUri& uri, const std::string& query, std::vector& results, const std::string& container_name) { // 检查是否匹配查询 if (MatchesQuery(doc_symbol.name, query)) { protocol::SymbolInformation info; info.name = doc_symbol.name; info.kind = doc_symbol.kind; info.location.uri = uri; info.location.range = doc_symbol.range; // 设置容器名称 if (!container_name.empty()) { info.containerName = container_name; } results.push_back(info); } // 递归处理子符号 std::string new_container = container_name.empty() ? doc_symbol.name : container_name + "." + doc_symbol.name; for (const auto& child : doc_symbol.children.value()) { ConvertToSymbolInformation(child, uri, query, results, new_container); } } bool Symbol::MatchesQuery(const std::string& symbol_name, const std::string& query) { // 空查询匹配所有 if (query.empty()) return true; // 转换为小写进行不区分大小写的匹配 std::string lower_symbol = symbol_name; std::string lower_query = query; std::transform(lower_symbol.begin(), lower_symbol.end(), lower_symbol.begin(), ::tolower); std::transform(lower_query.begin(), lower_query.end(), lower_query.begin(), ::tolower); // 1. 精确匹配 if (lower_symbol == lower_query) return true; // 2. 前缀匹配 if (lower_symbol.find(lower_query) == 0) return true; // 3. 包含匹配 if (lower_symbol.find(lower_query) != std::string::npos) return true; // 4. 模糊匹配(驼峰匹配) if (FuzzyMatch(query, symbol_name)) return true; return false; } bool Symbol::FuzzyMatch(const std::string& pattern, const std::string& text) { // 实现驼峰匹配 // 例如 "gS" 匹配 "getString" size_t pattern_idx = 0; size_t text_idx = 0; while (pattern_idx < pattern.length() && text_idx < text.length()) { char p = pattern[pattern_idx]; // 查找下一个匹配字符 bool found = false; while (text_idx < text.length()) { char t = text[text_idx]; // 不区分大小写匹配 if (std::tolower(p) == std::tolower(t)) { found = true; text_idx++; break; } // 如果模式字符是大写,只在大写字母位置匹配 if (std::isupper(p) && !std::isupper(t)) { text_idx++; continue; } text_idx++; } if (!found) return false; pattern_idx++; } return pattern_idx == pattern.length(); } int Symbol::CalculateScore(const std::string& symbol_name, const std::string& query) { int score = 0; // 精确匹配得分最高 if (symbol_name == query) return 1000; // 前缀匹配得分次高 if (symbol_name.find(query) == 0) return 900; // 不区分大小写的前缀匹配 std::string lower_symbol = symbol_name; std::string lower_query = query; std::transform(lower_symbol.begin(), lower_symbol.end(), lower_symbol.begin(), ::tolower); std::transform(lower_query.begin(), lower_query.end(), lower_query.begin(), ::tolower); if (lower_symbol.find(lower_query) == 0) return 800; // 包含匹配 size_t pos = lower_symbol.find(lower_query); if (pos != std::string::npos) { // 越靠前得分越高 score = 700 - static_cast(pos * 10); } // 模糊匹配得分最低 if (FuzzyMatch(query, symbol_name)) { score = std::max(score, 500); } return score; } } // namespace lsp::provider::workspace