♻️ 重构

This commit is contained in:
csh
2025-12-05 21:03:18 +08:00
parent 4c2e242920
commit 549f1d1b0a
161 changed files with 26415 additions and 28009 deletions
@@ -14,10 +14,9 @@ namespace lsp::provider::text_document
return "TextDocumentCodeAction";
}
std::string CodeAction::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
std::string CodeAction::ProvideResponse(const protocol::RequestMessage& request, [[maybe_unused]] ExecutionContext& context)
{
static_cast<void>(context);
spdlog::debug("TextDocumentCodeActionProvider: Providing response for method {}", request.method);
spdlog::debug("TextDocumentCodeActionProvider: Providing response for method {}", request.method);
// TODO: Implement the actual request handling logic
// 1. Parse request parameters
File diff suppressed because it is too large Load Diff
@@ -1,86 +1,14 @@
#pragma once
#include <string>
#include <vector>
#include "../base/interface.hpp"
#include "../../service/detail/symbol/types.hpp"
#include "../../language/symbol/types.hpp"
#include "../../service/symbol.hpp"
namespace lsp::provider::text_document
{
struct CompletionContext
{
protocol::DocumentUri uri;
protocol::Position position;
std::string prefix;
std::string line_content;
bool is_unit_context = false; // unit( 上下文
bool is_class_context = false; // class( 上下文
bool is_new_context = false; // new 上下文
bool is_class_method_context = false; // class(xxx)
std::string class_name;
};
// 临时设计
struct CompletionInfo
{
protocol::string type;
protocol::string class_name;
};
enum class CompletionSource
{
kEditing, // 当前编辑文档
kWorkspace, // 工作区符号
kSystem, // 系统库符号
kKeyword // 关键字
};
struct SourcedCompletionItem
{
protocol::CompletionItem item;
CompletionSource source;
};
namespace context_analyzer
{
CompletionContext Analyze(const protocol::CompletionParams& params, const std::optional<std::string>& document_content);
bool IsUnitContext(const std::string& line);
bool IsClassContext(const std::string& line);
bool IsNewContext(const std::string& line);
bool IsClassMethodContext(const std::string& line, std::string& class_name, std::string& method_prefix);
std::string ExtractPrefix(size_t cursor_pos, size_t line_start, const std::string& content);
std::string ExtractUnitPrefix(const std::string& line);
std::string ExtractClassPrefix(const std::string& line);
std::string ExtractNewPrefix(const std::string& line);
}
class Completion : public IRequestProvider
{
public:
std::string GetMethod() const override;
std::string GetProviderName() const override;
std::string ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& execution_context) override;
private:
protocol::CompletionList BuildCompletionList(const protocol::CompletionParams& params, ExecutionContext& execution_context);
// 符号收集
std::vector<SourcedCompletionItem> CollectKeywords(const std::string& prefix);
std::vector<SourcedCompletionItem> CollectClassMethods(const CompletionContext& comp_context, const service::Symbol& symbol_service);
std::vector<SourcedCompletionItem> CollectUnitNames(const CompletionContext& comp_context, const service::Symbol& symbol_service);
std::vector<SourcedCompletionItem> CollectClassNames(const CompletionContext& comp_context, const service::Symbol& symbol_service, bool is_new_context = false);
std::vector<SourcedCompletionItem> CollectEditingFunctions(const CompletionContext& comp_context, const service::Symbol& symbol_service);
std::vector<SourcedCompletionItem> CollectWorkspaceFunctions(const CompletionContext& comp_context, const service::Symbol& symbol_service);
std::vector<SourcedCompletionItem> CollectSystemFunctions(const CompletionContext& comp_context, const service::Symbol& symbol_service);
// 过滤和排序
std::vector<protocol::CompletionItem> FilterAndSort(const std::vector<SourcedCompletionItem>& items, const std::string& prefix);
static int GetMatchScore(const std::string& label, const std::string& prefix);
// 格式化辅助
static protocol::CompletionItemKind ToCompletionItemKind(language::symbol::SymbolKind kind);
// static std::string FormatSignature(const service::SymbolSignature& sig);
};
}
@@ -1,7 +1,12 @@
#include <spdlog/spdlog.h>
#include <cstring>
#include "./definition.hpp"
#include "../../protocol/transform/facade.hpp"
#include "../../service/document.hpp"
#include "../../manager/manager_hub.hpp"
#include "../../utils/text_coordinates.hpp"
#include "../../language/symbol/table.hpp"
#include "../../language/semantic/semantic_model.hpp"
#include "../../utils/string.hpp"
namespace lsp::provider::text_document
{
@@ -25,7 +30,8 @@ namespace lsp::provider::text_document
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InvalidParams, "Missing params");
}
protocol::DefinitionParams params = transform::As<protocol::DefinitionParams>(request.params.value());
protocol::DefinitionParams params =
transform::FromLSPAny.template operator()<protocol::DefinitionParams>(request.params.value());
auto location = BuildDefinitionResponse(params, context);
@@ -34,7 +40,7 @@ namespace lsp::provider::text_document
if (location.has_value())
{
response.result = transform::LSPAny(*location);
response.result = transform::ToLSPAny(*location);
}
else
{
@@ -50,6 +56,141 @@ namespace lsp::provider::text_document
std::optional<protocol::Location> Definition::BuildDefinitionResponse(const protocol::DefinitionParams& params, ExecutionContext& context)
{
spdlog::trace("{}: Processing definition request for URI='{}', Position=({}, {})", GetProviderName(), params.textDocument.uri, params.position.line, params.position.character);
std::string identifier = GetIdentifierAtPosition(params.textDocument.uri, params.position, context);
if (identifier.empty())
{
spdlog::info("{}: No identifier at position", GetProviderName());
return std::nullopt;
}
auto& hub = context.GetManagerHub();
auto content_opt = hub.documents().GetContent(params.textDocument.uri);
if (!content_opt)
{
spdlog::warn("{}: Document content not found for {}", GetProviderName(), params.textDocument.uri);
return std::nullopt;
}
language::ast::Location loc{};
loc.start_line = loc.end_line = params.position.line;
loc.start_column = loc.end_column = params.position.character;
loc.start_offset = loc.end_offset = utils::text_coordinates::ToOffset(params.position, *content_opt);
if (auto local = ResolveInCurrentDocument(params.textDocument.uri, identifier, loc, context))
{
return local;
}
return ResolveInIndex(identifier, context);
}
std::optional<protocol::Location> Definition::ResolveInCurrentDocument(const protocol::DocumentUri& uri,
const std::string& identifier,
const language::ast::Location& location,
ExecutionContext& context)
{
auto& hub = context.GetManagerHub();
auto* table = hub.symbols().GetSymbolTable(uri);
auto* semantic = hub.symbols().GetSemanticModel(uri);
if (table && semantic)
{
auto resolved = semantic->name_resolver().ResolveNameAtLocation(identifier, location);
if (resolved.IsResolved())
{
if (const auto* symbol = table->definition(resolved.symbol_id))
{
return ToLocation(uri, symbol->selection_range());
}
}
}
if (table)
{
auto matches = table->FindSymbolsByName(identifier);
for (auto id : matches)
{
if (const auto* symbol = table->definition(id))
{
return ToLocation(uri, symbol->selection_range());
}
}
}
return std::nullopt;
}
std::optional<protocol::Location> Definition::ResolveInIndex(const std::string& identifier, ExecutionContext& context)
{
auto& symbols = context.GetManagerHub().symbols();
auto lower = utils::ToLower(identifier);
auto search_kind = [&](protocol::SymbolKind kind) -> std::optional<protocol::Location> {
auto indexed = symbols.QueryIndexedSymbols(kind, std::nullopt);
for (const auto& item : indexed)
{
if (!utils::IEquals(item.name, lower))
continue;
if (const auto* table = symbols.GetSymbolTable(item.uri))
{
if (const auto* sym = table->definition(item.id))
{
return ToLocation(item.uri, sym->selection_range());
}
}
}
return std::nullopt;
};
if (auto result = search_kind(protocol::SymbolKind::Function))
return result;
if (auto result = search_kind(protocol::SymbolKind::Class))
return result;
if (auto result = search_kind(protocol::SymbolKind::Module))
return result;
return std::nullopt;
}
protocol::Location Definition::ToLocation(const protocol::DocumentUri& uri, const language::ast::Location& loc)
{
protocol::Location location;
location.uri = uri;
location.range.start.line = loc.start_line;
location.range.start.character = loc.start_column;
location.range.end.line = loc.end_line;
location.range.end.character = loc.end_column;
return location;
}
std::string Definition::GetIdentifierAtPosition(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context)
{
auto& hub = context.GetManagerHub();
auto content = hub.documents().GetContent(uri);
auto tree = hub.parser().GetTree(uri);
if (!content.has_value() || !tree)
return "";
size_t byte_offset = utils::text_coordinates::ToOffset(position, *content);
TSNode root = ts_tree_root_node(tree);
TSNode node = ts_node_descendant_for_byte_range(root, static_cast<uint32_t>(byte_offset), static_cast<uint32_t>(byte_offset));
while (!ts_node_is_null(node))
{
const char* node_type = ts_node_type(node);
if (strcmp(node_type, kIdentifier) == 0)
{
uint32_t start = ts_node_start_byte(node);
uint32_t end = ts_node_end_byte(node);
if (start < content->size() && end <= content->size())
return content->substr(start, end - start);
}
node = ts_node_parent(node);
}
return "";
}
}
@@ -1,5 +1,6 @@
#pragma once
#include "../base/interface.hpp"
#include "../../language/ast/types.hpp"
extern "C" {
#include <tree_sitter/api.h>
@@ -18,24 +19,18 @@ namespace lsp::provider::text_document
private:
std::optional<protocol::Location> BuildDefinitionResponse(const protocol::DefinitionParams& params, ExecutionContext& context);
std::optional<protocol::Location> FindLocalDefinition(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context);
std::optional<protocol::Location> ResolveInCurrentDocument(const protocol::DocumentUri& uri,
const std::string& identifier,
const language::ast::Location& location,
ExecutionContext& context);
std::optional<protocol::Location> ResolveInIndex(const std::string& identifier, ExecutionContext& context);
std::string GetIdentifierAtPosition(const protocol::DocumentUri& uri, const protocol::Position& position, ExecutionContext& context);
TSNode FindDefinitionNode(TSNode root, const std::string& identifier, const std::string& content);
static protocol::Location ToLocation(const protocol::DocumentUri& uri, const language::ast::Location& loc);
};
namespace
{
constexpr const char* kUnit = "unit";
constexpr const char* kInterfaceSection = "interface_section";
constexpr const char* kImplementationSection = "implementation_section";
constexpr const char* kFunctionDefinition = "function_definition_statement";
constexpr const char* kFunctionDeclaration = "function_declaration_statement";
constexpr const char* kClassDefinition = "class_definition_statement";
constexpr const char* kVarStatement = "var_statement";
constexpr const char* kConstStatement = "const_statement";
constexpr const char* kIdentifier = "identifier";
constexpr const char* kMethodWithImplementation = "method_with_implementation";
}
}
@@ -14,10 +14,9 @@ namespace lsp::provider::text_document
return "TextDocumentDiagnostic";
}
std::string Diagnostic::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
std::string Diagnostic::ProvideResponse(const protocol::RequestMessage& request, [[maybe_unused]] ExecutionContext& context)
{
static_cast<void>(context);
spdlog::debug("TextDocumentDiagnosticProvider: Providing response for method {}", request.method);
spdlog::debug("TextDocumentDiagnosticProvider: Providing response for method {}", request.method);
// TODO: Implement the actual request handling logic
// 1. Parse request parameters
@@ -1,7 +1,6 @@
#include <spdlog/spdlog.h>
#include "./did_change.hpp"
#include "../../protocol/transform/facade.hpp"
#include "../../service/document.hpp"
namespace lsp::provider::text_document
{
@@ -22,8 +21,8 @@ namespace lsp::provider::text_document
auto params = transform::FromLSPAny.template operator()<protocol::DidChangeTextDocumentParams>(notification.params.value());
auto document_service = context.GetService<service::Document>();
document_service->UpdateDocument(params);
auto& documents = context.GetManagerHub().documents();
documents.UpdateDocument(params);
spdlog::info("Document updated: {}", params.textDocument.uri);
}
@@ -1,7 +1,6 @@
#include <spdlog/spdlog.h>
#include "./did_close.hpp"
#include "../../protocol/transform/facade.hpp"
#include "../../service/document.hpp"
namespace lsp::provider::text_document
{
@@ -22,8 +21,8 @@ namespace lsp::provider::text_document
protocol::DidCloseTextDocumentParams params = transform::FromLSPAny.template operator()<protocol::DidCloseTextDocumentParams>(notification.params.value());
auto document_service = context.GetService<service::Document>();
document_service->CloseDocument(params);
auto& documents = context.GetManagerHub().documents();
documents.CloseDocument(params);
spdlog::info("Document closed: {}", params.textDocument.uri);
}
@@ -1,7 +1,6 @@
#include <spdlog/spdlog.h>
#include "./did_open.hpp"
#include "../../protocol/transform/facade.hpp"
#include "../../service/document.hpp"
namespace lsp::provider::text_document
{
@@ -21,8 +20,8 @@ namespace lsp::provider::text_document
auto params = transform::FromLSPAny.template operator()<protocol::DidOpenTextDocumentParams>(notification.params.value());
auto document_service = context.GetService<service::Document>();
document_service->OpenDocument(params);
auto& documents = context.GetManagerHub().documents();
documents.OpenDocument(params);
/*
if (auto* symbolService = context.TryGetService<SymbolService>()) {
@@ -14,10 +14,9 @@ namespace lsp::provider::text_document
return "TextDocumentDocumentColor";
}
std::string DocumentColor::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
std::string DocumentColor::ProvideResponse(const protocol::RequestMessage& request, [[maybe_unused]] ExecutionContext& context)
{
static_cast<void>(context);
spdlog::debug("TextDocumentDocumentColorProvider: Providing response for method {}", request.method);
spdlog::debug("TextDocumentDocumentColorProvider: Providing response for method {}", request.method);
// TODO: Implement the actual request handling logic
// 1. Parse request parameters
@@ -14,10 +14,9 @@ namespace lsp::provider::text_document
return "TextDocumentDocumentHighlight";
}
std::string DocumentHighlight::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
std::string DocumentHighlight::ProvideResponse(const protocol::RequestMessage& request, [[maybe_unused]] ExecutionContext& context)
{
static_cast<void>(context);
spdlog::debug("TextDocumentDocumentHighlightProvider: Providing response for method {}", request.method);
spdlog::debug("TextDocumentDocumentHighlightProvider: Providing response for method {}", request.method);
// TODO: Implement the actual request handling logic
// 1. Parse request parameters
@@ -4,684 +4,6 @@
namespace lsp::provider::text_document
{
bool IsFieldName(TSNode parent, TSNode node, const std::string& field_name)
{
uint32_t child_count = ts_node_child_count(parent);
for (uint32_t i = 0; i < child_count; ++i)
{
TSNode sibling = ts_node_child(parent, i);
if (ts_node_eq(sibling, node))
{
const char* actual_field = ts_node_field_name_for_child(parent, i);
return actual_field && std::string(actual_field) == field_name;
}
}
return false;
}
SemanticToken::SemanticToken(protocol::uinteger l, protocol::uinteger c, protocol::uinteger len, SemanticTokenType t, protocol::uinteger mod) :
line(l), character(c), length(len), type(t), modifiers(mod)
{
}
SemanticTokensCache::SemanticTokensCache(const std::string& id, std::vector<uint32_t> tokens, const std::string& version) :
result_id(id), data(std::move(tokens)), document_version(version)
{
spdlog::debug("SemanticTokensCache: Created cache entry with {} tokens, result_id={}, version={}", data.size() / 5, id, version);
}
SemanticTokensCore::SemanticTokensCore()
{
spdlog::info("SemanticTokensCore: Initializing semantic tokens core");
InitNodeTypeMap();
spdlog::info("SemanticTokensCore: Initialization completed with {} node type mappings", node_type_map_.size());
}
SemanticTokensCore& SemanticTokensCore::GetInstance()
{
static SemanticTokensCore instance;
return instance;
}
void SemanticTokensCore::InitNodeTypeMap()
{
spdlog::trace("SemanticTokensCore: Initializing node type mappings");
// ========== 基本字面量 ==========
node_type_map_["number"] = SemanticTokenType::kNumber;
node_type_map_["string"] = SemanticTokenType::kString;
node_type_map_["escape_sequence"] = SemanticTokenType::kString;
node_type_map_["boolean"] = SemanticTokenType::kEnum;
node_type_map_["true"] = SemanticTokenType::kEnum;
node_type_map_["false"] = SemanticTokenType::kEnum;
node_type_map_["nil"] = SemanticTokenType::kEnum;
node_type_map_["infinity"] = SemanticTokenType::kNumber;
node_type_map_["plus_inf"] = SemanticTokenType::kNumber;
node_type_map_["minus_inf"] = SemanticTokenType::kNumber;
node_type_map_["ellipsis"] = SemanticTokenType::kOperator;
// ========== 注释 ==========
node_type_map_["line_comment"] = SemanticTokenType::kComment;
node_type_map_["block_comment"] = SemanticTokenType::kComment;
node_type_map_["nested_comment"] = SemanticTokenType::kComment;
node_type_map_["html_comment"] = SemanticTokenType::kComment;
// ========== 声明关键字 ==========
node_type_map_["function"] = SemanticTokenType::kKeyword;
node_type_map_["var"] = SemanticTokenType::kKeyword;
node_type_map_["static"] = SemanticTokenType::kKeyword;
node_type_map_["global"] = SemanticTokenType::kKeyword;
node_type_map_["const"] = SemanticTokenType::kKeyword;
node_type_map_["class"] = SemanticTokenType::kKeyword;
node_type_map_["type"] = SemanticTokenType::kKeyword;
node_type_map_["property"] = SemanticTokenType::kKeyword;
node_type_map_["unit"] = SemanticTokenType::kKeyword;
node_type_map_["interface"] = SemanticTokenType::kKeyword;
node_type_map_["implementation"] = SemanticTokenType::kKeyword;
node_type_map_["initialization"] = SemanticTokenType::kKeyword;
node_type_map_["finalization"] = SemanticTokenType::kKeyword;
node_type_map_["uses"] = SemanticTokenType::kKeyword;
node_type_map_["out"] = SemanticTokenType::kKeyword;
// ========== 控制流关键字 ==========
node_type_map_["if"] = SemanticTokenType::kKeyword;
node_type_map_["else"] = SemanticTokenType::kKeyword;
node_type_map_["then"] = SemanticTokenType::kKeyword;
node_type_map_["for"] = SemanticTokenType::kKeyword;
node_type_map_["while"] = SemanticTokenType::kKeyword;
node_type_map_["repeat"] = SemanticTokenType::kKeyword;
node_type_map_["until"] = SemanticTokenType::kKeyword;
node_type_map_["case"] = SemanticTokenType::kKeyword;
node_type_map_["of"] = SemanticTokenType::kKeyword;
node_type_map_["try"] = SemanticTokenType::kKeyword;
node_type_map_["except"] = SemanticTokenType::kKeyword;
node_type_map_["end"] = SemanticTokenType::kKeyword;
node_type_map_["begin"] = SemanticTokenType::kKeyword;
node_type_map_["do"] = SemanticTokenType::kKeyword;
node_type_map_["to"] = SemanticTokenType::kKeyword;
node_type_map_["downto"] = SemanticTokenType::kKeyword;
node_type_map_["in"] = SemanticTokenType::kKeyword;
node_type_map_["is"] = SemanticTokenType::kKeyword;
node_type_map_["like"] = SemanticTokenType::kKeyword;
node_type_map_["as"] = SemanticTokenType::kKeyword;
// ========== 语句关键字 ==========
node_type_map_["return"] = SemanticTokenType::kKeyword;
node_type_map_["break"] = SemanticTokenType::kKeyword;
node_type_map_["continue"] = SemanticTokenType::kKeyword;
node_type_map_["inherited"] = SemanticTokenType::kKeyword;
node_type_map_["echo"] = SemanticTokenType::kKeyword;
node_type_map_["raise"] = SemanticTokenType::kKeyword;
node_type_map_["new"] = SemanticTokenType::kKeyword;
node_type_map_["array"] = SemanticTokenType::kKeyword;
// ========== 访问修饰符 ==========
node_type_map_["public"] = SemanticTokenType::kModifier;
node_type_map_["private"] = SemanticTokenType::kModifier;
node_type_map_["protected"] = SemanticTokenType::kModifier;
node_type_map_["virtual"] = SemanticTokenType::kModifier;
node_type_map_["override"] = SemanticTokenType::kModifier;
node_type_map_["overload"] = SemanticTokenType::kModifier;
node_type_map_["operator"] = SemanticTokenType::kModifier;
node_type_map_["weakref"] = SemanticTokenType::kModifier;
node_type_map_["autoref"] = SemanticTokenType::kModifier;
// ========== 属性访问器 ==========
node_type_map_["read"] = SemanticTokenType::kKeyword;
node_type_map_["write"] = SemanticTokenType::kKeyword;
node_type_map_["index"] = SemanticTokenType::kKeyword;
// ========== SQL关键字 ==========
node_type_map_["select"] = SemanticTokenType::kKeyword;
node_type_map_["sselect"] = SemanticTokenType::kKeyword;
node_type_map_["vselect"] = SemanticTokenType::kKeyword;
node_type_map_["mselect"] = SemanticTokenType::kKeyword;
node_type_map_["update"] = SemanticTokenType::kKeyword;
node_type_map_["insert"] = SemanticTokenType::kKeyword;
node_type_map_["delete"] = SemanticTokenType::kKeyword;
node_type_map_["from"] = SemanticTokenType::kKeyword;
node_type_map_["where"] = SemanticTokenType::kKeyword;
node_type_map_["join"] = SemanticTokenType::kKeyword;
node_type_map_["left"] = SemanticTokenType::kKeyword;
node_type_map_["right"] = SemanticTokenType::kKeyword;
node_type_map_["full"] = SemanticTokenType::kKeyword;
node_type_map_["cross"] = SemanticTokenType::kKeyword;
node_type_map_["on"] = SemanticTokenType::kKeyword;
node_type_map_["with"] = SemanticTokenType::kKeyword;
node_type_map_["group"] = SemanticTokenType::kKeyword;
node_type_map_["by"] = SemanticTokenType::kKeyword;
node_type_map_["order"] = SemanticTokenType::kKeyword;
node_type_map_["having"] = SemanticTokenType::kKeyword;
node_type_map_["distinct"] = SemanticTokenType::kKeyword;
node_type_map_["drange"] = SemanticTokenType::kKeyword;
node_type_map_["into"] = SemanticTokenType::kKeyword;
node_type_map_["values"] = SemanticTokenType::kKeyword;
node_type_map_["set"] = SemanticTokenType::kKeyword;
node_type_map_["insertfields"] = SemanticTokenType::kKeyword;
node_type_map_["asc"] = SemanticTokenType::kKeyword;
node_type_map_["desc"] = SemanticTokenType::kKeyword;
// ========== 逻辑操作符关键字 ==========
node_type_map_["and"] = SemanticTokenType::kOperator;
node_type_map_["or"] = SemanticTokenType::kOperator;
node_type_map_["not"] = SemanticTokenType::kOperator;
node_type_map_["mod"] = SemanticTokenType::kOperator;
node_type_map_["div"] = SemanticTokenType::kOperator;
node_type_map_["shl"] = SemanticTokenType::kOperator;
node_type_map_["shr"] = SemanticTokenType::kOperator;
node_type_map_["rol"] = SemanticTokenType::kOperator;
node_type_map_["ror"] = SemanticTokenType::kOperator;
// ========== 集合操作符 ==========
node_type_map_["union"] = SemanticTokenType::kOperator;
node_type_map_["union2"] = SemanticTokenType::kOperator;
node_type_map_["intersect"] = SemanticTokenType::kOperator;
node_type_map_["outersect"] = SemanticTokenType::kOperator;
node_type_map_["minus"] = SemanticTokenType::kOperator;
// ========== TSLX模板标签 ==========
node_type_map_["tslx"] = SemanticTokenType::kMacro;
node_type_map_["tsl"] = SemanticTokenType::kMacro;
node_type_map_["html_tag_name"] = SemanticTokenType::kNamespace;
// ========== 特殊字段 ==========
node_type_map_["sql_field"] = SemanticTokenType::kProperty;
node_type_map_["_sql_field_simple"] = SemanticTokenType::kProperty;
node_type_map_["_sql_field_with_table"] = SemanticTokenType::kProperty;
// ========== 类型规范 ==========
node_type_map_["type_specification"] = SemanticTokenType::kType;
// 默认标识符为变量
node_type_map_["identifier"] = SemanticTokenType::kVariable;
}
std::string SemanticTokensCore::GenerateResultId(const std::string& uri, const std::string& version)
{
return uri + ":" + version + ":" + std::to_string(std::time(nullptr));
}
std::vector<SemanticToken> SemanticTokensCore::CollectTokensInRange(TSNode root, const std::string& source, const protocol::Range* range)
{
std::vector<SemanticToken> tokens;
TraverseNode(root, source, tokens, range);
// Sort by position
std::sort(tokens.begin(), tokens.end(), [](const SemanticToken& a, const SemanticToken& b) {
if (a.line != b.line)
return a.line < b.line;
return a.character < b.character;
});
return tokens;
}
void SemanticTokensCore::TraverseNode(TSNode node, const std::string& source_code, std::vector<SemanticToken>& tokens, const protocol::Range* range)
{
if (ts_node_is_null(node))
{
spdlog::trace("SemanticTokensCore: Skipping null node");
return;
}
TSPoint start = ts_node_start_point(node);
TSPoint end = ts_node_end_point(node);
if (range && !IsNodeInRange(start, end, *range))
return;
ProcessNode(node, tokens);
uint32_t child_count = ts_node_child_count(node);
for (uint32_t i = 0; i < child_count; ++i)
{
TSNode child = ts_node_child(node, i);
TraverseNode(child, source_code, tokens, range);
}
spdlog::trace("TraverseNode end...");
}
void SemanticTokensCore::ProcessNode(TSNode node, std::vector<SemanticToken>& tokens)
{
std::string type_str(ts_node_type(node));
spdlog::trace("ProcessNode type_str = {}", type_str);
auto it = node_type_map_.find(type_str);
if (it != node_type_map_.end())
{
TSPoint start = ts_node_start_point(node);
uint32_t start_byte = ts_node_start_byte(node);
uint32_t end_byte = ts_node_end_byte(node);
uint32_t length = end_byte - start_byte;
SemanticTokenType token_type = it->second;
if (token_type == SemanticTokenType::kVariable)
token_type = DetermineIdentifierType(node);
uint32_t modifiers = DetermineModifiers(node);
tokens.emplace_back(start.row, start.column, length, token_type, modifiers);
spdlog::debug("Added semantic token: type = {}, line = {}, char = {}, length = {}", type_str, start.row, start.column, length);
}
}
SemanticTokenType SemanticTokensCore::DetermineIdentifierType(TSNode node)
{
TSNode parent = ts_node_parent(node);
if (ts_node_is_null(parent))
return SemanticTokenType::kVariable;
const char* parent_type = ts_node_type(parent);
std::string parent_str(parent_type);
// 函数声明和定义
if ((parent_str == "function_declaration_statement" ||
parent_str == "function_definition_statement" ||
parent_str == "anonymous_function_statement" ||
parent_str == "anonymous_function_expression") &&
IsFieldName(parent, node, "name"))
{
return SemanticTokenType::kFunction;
}
// 方法声明和定义
if ((parent_str == "method_declaration" ||
parent_str == "method_declaration_only" ||
parent_str == "method_with_modifier" ||
parent_str == "method_with_implementation" ||
parent_str == "modifier_method" ||
parent_str == "normal_method") &&
(IsFieldName(parent, node, "name") || IsFieldName(parent, node, "method_name")))
{
return SemanticTokenType::kMethod;
}
// 操作符重载
if (parent_str == "_qualified_method_name" && IsFieldName(parent, node, "method_name"))
{
return SemanticTokenType::kMethod;
}
// 函数调用
if (parent_str == "call" && IsFieldName(parent, node, "function"))
{
return SemanticTokenType::kFunction;
}
// ========== 类相关 ==========
// 类定义
if (parent_str == "class_definition_statement" && IsFieldName(parent, node, "name"))
{
return SemanticTokenType::kClass;
}
// 类名引用(在方法定义中)
if ((parent_str == "_qualified_method_name" ||
parent_str == "_operator_method" ||
parent_str == "_operator_method_with_modifier") &&
IsFieldName(parent, node, "class_name"))
{
return SemanticTokenType::kClass;
}
// 父类引用
if (parent_str == "_parent_list" && IsFieldName(parent, node, "parent"))
{
return SemanticTokenType::kClass;
}
// ========== 参数相关 ==========
if (parent_str == "parameter" && IsFieldName(parent, node, "name"))
{
return SemanticTokenType::kParameter;
}
// for循环变量
if ((parent_str == "for_in_statement" || parent_str == "for_to_statement") &&
(IsFieldName(parent, node, "key") || IsFieldName(parent, node, "value") ||
IsFieldName(parent, node, "counter")))
{
return SemanticTokenType::kVariable;
}
// ========== 属性相关 ==========
// 属性声明
if (parent_str == "property_declaration" && IsFieldName(parent, node, "name"))
{
return SemanticTokenType::kProperty;
}
// 属性访问
if (parent_str == "attribute" && IsFieldName(parent, node, "attribute"))
{
return SemanticTokenType::kProperty;
}
// 属性访问器中的标识符
if ((parent_str == "read_only_accessor" ||
parent_str == "write_only_accessor" ||
parent_str == "read_write_accessor" ||
parent_str == "write_read_accessor"))
{
return SemanticTokenType::kMethod;
}
// ========== 变量声明 ==========
if ((parent_str == "var_declaration" ||
parent_str == "static_declaration" ||
parent_str == "global_declaration" ||
parent_str == "nostatic_declaration") &&
IsFieldName(parent, node, "name"))
{
// 检查是否是成员变量
TSNode grandparent = ts_node_parent(parent);
if (!ts_node_is_null(grandparent))
{
std::string grandparent_str(ts_node_type(grandparent));
if (grandparent_str == "member_variable" || grandparent_str == "variable_declaration")
{
TSNode great_grandparent = ts_node_parent(grandparent);
if (!ts_node_is_null(great_grandparent))
{
std::string ggp_str(ts_node_type(great_grandparent));
if (ggp_str == "class_member" || ggp_str == "class_body")
{
return SemanticTokenType::kProperty;
}
}
}
}
}
return SemanticTokenType::kVariable;
}
uint32_t SemanticTokensCore::DetermineModifiers(TSNode node)
{
uint32_t modifiers = 0;
TSNode parent = ts_node_parent(node);
if (!ts_node_is_null(parent))
{
std::string parent_str(ts_node_type(parent));
std::string node_str(ts_node_type(node));
// 声明修饰符
if (parent_str.find("declaration") != std::string::npos ||
parent_str.find("definition") != std::string::npos)
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kDeclaration);
}
// 常量修饰符
if (parent_str == "const_statement")
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kReadonly);
}
// 静态修饰符
if (parent_str == "static_declaration" || parent_str == "static_statement")
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kStatic);
}
// 检查方法修饰符
TSNode grandparent = ts_node_parent(parent);
if (!ts_node_is_null(grandparent))
{
std::string grandparent_str(ts_node_type(grandparent));
// 虚方法
if (grandparent_str == "method_with_modifier")
{
// 需要检查modifier字段
uint32_t child_count = ts_node_child_count(grandparent);
for (uint32_t i = 0; i < child_count; ++i)
{
TSNode child = ts_node_child(grandparent, i);
const char* field = ts_node_field_name_for_child(grandparent, i);
if (field && std::string(field) == "modifier")
{
std::string modifier_str(ts_node_type(child));
if (modifier_str == "virtual")
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kAbstract);
}
}
}
}
// 类成员
if (grandparent_str == "class_member" || grandparent_str == "class_body")
{
// 可以添加默认库修饰符等
if (parent_str == "property_declaration")
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kReadonly);
}
}
}
// 异步修饰符(如果有异步函数)
if (node_str == "async" || parent_str.find("async") != std::string::npos)
{
modifiers |= static_cast<uint32_t>(SemanticTokenModifier::kAsync);
}
}
return modifiers;
}
bool SemanticTokensCore::IsNodeInRange(TSPoint start, TSPoint end, const protocol::Range& range)
{
if (end.row < range.start.line || start.row > range.end.line)
return false;
if (start.row == range.start.line && end.column < range.start.character)
return false;
if (end.row == range.end.line && start.column > range.end.character)
return false;
return true;
}
std::vector<protocol::uinteger> SemanticTokensCore::EncodeTokens(const std::vector<SemanticToken>& tokens)
{
std::vector<uint32_t> encoded;
encoded.reserve(tokens.size() * 5);
protocol::uinteger prev_line = 0;
protocol::uinteger prev_char = 0;
for (const auto& token : tokens)
{
protocol::uinteger delta_line = token.line - prev_line;
protocol::uinteger delta_char = (delta_line == 0) ? token.character - prev_char : token.character;
encoded.push_back(delta_line);
encoded.push_back(delta_char);
encoded.push_back(token.length);
encoded.push_back(static_cast<protocol::uinteger>(token.type));
encoded.push_back(token.modifiers);
prev_line = token.line;
prev_char = token.character;
}
return encoded;
}
std::vector<protocol::SemanticTokensEdit> SemanticTokensCore::ComputeDelta(const std::vector<protocol::uinteger>& old_data, const std::vector<protocol::uinteger>& new_data)
{
std::vector<protocol::SemanticTokensEdit> edits;
// Simple diff algorithm - can be optimized with more sophisticated algorithms
size_t old_size = old_data.size();
size_t new_size = new_data.size();
if (old_size == 0 && new_size > 0)
{
// All new
protocol::SemanticTokensEdit edit;
edit.start = 0;
edit.deleteCount = 0;
edit.data = new_data;
edits.push_back(edit);
}
else if (old_size > 0 && new_size == 0)
{
// All deleted
protocol::SemanticTokensEdit edit;
edit.start = 0;
edit.deleteCount = old_size;
edits.push_back(edit);
}
else if (old_data != new_data)
{
// Replace all (simple approach - can be optimized)
protocol::SemanticTokensEdit edit;
edit.start = 0;
edit.deleteCount = old_size;
edit.data = new_data;
edits.push_back(edit);
}
return edits;
}
// Range request
std::string SemanticTokensCore::HandleRange(const protocol::RequestMessage& request, ExecutionContext& context)
{
auto params = transform::FromLSPAny.template operator()<protocol::SemanticTokensRangeParams>(request.params.value());
service::Document& doc_service = context.GetService<service::Document>();
TSTree* tree = doc_service.GetSyntaxTree(params.textDocument.uri);
auto content = doc_service.GetContent(params.textDocument.uri);
if (!tree || !content)
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Document not available");
auto tokens = CollectTokensInRange(ts_tree_root_node(tree), content.value(), &params.range);
auto encoded = EncodeTokens(tokens);
protocol::ResponseMessage response;
response.id = request.id;
protocol::SemanticTokens result;
result.data = encoded;
response.result = transform::LSPAny(result);
spdlog::debug("SemanticTokens Range: Generated {} tokens for range in document: {}", encoded.size() / 5, params.textDocument.uri);
std::optional<std::string> json = transform::Serialize(response);
if (!json.has_value())
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Internal error");
return json.value();
}
// Full request
std::string SemanticTokensCore::HandleFull(const protocol::RequestMessage& request, ExecutionContext& context)
{
auto params = transform::As<protocol::SemanticTokensParams>(request.params.value());
service::Document& doc_service = context.GetService<service::Document>();
TSTree* tree = doc_service.GetSyntaxTree(params.textDocument.uri);
auto content = doc_service.GetContent(params.textDocument.uri);
if (!tree || !content)
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Document not available");
auto tokens = CollectTokensInRange(ts_tree_root_node(tree), content.value());
auto encoded = EncodeTokens(tokens);
// Generate result ID and cache
std::string version = "1"; // Should get actual document version
std::string result_id = GenerateResultId(params.textDocument.uri, version);
{
std::lock_guard<std::mutex> lock(cache_mutex_);
cache_.emplace(params.textDocument.uri, SemanticTokensCache(result_id, encoded, version));
}
protocol::ResponseMessage response;
response.id = request.id;
protocol::SemanticTokens result;
result.resultId = result_id;
result.data = encoded;
response.result = transform::LSPAny(result);
spdlog::debug("SemanticTokens Full: Generated {} tokens for document: {}", encoded.size() / 5, params.textDocument.uri);
std::optional<std::string> json = transform::Serialize(response);
if (!json.has_value())
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Internal error");
return json.value();
}
// Delta request
std::string SemanticTokensCore::HandleDelta(const protocol::RequestMessage& request, ExecutionContext& context)
{
auto params = transform::As<protocol::SemanticTokensDeltaParams>(request.params.value());
service::Document& doc_service = context.GetService<service::Document>();
// 检查缓存
bool need_full_update = false;
std::vector<protocol::uinteger> old_data;
{
std::lock_guard<std::mutex> lock(cache_mutex_);
auto cache_it = cache_.find(params.textDocument.uri);
if (cache_it == cache_.end() || cache_it->second.result_id != params.previousResultId)
{
need_full_update = true; // 标记需要完整更新
}
else
{
old_data = cache_it->second.data; // 复制旧数据
}
} // 锁在这里释放
// 如果需要完整更新,在锁外调用 HandleFull
if (need_full_update)
{
protocol::RequestMessage full_request = request;
full_request.method = "textDocument/semanticTokens/full";
protocol::SemanticTokensParams full_params;
full_params.textDocument = params.textDocument;
full_request.params = transform::LSPObject(full_params);
return HandleFull(full_request, context);
}
TSTree* tree = doc_service.GetSyntaxTree(params.textDocument.uri);
auto content = doc_service.GetContent(params.textDocument.uri);
if (!tree || !content)
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Document not available");
// Get new tokens
auto tokens = CollectTokensInRange(ts_tree_root_node(tree), content.value());
auto new_encoded = EncodeTokens(tokens);
// Compute delta
auto edits = ComputeDelta(old_data, new_encoded);
// Update cache
std::string version = "2"; // Should get actual document version
std::string new_result_id = GenerateResultId(params.textDocument.uri, version);
{
std::lock_guard<std::mutex> lock(cache_mutex_);
cache_.emplace(params.textDocument.uri, SemanticTokensCache(new_result_id, new_encoded, version));
}
protocol::ResponseMessage response;
response.id = request.id;
protocol::SemanticTokensDelta result;
result.resultId = new_result_id;
result.edits = edits;
response.result = transform::LSPAny(result);
spdlog::debug("SemanticTokens Delta: Generated {} edits for document: {}", edits.size(), params.textDocument.uri);
std::optional<std::string> json = transform::Serialize(response);
if (!json.has_value())
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Internal error");
return json.value();
};
std::unordered_map<std::string, SemanticTokensCache> SemanticTokensCore::cache_;
std::mutex SemanticTokensCore::cache_mutex_;
std::string SemanticTokensRange::GetMethod() const
{
return "textDocument/semanticTokens/range";
@@ -695,7 +17,6 @@ namespace lsp::provider::text_document
std::string SemanticTokensRange::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
{
spdlog::debug("TextDocumentSemanticTokensRangeProvider: Providing response for method {}", request.method);
return SemanticTokensCore::GetInstance().HandleRange(request, context);
}
std::string SemanticTokensFull::GetMethod() const
@@ -711,7 +32,6 @@ namespace lsp::provider::text_document
std::string SemanticTokensFull::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
{
spdlog::debug("SemanticTokensFullProvider: Providing response for method {}", request.method);
return SemanticTokensCore::GetInstance().HandleFull(request, context);
}
std::string SemanticTokensFullDelta::GetMethod() const
@@ -727,6 +47,5 @@ namespace lsp::provider::text_document
std::string SemanticTokensFullDelta::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
{
spdlog::debug("SemanticTokensFullDeltaProvider: Providing response for method {}", request.method);
return SemanticTokensCore::GetInstance().HandleDelta(request, context);
}
}
@@ -7,102 +7,6 @@
namespace lsp::provider::text_document
{
enum class SemanticTokenType: protocol::uinteger
{
kNamespace = 0,
kType = 1,
kClass = 2,
kEnum = 3,
kInterface = 4,
kStruct = 5,
kTypeParameter = 6,
kParameter = 7,
kVariable = 8,
kProperty = 9,
kEnumMember = 10,
kEvent = 11,
kFunction = 12,
kMethod = 13,
kMacro = 14,
kKeyword = 15,
kModifier = 16,
kComment = 17,
kString = 18,
kNumber = 19,
kRegexp = 20,
kOperator = 21,
kDecorator = 22
};
enum class SemanticTokenModifier: protocol::uinteger
{
kDeclaration = 1 << 0,
kDefinition = 1 << 1,
kReadonly = 1 << 2,
kStatic = 1 << 3,
kDeprecated = 1 << 4,
kAbstract = 1 << 5,
kAsync = 1 << 6,
kModification = 1 << 7,
kDocumentation = 1 << 8,
kDefault_library = 1 << 9
};
class SemanticToken
{
public:
SemanticToken(protocol::uinteger l, protocol::uinteger c, protocol::uinteger len, SemanticTokenType t, protocol::uinteger mod);
protocol::uinteger line;
protocol::uinteger character;
protocol::uinteger length;
SemanticTokenType type;
protocol::uinteger modifiers;
};
class SemanticTokensCache
{
public:
SemanticTokensCache(const std::string& id, std::vector<uint32_t> tokens, const std::string& version);
std::string result_id;
std::vector<uint32_t> data;
std::string document_version;
};
class SemanticTokensCore
{
public:
SemanticTokensCore(const SemanticTokensCore&) = delete;
SemanticTokensCore& operator=(const SemanticTokensCore&) = delete;
static SemanticTokensCore& GetInstance();
std::string HandleRange(const protocol::RequestMessage& request, ExecutionContext& context);
std::string HandleFull(const protocol::RequestMessage& request, ExecutionContext& context);
std::string HandleDelta(const protocol::RequestMessage& request, ExecutionContext& context);
private:
SemanticTokensCore();
std::vector<SemanticToken> CollectTokensInRange(TSNode root, const std::string& source, const protocol::Range* range = nullptr);
void TraverseNode(TSNode node, const std::string& source_code, std::vector<SemanticToken>& tokens, const protocol::Range* range);
void ProcessNode(TSNode node, std::vector<SemanticToken>& tokens);
SemanticTokenType DetermineIdentifierType(TSNode node);
uint32_t DetermineModifiers(TSNode node);
std::vector<protocol::uinteger> EncodeTokens(const std::vector<SemanticToken>& tokens);
std::vector<protocol::SemanticTokensEdit> ComputeDelta(const std::vector<protocol::uinteger>& old_data, const std::vector<protocol::uinteger>& new_data);
void InitNodeTypeMap();
std::string GenerateResultId(const std::string& uri, const std::string& version);
bool IsNodeInRange(TSPoint start, TSPoint end, const protocol::Range& range);
static std::unordered_map<std::string, SemanticTokensCache> cache_;
static std::mutex cache_mutex_;
std::unordered_map<std::string, SemanticTokenType> node_type_map_;
};
class SemanticTokensRange : public IRequestProvider
{
public: