#include #include "./initialize.hpp" #include "../../service/symbol.hpp" #include "../../scheduler/async_executor.hpp" #include "../../protocol/transform/facade.hpp" namespace lsp::provider { std::string Initialize::GetMethod() const { return "initialize"; } std::string Initialize::GetProviderName() const { return "Initialize"; } std::string Initialize::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) { spdlog::debug("InitializeProvider: Providing response for method {}", request.method); protocol::InitializeParams params = transform::As(request.params.value()); if (params.workspaceFolders) ProcessWorkspaceFolder(params.workspaceFolders.value(), context); protocol::ResponseMessage response; response.id = request.id; response.result = transform::LSPAny(BuildInitializeResult()); std::optional json = transform::Serialize(response); if (!json.has_value()) { context.TriggerLifecycleEvent(ServerLifecycleEvent::kInitializeFailed); return BuildErrorResponseMessage(request, protocol::ErrorCodes::kInternalError, "Internal error"); } context.TriggerLifecycleEvent(ServerLifecycleEvent::kInitialized); return json.value(); } protocol::InitializeResult Initialize::BuildInitializeResult() { protocol::InitializeResult result; result.serverInfo.name = "TSL Language Server"; result.serverInfo.version = __DATE__; result.capabilities.textDocumentSync = BuildTextDocumentSyncOptions(); result.capabilities.completionProvider = BuildCompletionOptions(); // result.capabilities.semanticTokensProvider = BuildSemanticTokenOptions(); return result; } protocol::TextDocumentSyncOptions Initialize::BuildTextDocumentSyncOptions() { protocol::TextDocumentSyncOptions options; options.openClose = true; options.change = protocol::TextDocumentSyncKind::kIncremental; return options; } protocol::CompletionOptions Initialize::BuildCompletionOptions() { protocol::CompletionOptions options; options.triggerCharacters = { std::vector{ ".", "(" } }; options.resolveProvider = true; options.completionItem = { .labelDetailsSupport = true }; return options; } protocol::SemanticTokensOptions Initialize::BuildSemanticTokenOptions() { protocol::SemanticTokensOptions options; options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Namespace); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Type); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Class); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Enum); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Interface); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Struct); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::TypeParameter); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Parameter); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Variable); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Property); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::EnumMember); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Event); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Function); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Method); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Macro); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Keyword); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Modifier); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Comment); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::String); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Number); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Regexp); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Operator); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Decorator); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Declaration); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Definition); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Readonly); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Static); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Deprecated); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Abstract); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Async); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Modification); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Documentation); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::DefaultLibrary); options.range = true; options.full = protocol::SemanticTokensOptions::Full{ .delta = true }; return options; } void Initialize::ProcessWorkspaceFolder(const std::vector& workspace_folders, ExecutionContext& context) { auto symbol = context.GetService(); auto& scheduler = context.GetScheduler(); for (const auto& workspace_folder : workspace_folders) { std::string workspace_path = UriToPath(workspace_folder.uri); scheduler.Submit("Load workspace symbols", [symbol, workspace_path, folder_name = workspace_folder.name]() -> std::optional { try { symbol->LoadWorkspaceSymbols(workspace_path); return fmt::format("Loaded workspace {} symbols", workspace_path); } catch (const std::exception& e) { spdlog::error("Failed to load workspace {} symbols: {}", folder_name, e.what()); throw; // Request会处理异常 } }, [](const std::string& result) { spdlog::info("Worksapce loading result:", result); }); } spdlog::info("Initiated loading for {} workspace folder(s)", workspace_folders.size()); } std::string Initialize::UriToPath(const protocol::DocumentUri& uri) { std::string path = uri; if (path.find("file://") == 0) path = path.substr(7); #ifdef _WIN32 if (path.length() > 0 && path[0] == '/') path = path.substr(1); #endif return path; } }