♻️ 重构符号表的代码
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,242 +1,230 @@
|
||||
#include "./symbol.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include "./symbol.hpp"
|
||||
|
||||
#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";
|
||||
}
|
||||
namespace lsp::provider::workspace {
|
||||
std::string Symbol::GetMethod() const { return "workspace/symbol"; }
|
||||
|
||||
std::string Symbol::GetProviderName() const
|
||||
{
|
||||
return "WorkSpaceSymbol";
|
||||
}
|
||||
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);
|
||||
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");
|
||||
}
|
||||
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()<protocol::WorkspaceSymbolParams>(request.params.value());
|
||||
protocol::WorkspaceSymbolParams params =
|
||||
transform::FromLSPAny.template
|
||||
operator()<protocol::WorkspaceSymbolParams>(request.params.value());
|
||||
|
||||
auto symbols = BuildSymbolResponse(params, context);
|
||||
auto symbols = BuildSymbolResponse(params, context);
|
||||
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.result = transform::ToLSPAny(symbols);
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.result = transform::ToLSPAny(symbols);
|
||||
|
||||
std::optional<std::string> json = transform::Serialize(response);
|
||||
if (!json.has_value())
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Failed to serialize response");
|
||||
return json.value();
|
||||
}
|
||||
|
||||
std::vector<protocol::SymbolInformation> 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<protocol::SymbolInformation> Symbol::SearchSymbols(const std::string& query, ExecutionContext& context)
|
||||
{
|
||||
std::vector<protocol::SymbolInformation> results;
|
||||
|
||||
// 从容器获取服务
|
||||
const auto& document_service = context.GetService<service::Document>();
|
||||
const auto& symbol_service = context.GetService<service::Symbol>();
|
||||
|
||||
// 获取所有打开的文档
|
||||
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<protocol::SymbolInformation>& 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<int>(pos * 10);
|
||||
}
|
||||
|
||||
// 模糊匹配得分最低
|
||||
if (FuzzyMatch(query, symbol_name))
|
||||
{
|
||||
score = std::max(score, 500);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
std::optional<std::string> json = transform::Serialize(response);
|
||||
if (!json.has_value())
|
||||
return BuildErrorResponseMessage(request,
|
||||
protocol::ErrorCodes::InternalError,
|
||||
"Failed to serialize response");
|
||||
return json.value();
|
||||
}
|
||||
|
||||
std::vector<protocol::SymbolInformation> 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<protocol::SymbolInformation> Symbol::SearchSymbols(
|
||||
const std::string& query, ExecutionContext& context) {
|
||||
std::vector<protocol::SymbolInformation> results;
|
||||
|
||||
// 从容器获取服务
|
||||
auto document_service = context.GetService<service::Document>();
|
||||
auto symbol_service = context.GetService<service::Symbol>();
|
||||
|
||||
// 获取所有打开的文档
|
||||
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<protocol::SymbolInformation>& 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<int>(pos * 10);
|
||||
}
|
||||
|
||||
// 模糊匹配得分最低
|
||||
if (FuzzyMatch(query, symbol_name)) {
|
||||
score = std::max(score, 500);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
} // namespace lsp::provider::workspace
|
||||
|
||||
Reference in New Issue
Block a user