module; export module lsp.provider.initialize.initialize; import spdlog; import std; import lsp.protocol; import lsp.codec.facade; import lsp.provider.base.interface; import lsp.scheduler.async_executor; namespace transform = lsp::codec; export namespace lsp::provider { class Initialize : public AutoRegisterProvider { public: static constexpr std::string_view kMethod = "initialize"; static constexpr std::string_view kProviderName = "Initialize"; Initialize() = default; std::string ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) override; private: protocol::InitializeResult BuildInitializeResult(); protocol::TextDocumentSyncOptions BuildTextDocumentSyncOptions(); protocol::CompletionOptions BuildCompletionOptions(); protocol::SignatureHelpOptions BuildSignatureHelpOptions(); protocol::SemanticTokensOptions BuildSemanticTokenOptions(); protocol::CodeActionOptions BuildCodeActionOptions(); protocol::DocumentOnTypeFormattingOptions BuildOnTypeFormattingOptions(); protocol::ExecuteCommandOptions BuildExecuteCommandOptions(); void ProcessWorkspaceFolder(const std::vector& workspace_folders, ExecutionContext& context); }; } namespace lsp::provider { std::string Initialize::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) { spdlog::debug("Initialize request {}", request.method); protocol::InitializeParams params = transform::FromLSPAny.template operator()(request.params.value()); auto& manager_hub = context.GetManagerHub(); manager_hub.Initialize(); if (params.workspaceFolders) { manager_hub.SetWorkspaceFolders(params.workspaceFolders.value()); ProcessWorkspaceFolder(params.workspaceFolders.value(), context); } protocol::ResponseMessage response; response.id = request.id; response.result = transform::ToLSPAny(BuildInitializeResult()); std::optional json = transform::Serialize(response); if (!json.has_value()) { context.TriggerLifecycleEvent(ServerLifecycleEvent::kInitializeFailed); return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "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.definitionProvider = true; // NOTE: Only advertise the minimal feature set for now: // - completion (with resolve) // - go-to-definition // // Staged rollout: keep other capabilities disabled. Uncomment as features are re-enabled. // result.capabilities.typeDefinitionProvider = true; // result.capabilities.implementationProvider = true; // result.capabilities.hoverProvider = true; // result.capabilities.signatureHelpProvider = BuildSignatureHelpOptions(); // result.capabilities.codeActionProvider = BuildCodeActionOptions(); // result.capabilities.codeLensProvider = protocol::CodeLensOptions{ .resolveProvider = true }; // result.capabilities.documentLinkProvider = protocol::DocumentLinkOptions{ .resolveProvider = true }; // result.capabilities.colorProvider = true; // result.capabilities.referencesProvider = true; // result.capabilities.documentHighlightProvider = true; // result.capabilities.renameProvider = protocol::RenameOptions{ .prepareProvider = true }; // result.capabilities.documentSymbolProvider = true; // result.capabilities.workspaceSymbolProvider = protocol::WorkspaceSymbolOptions{ .resolveProvider = true }; // result.capabilities.semanticTokensProvider = BuildSemanticTokenOptions(); // result.capabilities.callHierarchyProvider = true; // result.capabilities.typeHierarchyProvider = true; // result.capabilities.inlayHintProvider = protocol::InlayHintOptions{ .resolveProvider = true }; // result.capabilities.foldingRangeProvider = true; // result.capabilities.selectionRangeProvider = true; // result.capabilities.linkedEditingRangeProvider = true; // result.capabilities.monikerProvider = true; // result.capabilities.inlineValueProvider = true; // result.capabilities.documentFormattingProvider = true; // result.capabilities.documentRangeFormattingProvider = true; // result.capabilities.documentOnTypeFormattingProvider = BuildOnTypeFormattingOptions(); // result.capabilities.executeCommandProvider = BuildExecuteCommandOptions(); // // protocol::DiagnosticOptions diagnostic; // diagnostic.identifier = "syntax"; // diagnostic.interFileDependencies = false; // diagnostic.workspaceDiagnostics = true; // result.capabilities.diagnosticProvider = std::move(diagnostic); // // protocol::ServerCapabilities::Workspace workspace; // protocol::ServerCapabilities::Workspace::FileOperations file_operations; // file_operations.didCreate = true; // file_operations.willCreate = true; // file_operations.didDelete = true; // file_operations.willDelete = true; // file_operations.didRename = true; // file_operations.willRename = true; // workspace.fileOperations = std::move(file_operations); // result.capabilities.workspace = std::move(workspace); return result; } protocol::TextDocumentSyncOptions Initialize::BuildTextDocumentSyncOptions() { protocol::TextDocumentSyncOptions options; options.openClose = true; options.change = protocol::TextDocumentSyncKind::Incremental; return options; } protocol::CompletionOptions Initialize::BuildCompletionOptions() { protocol::CompletionOptions options; options.triggerCharacters = { std::vector{ ".", "(" } }; options.resolveProvider = true; options.completionItem = { .labelDetailsSupport = true }; return options; } protocol::SignatureHelpOptions Initialize::BuildSignatureHelpOptions() { protocol::SignatureHelpOptions options; options.triggerCharacters = { std::vector{ "(", "," } }; options.retriggerCharacters = { std::vector{ "(", "," } }; return options; } protocol::CodeActionOptions Initialize::BuildCodeActionOptions() { protocol::CodeActionOptions options; options.codeActionKinds = std::vector{ protocol::CodeActionKindLiterals::QuickFix, protocol::CodeActionKindLiterals::SourceFixAll, }; options.resolveProvider = true; return options; } protocol::DocumentOnTypeFormattingOptions Initialize::BuildOnTypeFormattingOptions() { protocol::DocumentOnTypeFormattingOptions options; options.firstTriggerCharacter = ";"; options.moreTriggerCharacter = std::vector{ "\n" }; return options; } protocol::ExecuteCommandOptions Initialize::BuildExecuteCommandOptions() { protocol::ExecuteCommandOptions options; options.commands = std::vector{ "tsl.noop", "tsl.loadWorkspace", "tsl.indexFiles", }; return options; } protocol::SemanticTokensOptions Initialize::BuildSemanticTokenOptions() { protocol::SemanticTokensOptions options; options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Namespace); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Class); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Method); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Function); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Property); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Variable); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Parameter); options.legend.tokenTypes.emplace_back(protocol::SemanticTokenTypesLiterals::Keyword); 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::Operator); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Declaration); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Definition); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Static); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Readonly); options.legend.tokenModifiers.emplace_back(protocol::SemanticTokenModifiersLiterals::Modification); options.range = true; options.full = protocol::SemanticTokensOptions::Full{ .delta = true }; return options; } void Initialize::ProcessWorkspaceFolder(const std::vector& workspace_folders, ExecutionContext& context) { auto& manager_hub = context.GetManagerHub(); auto& scheduler = context.GetScheduler(); for (const auto& workspace_folder : workspace_folders) { auto task_id = std::format("Load workspace symbols: {}", workspace_folder.uri); scheduler.Submit(task_id, [&manager_hub, uri = workspace_folder.uri, folder_name = workspace_folder.name](std::stop_token stop_token) -> std::optional { try { manager_hub.symbols().LoadWorkspace(uri, stop_token); return std::format("Loaded workspace {} symbols", uri); } catch (const std::exception& e) { spdlog::error("Failed to load workspace {} symbols: {}", folder_name, e.what()); throw; // Request会处理异常 } }, [](const ::lsp::scheduler::async_executor::TaskResult& result) { if (result.status == ::lsp::scheduler::async_executor::TaskStatus::kCancelled) { spdlog::debug("Workspace loading task cancelled"); } else if (result.status == ::lsp::scheduler::async_executor::TaskStatus::kCompleted && result.value) { spdlog::info("Workspace loading result: {}", *result.value); } }); } spdlog::debug("Initiated loading for {} workspace folder(s)", workspace_folders.size()); } }