244 lines
11 KiB
C++
244 lines
11 KiB
C++
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<Initialize, IRequestProvider>
|
|
{
|
|
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<protocol::WorkspaceFolder>& 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()<protocol::InitializeParams>(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<std::string> 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<std::string>{ ".", "(" } };
|
|
options.resolveProvider = true;
|
|
options.completionItem = { .labelDetailsSupport = true };
|
|
return options;
|
|
}
|
|
|
|
protocol::SignatureHelpOptions Initialize::BuildSignatureHelpOptions()
|
|
{
|
|
protocol::SignatureHelpOptions options;
|
|
options.triggerCharacters = { std::vector<std::string>{ "(", "," } };
|
|
options.retriggerCharacters = { std::vector<std::string>{ "(", "," } };
|
|
return options;
|
|
}
|
|
|
|
protocol::CodeActionOptions Initialize::BuildCodeActionOptions()
|
|
{
|
|
protocol::CodeActionOptions options;
|
|
options.codeActionKinds = std::vector<protocol::CodeActionKind>{
|
|
protocol::CodeActionKindLiterals::QuickFix,
|
|
protocol::CodeActionKindLiterals::SourceFixAll,
|
|
};
|
|
options.resolveProvider = true;
|
|
return options;
|
|
}
|
|
|
|
protocol::DocumentOnTypeFormattingOptions Initialize::BuildOnTypeFormattingOptions()
|
|
{
|
|
protocol::DocumentOnTypeFormattingOptions options;
|
|
options.firstTriggerCharacter = ";";
|
|
options.moreTriggerCharacter = std::vector<protocol::string>{ "\n" };
|
|
return options;
|
|
}
|
|
|
|
protocol::ExecuteCommandOptions Initialize::BuildExecuteCommandOptions()
|
|
{
|
|
protocol::ExecuteCommandOptions options;
|
|
options.commands = std::vector<protocol::string>{
|
|
"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<protocol::WorkspaceFolder>& 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<std::string> {
|
|
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());
|
|
}
|
|
|
|
}
|