🐛 fix(core): enforce strict LSP lifecycle
This commit is contained in:
@@ -6,6 +6,7 @@ import spdlog;
|
||||
import std;
|
||||
|
||||
import lsp.core.server;
|
||||
import lsp.provider.manifest;
|
||||
import lsp.utils.args_parser;
|
||||
|
||||
namespace
|
||||
@@ -46,11 +47,17 @@ export int Run(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
int exit_code = 1;
|
||||
try
|
||||
{
|
||||
spdlog::info("TSL-LSP server starting...");
|
||||
lsp::core::LspServer server(config.thread_count, config.interpreter_path);
|
||||
server.Run();
|
||||
lsp::core::LspServer server(
|
||||
std::cin,
|
||||
std::cout,
|
||||
lsp::provider::RegisterAllProviders,
|
||||
config.thread_count,
|
||||
config.interpreter_path);
|
||||
exit_code = server.Run();
|
||||
}
|
||||
catch (const std::exception& error)
|
||||
{
|
||||
@@ -67,7 +74,7 @@ export int Run(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
spdlog::info("TSL-LSP server stopped normally");
|
||||
spdlog::info("TSL-LSP server stopped with exit code {}", exit_code);
|
||||
spdlog::shutdown();
|
||||
return 0;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
module;
|
||||
|
||||
export module lsp.core.dispatcher;
|
||||
import spdlog;
|
||||
|
||||
import spdlog;
|
||||
import std;
|
||||
import lsp.protocol.types;
|
||||
|
||||
import lsp.codec.facade;
|
||||
import lsp.scheduler.async_executor;
|
||||
import lsp.manager.manager_hub;
|
||||
import lsp.protocol.types;
|
||||
import lsp.scheduler.async_executor;
|
||||
|
||||
namespace transform = lsp::codec;
|
||||
|
||||
export namespace lsp::core
|
||||
{
|
||||
enum class ServerLifecycleEvent
|
||||
{
|
||||
kInitializing,
|
||||
kInitialized,
|
||||
kInitializeFailed,
|
||||
kShuttingDown,
|
||||
kShutdown
|
||||
};
|
||||
|
||||
using LifecycleCallback = std::function<void(ServerLifecycleEvent)>;
|
||||
|
||||
class IProvider
|
||||
{
|
||||
public:
|
||||
@@ -32,61 +22,65 @@ export namespace lsp::core
|
||||
virtual std::string GetProviderName() const = 0;
|
||||
};
|
||||
|
||||
class ExecutionContext;
|
||||
|
||||
class IRequestProvider : public IProvider
|
||||
{
|
||||
public:
|
||||
virtual ~IRequestProvider() = default;
|
||||
virtual std::string ProvideResponse(const protocol::RequestMessage& request, class ExecutionContext& execution_context) = 0;
|
||||
virtual std::string ProvideResponse(const protocol::RequestMessage& request,
|
||||
ExecutionContext& execution_context) = 0;
|
||||
};
|
||||
|
||||
class INotificationProvider : public IProvider
|
||||
{
|
||||
public:
|
||||
virtual ~INotificationProvider() = default;
|
||||
virtual void HandleNotification(const protocol::NotificationMessage& notification, class ExecutionContext& execution_context) = 0;
|
||||
virtual void HandleNotification(const protocol::NotificationMessage& notification,
|
||||
ExecutionContext& execution_context) = 0;
|
||||
};
|
||||
|
||||
class ExecutionContext
|
||||
{
|
||||
public:
|
||||
ExecutionContext(LifecycleCallback lifecycle_callback,
|
||||
scheduler::async_executor::AsyncExecutor& scheduler,
|
||||
manager::ManagerHub& manager_hub) :
|
||||
lifecycle_callback_(lifecycle_callback),
|
||||
async_executor_(scheduler),
|
||||
manager_hub_(manager_hub) {}
|
||||
|
||||
scheduler::async_executor::AsyncExecutor& GetScheduler() const { return async_executor_; }
|
||||
manager::ManagerHub& GetManagerHub() const { return manager_hub_; }
|
||||
|
||||
void TriggerLifecycleEvent(ServerLifecycleEvent event) const
|
||||
ExecutionContext(scheduler::async_executor::AsyncExecutor& scheduler,
|
||||
manager::ManagerHub& manager_hub)
|
||||
: async_executor_(scheduler), manager_hub_(manager_hub)
|
||||
{
|
||||
if (lifecycle_callback_)
|
||||
lifecycle_callback_(event);
|
||||
}
|
||||
|
||||
scheduler::async_executor::AsyncExecutor& GetScheduler() const
|
||||
{
|
||||
return async_executor_;
|
||||
}
|
||||
|
||||
manager::ManagerHub& GetManagerHub() const
|
||||
{
|
||||
return manager_hub_;
|
||||
}
|
||||
|
||||
private:
|
||||
LifecycleCallback lifecycle_callback_;
|
||||
scheduler::async_executor::AsyncExecutor& async_executor_;
|
||||
manager::ManagerHub& manager_hub_;
|
||||
};
|
||||
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message);
|
||||
std::string BuildErrorResponseMessage(std::optional<protocol::RequestId> id,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message);
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message);
|
||||
|
||||
class RequestDispatcher
|
||||
{
|
||||
public:
|
||||
RequestDispatcher();
|
||||
RequestDispatcher(scheduler::async_executor::AsyncExecutor& scheduler,
|
||||
manager::ManagerHub& manager_hub);
|
||||
~RequestDispatcher() = default;
|
||||
|
||||
void SetRequestScheduler(scheduler::async_executor::AsyncExecutor* scheduler);
|
||||
void SetManagerHub(manager::ManagerHub* manager_hub);
|
||||
|
||||
void RegisterRequestProvider(std::shared_ptr<IRequestProvider> provider);
|
||||
void RegisterNotificationProvider(std::shared_ptr<INotificationProvider> provider);
|
||||
|
||||
void RegisterLifecycleCallback(LifecycleCallback callback);
|
||||
|
||||
std::string Dispatch(const protocol::RequestMessage& request);
|
||||
void Dispatch(const protocol::NotificationMessage& notification);
|
||||
|
||||
@@ -97,99 +91,71 @@ export namespace lsp::core
|
||||
std::vector<std::string> GetAllSupportedMethods() const;
|
||||
|
||||
private:
|
||||
void NotifyAllLifecycleListeners(ServerLifecycleEvent event);
|
||||
std::string HandleUnknownRequest(const protocol::RequestMessage& request);
|
||||
void HandleUnknownNotification(const protocol::NotificationMessage& notification);
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex providers_mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<IRequestProvider>> providers_;
|
||||
|
||||
mutable std::shared_mutex notification_providers_mutex_;
|
||||
std::unordered_map<std::string, std::shared_ptr<INotificationProvider>> notification_providers_;
|
||||
std::unordered_map<std::string, std::shared_ptr<INotificationProvider>>
|
||||
notification_providers_;
|
||||
|
||||
std::mutex callbacks_mutex_;
|
||||
std::vector<LifecycleCallback> lifecycle_callbacks_;
|
||||
|
||||
LifecycleCallback context_lifecycle_callback_;
|
||||
|
||||
scheduler::async_executor::AsyncExecutor* async_executor_ = nullptr;
|
||||
manager::ManagerHub* manager_hub_ = nullptr;
|
||||
scheduler::async_executor::AsyncExecutor& async_executor_;
|
||||
manager::ManagerHub& manager_hub_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lsp::core
|
||||
{
|
||||
RequestDispatcher::RequestDispatcher()
|
||||
RequestDispatcher::RequestDispatcher(
|
||||
scheduler::async_executor::AsyncExecutor& scheduler,
|
||||
manager::ManagerHub& manager_hub)
|
||||
: async_executor_(scheduler), manager_hub_(manager_hub)
|
||||
{
|
||||
context_lifecycle_callback_ = [this](ServerLifecycleEvent event) {
|
||||
NotifyAllLifecycleListeners(event);
|
||||
};
|
||||
}
|
||||
|
||||
void RequestDispatcher::SetRequestScheduler(scheduler::async_executor::AsyncExecutor* scheduler)
|
||||
void RequestDispatcher::RegisterRequestProvider(
|
||||
std::shared_ptr<IRequestProvider> provider)
|
||||
{
|
||||
async_executor_ = scheduler;
|
||||
spdlog::debug("Request scheduler set");
|
||||
}
|
||||
|
||||
void RequestDispatcher::SetManagerHub(manager::ManagerHub* manager_hub)
|
||||
{
|
||||
manager_hub_ = manager_hub;
|
||||
spdlog::debug("Manager hub bound to dispatcher");
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterRequestProvider(std::shared_ptr<IRequestProvider> provider)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
std::unique_lock lock(providers_mutex_);
|
||||
std::string method = provider->GetMethod();
|
||||
providers_[method] = provider;
|
||||
providers_[method] = std::move(provider);
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterNotificationProvider(std::shared_ptr<INotificationProvider> provider)
|
||||
void RequestDispatcher::RegisterNotificationProvider(
|
||||
std::shared_ptr<INotificationProvider> provider)
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
std::unique_lock lock(notification_providers_mutex_);
|
||||
std::string method = provider->GetMethod();
|
||||
notification_providers_[method] = provider;
|
||||
}
|
||||
|
||||
void RequestDispatcher::RegisterLifecycleCallback(LifecycleCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
lifecycle_callbacks_.push_back(std::move(callback));
|
||||
notification_providers_[method] = std::move(provider);
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
|
||||
{
|
||||
std::shared_ptr<IRequestProvider> provider = nullptr;
|
||||
std::shared_ptr<IRequestProvider> provider;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
auto it = providers_.find(request.method);
|
||||
if (it != providers_.end())
|
||||
provider = it->second;
|
||||
std::shared_lock lock(providers_mutex_);
|
||||
auto provider_it = providers_.find(request.method);
|
||||
if (provider_it != providers_.end())
|
||||
provider = provider_it->second;
|
||||
}
|
||||
|
||||
if (!provider)
|
||||
return HandleUnknownRequest(request);
|
||||
|
||||
if (!async_executor_ || !manager_hub_)
|
||||
{
|
||||
spdlog::error("RequestDispatcher dependencies not set");
|
||||
return "{}";
|
||||
}
|
||||
|
||||
ExecutionContext context(context_lifecycle_callback_, *async_executor_, *manager_hub_);
|
||||
ExecutionContext context(async_executor_, manager_hub_);
|
||||
return provider->ProvideResponse(request, context);
|
||||
}
|
||||
|
||||
void RequestDispatcher::Dispatch(const protocol::NotificationMessage& notification)
|
||||
{
|
||||
std::shared_ptr<INotificationProvider> provider = nullptr;
|
||||
std::shared_ptr<INotificationProvider> provider;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
auto it = notification_providers_.find(notification.method);
|
||||
if (it != notification_providers_.end())
|
||||
provider = it->second;
|
||||
std::shared_lock lock(notification_providers_mutex_);
|
||||
auto provider_it = notification_providers_.find(notification.method);
|
||||
if (provider_it != notification_providers_.end())
|
||||
provider = provider_it->second;
|
||||
}
|
||||
|
||||
if (!provider)
|
||||
@@ -198,45 +164,45 @@ namespace lsp::core
|
||||
return;
|
||||
}
|
||||
|
||||
if (!async_executor_ || !manager_hub_)
|
||||
{
|
||||
spdlog::error("NotificationDispatcher dependencies not set");
|
||||
return;
|
||||
}
|
||||
|
||||
ExecutionContext context(context_lifecycle_callback_, *async_executor_, *manager_hub_);
|
||||
ExecutionContext context(async_executor_, manager_hub_);
|
||||
provider->HandleNotification(notification, context);
|
||||
}
|
||||
|
||||
bool RequestDispatcher::SupportsRequest(const std::string& method) const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
std::shared_lock lock(providers_mutex_);
|
||||
return providers_.contains(method);
|
||||
}
|
||||
|
||||
bool RequestDispatcher::SupportsNotification(const std::string& method) const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
std::shared_lock lock(notification_providers_mutex_);
|
||||
return notification_providers_.contains(method);
|
||||
}
|
||||
|
||||
std::vector<std::string> RequestDispatcher::GetSupportedRequests() const
|
||||
{
|
||||
std::vector<std::string> methods;
|
||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||
std::shared_lock lock(providers_mutex_);
|
||||
methods.reserve(providers_.size());
|
||||
for (const auto& [method, _] : providers_)
|
||||
for (const auto& [method, provider] : providers_)
|
||||
{
|
||||
static_cast<void>(provider);
|
||||
methods.push_back(method);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
std::vector<std::string> RequestDispatcher::GetSupportedNotifications() const
|
||||
{
|
||||
std::vector<std::string> methods;
|
||||
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
|
||||
std::shared_lock lock(notification_providers_mutex_);
|
||||
methods.reserve(notification_providers_.size());
|
||||
for (const auto& [method, _] : notification_providers_)
|
||||
for (const auto& [method, provider] : notification_providers_)
|
||||
{
|
||||
static_cast<void>(provider);
|
||||
methods.push_back(method);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
@@ -248,48 +214,40 @@ namespace lsp::core
|
||||
return methods;
|
||||
}
|
||||
|
||||
void RequestDispatcher::NotifyAllLifecycleListeners(ServerLifecycleEvent event)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||
for (const auto& callback : lifecycle_callbacks_)
|
||||
{
|
||||
if (callback)
|
||||
callback(event);
|
||||
}
|
||||
}
|
||||
|
||||
std::string RequestDispatcher::HandleUnknownRequest(const protocol::RequestMessage& request)
|
||||
std::string RequestDispatcher::HandleUnknownRequest(
|
||||
const protocol::RequestMessage& request)
|
||||
{
|
||||
spdlog::warn("No request provider registered for method: {}", request.method);
|
||||
return BuildErrorResponseMessage(
|
||||
request, protocol::ErrorCodes::MethodNotFound, "Method not supported");
|
||||
}
|
||||
|
||||
void RequestDispatcher::HandleUnknownNotification(
|
||||
const protocol::NotificationMessage& notification)
|
||||
{
|
||||
spdlog::warn("No notification provider registered for method: {}",
|
||||
notification.method);
|
||||
}
|
||||
|
||||
std::string BuildErrorResponseMessage(std::optional<protocol::RequestId> id,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message)
|
||||
{
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.id = std::move(id);
|
||||
response.error = protocol::ResponseError{
|
||||
.jsonrpc = "2.0",
|
||||
.code = static_cast<protocol::integer>(protocol::ErrorCodes::MethodNotFound),
|
||||
.message = "Method not supported",
|
||||
.data = std::nullopt
|
||||
.code = static_cast<protocol::integer>(code),
|
||||
.message = std::string(message),
|
||||
.data = std::nullopt,
|
||||
};
|
||||
auto json = transform::Serialize(response);
|
||||
return json.value_or("{}");
|
||||
return transform::Serialize(response).value();
|
||||
}
|
||||
|
||||
void RequestDispatcher::HandleUnknownNotification(const protocol::NotificationMessage& notification)
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message)
|
||||
{
|
||||
spdlog::warn("No notification provider registered for method: {}", notification.method);
|
||||
}
|
||||
|
||||
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message)
|
||||
{
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
protocol::ResponseError error;
|
||||
error.code = static_cast<protocol::integer>(code);
|
||||
error.message = message;
|
||||
response.error = error;
|
||||
auto json = transform::Serialize(response);
|
||||
if (json.has_value())
|
||||
return json.value();
|
||||
spdlog::error("Failed to serialize error response.");
|
||||
return R"({"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to serialize error response"}})";
|
||||
return BuildErrorResponseMessage(request.id, code, message);
|
||||
}
|
||||
}
|
||||
|
||||
+188
-243
@@ -1,65 +1,59 @@
|
||||
module;
|
||||
|
||||
export module lsp.core.server;
|
||||
|
||||
import spdlog;
|
||||
import std;
|
||||
import tree_sitter;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.bridge.win32_stdio;
|
||||
import lsp.core.dispatcher;
|
||||
import lsp.protocol;
|
||||
import lsp.codec.facade;
|
||||
import lsp.core.dispatcher;
|
||||
import lsp.language.ast;
|
||||
import lsp.manager.manager_hub;
|
||||
import lsp.manager.bootstrap;
|
||||
import lsp.manager.events;
|
||||
import lsp.scheduler.async_executor;
|
||||
import lsp.provider.base.interface;
|
||||
import lsp.manager.manager_hub;
|
||||
import lsp.protocol;
|
||||
import lsp.provider.manifest;
|
||||
import lsp.scheduler.async_executor;
|
||||
|
||||
namespace transform = lsp::codec;
|
||||
|
||||
export namespace lsp::core
|
||||
{
|
||||
using ProviderRegistrar = std::function<void(RequestDispatcher&)>;
|
||||
|
||||
enum class ServerState
|
||||
{
|
||||
kUninitialized,
|
||||
kRunning,
|
||||
kShutdownRequested,
|
||||
kExiting,
|
||||
};
|
||||
|
||||
class LspServer
|
||||
{
|
||||
public:
|
||||
explicit LspServer(std::size_t concurrency = std::thread::hardware_concurrency(),
|
||||
std::string interpreter_path = "");
|
||||
~LspServer();
|
||||
void Run();
|
||||
LspServer(std::istream& input,
|
||||
std::ostream& output,
|
||||
ProviderRegistrar registrar,
|
||||
std::size_t concurrency = std::thread::hardware_concurrency(),
|
||||
std::string interpreter_path = "");
|
||||
~LspServer() = default;
|
||||
|
||||
int Run();
|
||||
|
||||
private:
|
||||
// 读取LSP消息
|
||||
std::optional<std::string> ReadMessage();
|
||||
|
||||
// 处理LSP请求 - 返回序列化的响应或空字符串(对于通知)
|
||||
void HandleMessage(const std::string& raw_message);
|
||||
|
||||
// 发送LSP消息(响应/通知)
|
||||
void SendMessage(const std::string& message);
|
||||
|
||||
// 处理不同类型的消息
|
||||
void HandleRequest(const protocol::RequestMessage& request);
|
||||
void HandleNotification(const protocol::NotificationMessage& notification);
|
||||
void HandleResponse(const protocol::ResponseMessage& response);
|
||||
|
||||
// 生命周期事件处理
|
||||
void OnLifecycleEvent(provider::ServerLifecycleEvent event);
|
||||
|
||||
// 判断是否需要同步处理
|
||||
bool RequiresSyncProcessing(const std::string& method) const;
|
||||
|
||||
// 检查是否可以处理请求
|
||||
bool CanProcessRequest(const std::string& method) const;
|
||||
|
||||
// 处理取消请求
|
||||
void HandleCancelRequest(const protocol::NotificationMessage& notification);
|
||||
|
||||
private:
|
||||
void InitializeManagerHub();
|
||||
void RegisterProviders();
|
||||
void RegisterProviders(ProviderRegistrar registrar);
|
||||
void RegisterDiagnosticsPublisher();
|
||||
|
||||
void PublishDiagnostics(const protocol::DocumentUri& uri,
|
||||
@@ -68,32 +62,42 @@ export namespace lsp::core
|
||||
const protocol::string& content);
|
||||
void ClearDiagnostics(const protocol::DocumentUri& uri);
|
||||
|
||||
// 错误处理
|
||||
void SendError(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message);
|
||||
void SendStateError(const protocol::RequestMessage& request);
|
||||
void SendError(const protocol::RequestMessage& request,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message);
|
||||
|
||||
private:
|
||||
RequestDispatcher dispatcher_;
|
||||
std::istream& input_;
|
||||
std::ostream& output_;
|
||||
manager::ManagerHub manager_hub_;
|
||||
scheduler::async_executor::AsyncExecutor async_executor_;
|
||||
RequestDispatcher dispatcher_;
|
||||
std::string interpreter_path_;
|
||||
|
||||
std::atomic<bool> is_initialized_ = false;
|
||||
std::atomic<bool> is_shutting_down_ = false;
|
||||
ServerState state_ = ServerState::kUninitialized;
|
||||
int exit_code_ = 1;
|
||||
std::atomic<bool> fatal_io_error_ = false;
|
||||
std::mutex output_mutex_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lsp::core
|
||||
{
|
||||
LspServer::LspServer(std::size_t concurrency, std::string interpreter_path) : manager_hub_(),
|
||||
async_executor_(concurrency),
|
||||
interpreter_path_(std::move(interpreter_path))
|
||||
LspServer::LspServer(std::istream& input,
|
||||
std::ostream& output,
|
||||
ProviderRegistrar registrar,
|
||||
std::size_t concurrency,
|
||||
std::string interpreter_path)
|
||||
: input_(input),
|
||||
output_(output),
|
||||
manager_hub_(),
|
||||
async_executor_(concurrency),
|
||||
dispatcher_(async_executor_, manager_hub_),
|
||||
interpreter_path_(std::move(interpreter_path))
|
||||
{
|
||||
spdlog::info("Initializing LSP server with {} worker threads", concurrency);
|
||||
|
||||
InitializeManagerHub();
|
||||
RegisterProviders();
|
||||
RegisterProviders(std::move(registrar));
|
||||
if (provider::kEnableDiagnosticsPublisher)
|
||||
{
|
||||
RegisterDiagnosticsPublisher();
|
||||
@@ -103,48 +107,48 @@ namespace lsp::core
|
||||
spdlog::debug("Diagnostics publisher disabled (staged rollout)");
|
||||
}
|
||||
|
||||
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetAllSupportedMethods().size());
|
||||
spdlog::debug("LSP server initialized with {} providers.",
|
||||
dispatcher_.GetAllSupportedMethods().size());
|
||||
}
|
||||
|
||||
LspServer::~LspServer()
|
||||
{
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("LSP server shutting down...");
|
||||
}
|
||||
|
||||
void LspServer::Run()
|
||||
int LspServer::Run()
|
||||
{
|
||||
spdlog::info("LSP server starting main loop...");
|
||||
spdlog::info("Waiting for LSP messages on stdin...");
|
||||
|
||||
bridge::win32_stdio::SetStdioBinaryMode();
|
||||
|
||||
while (!is_shutting_down_)
|
||||
while (state_ != ServerState::kExiting)
|
||||
{
|
||||
if (fatal_io_error_)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
std::optional<std::string> message = ReadMessage();
|
||||
auto message = ReadMessage();
|
||||
if (!message)
|
||||
{
|
||||
if (std::cin.eof())
|
||||
{
|
||||
spdlog::info("End of input stream, exiting main loop");
|
||||
break; // EOF
|
||||
}
|
||||
spdlog::debug("No message received, continuing...");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
continue;
|
||||
spdlog::info("End of input stream, exiting main loop");
|
||||
break;
|
||||
}
|
||||
|
||||
HandleMessage(*message);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
catch (const std::exception& error)
|
||||
{
|
||||
spdlog::error("Error in main loop: {}", e.what());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
spdlog::error("Fatal error in main loop: {}", error.what());
|
||||
exit_code_ = 1;
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
spdlog::error("Unknown fatal error in main loop");
|
||||
exit_code_ = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spdlog::info("LSP server main loop ended");
|
||||
return exit_code_;
|
||||
}
|
||||
|
||||
std::optional<std::string> LspServer::ReadMessage()
|
||||
@@ -152,56 +156,32 @@ namespace lsp::core
|
||||
std::string line;
|
||||
std::size_t content_length = 0;
|
||||
|
||||
// 读取 LSP Header
|
||||
while (std::getline(std::cin, line))
|
||||
while (std::getline(input_, line))
|
||||
{
|
||||
// 去掉尾部 \\r
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
{
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
if (line.empty())
|
||||
{
|
||||
break; // 空行表示 header 结束
|
||||
}
|
||||
break;
|
||||
|
||||
if (line.rfind("Content-Length:", 0) == 0)
|
||||
{
|
||||
std::string length_str = line.substr(15); // 跳过 "Content-Length:"
|
||||
std::size_t start = length_str.find_first_not_of(' ');
|
||||
if (start != std::string::npos)
|
||||
{
|
||||
length_str = length_str.substr(start);
|
||||
try
|
||||
{
|
||||
content_length = std::stoul(length_str);
|
||||
spdlog::trace("Content-Length: {}", content_length);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
spdlog::error("Failed to parse Content-Length: {}", e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line.rfind("Content-Length:", 0) != 0)
|
||||
continue;
|
||||
|
||||
std::string length = line.substr(std::string_view("Content-Length:").size());
|
||||
const auto start = length.find_first_not_of(' ');
|
||||
if (start == std::string::npos)
|
||||
return std::nullopt;
|
||||
|
||||
content_length = std::stoul(length.substr(start));
|
||||
}
|
||||
|
||||
if (content_length == 0)
|
||||
{
|
||||
spdlog::debug("No Content-Length found in header");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 读取内容体
|
||||
std::string body(content_length, '\0');
|
||||
std::cin.read(&body[0], content_length);
|
||||
|
||||
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
|
||||
{
|
||||
spdlog::error("Failed to read expected content length: {} bytes, got {} bytes", content_length, std::cin.gcount());
|
||||
input_.read(body.data(), static_cast<std::streamsize>(content_length));
|
||||
if (input_.gcount() != static_cast<std::streamsize>(content_length))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
spdlog::trace("Received message: {}", body);
|
||||
return body;
|
||||
@@ -216,11 +196,11 @@ namespace lsp::core
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& obj = any->Get<protocol::LSPObject>();
|
||||
const bool has_id = obj.find("id") != obj.end();
|
||||
const bool has_method = obj.find("method") != obj.end();
|
||||
const bool has_result = obj.find("result") != obj.end();
|
||||
const bool has_error = obj.find("error") != obj.end();
|
||||
const auto& object = any->Get<protocol::LSPObject>();
|
||||
const bool has_id = object.contains("id");
|
||||
const bool has_method = object.contains("method");
|
||||
const bool has_result = object.contains("result");
|
||||
const bool has_error = object.contains("error");
|
||||
|
||||
if (has_method && has_id)
|
||||
{
|
||||
@@ -233,10 +213,15 @@ namespace lsp::core
|
||||
|
||||
if (has_method)
|
||||
{
|
||||
if (auto notification = transform::Deserialize<protocol::NotificationMessage>(raw_message))
|
||||
if (auto notification =
|
||||
transform::Deserialize<protocol::NotificationMessage>(raw_message))
|
||||
{
|
||||
HandleNotification(*notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::warn("Failed to parse notification message");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,35 +239,84 @@ namespace lsp::core
|
||||
|
||||
void LspServer::SendMessage(const std::string& message)
|
||||
{
|
||||
if (message.empty())
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(output_mutex_);
|
||||
std::cout << "Content-Length: " << message.size() << "\r\n\r\n"
|
||||
<< message << std::flush;
|
||||
std::lock_guard lock(output_mutex_);
|
||||
output_ << "Content-Length: " << message.size() << "\r\n\r\n"
|
||||
<< message << std::flush;
|
||||
if (!output_)
|
||||
{
|
||||
fatal_io_error_ = true;
|
||||
throw std::runtime_error("Failed to write LSP message");
|
||||
}
|
||||
}
|
||||
|
||||
void LspServer::HandleRequest(const protocol::RequestMessage& request)
|
||||
{
|
||||
spdlog::debug("Handling request: {}", request.method);
|
||||
|
||||
if (request.method == "initialize")
|
||||
{
|
||||
if (state_ != ServerState::kUninitialized)
|
||||
{
|
||||
SendError(request,
|
||||
protocol::ErrorCodes::InvalidRequest,
|
||||
"Server is already initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto response = dispatcher_.Dispatch(request);
|
||||
SendMessage(response);
|
||||
const auto parsed = transform::Deserialize<protocol::ResponseMessage>(response);
|
||||
if (!parsed)
|
||||
throw std::runtime_error("Initialize provider returned an invalid response");
|
||||
if (!parsed->error)
|
||||
state_ = ServerState::kRunning;
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method == "shutdown")
|
||||
{
|
||||
auto response = dispatcher_.Dispatch(request);
|
||||
SendMessage(response);
|
||||
is_shutting_down_ = true;
|
||||
if (state_ == ServerState::kUninitialized)
|
||||
{
|
||||
SendError(request,
|
||||
protocol::ErrorCodes::ServerNotInitialized,
|
||||
"Server not initialized");
|
||||
return;
|
||||
}
|
||||
if (state_ != ServerState::kRunning)
|
||||
{
|
||||
SendError(request,
|
||||
protocol::ErrorCodes::InvalidRequest,
|
||||
"Shutdown already requested");
|
||||
return;
|
||||
}
|
||||
|
||||
async_executor_.WaitAll();
|
||||
manager_hub_.Shutdown();
|
||||
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
response.result = protocol::LSPAny(std::nullptr_t{});
|
||||
SendMessage(transform::Serialize(response).value());
|
||||
state_ = ServerState::kShutdownRequested;
|
||||
return;
|
||||
}
|
||||
|
||||
// 未初始化时的特殊处理
|
||||
if (!is_initialized_ && request.method != "initialize")
|
||||
if (state_ == ServerState::kUninitialized)
|
||||
{
|
||||
SendStateError(request);
|
||||
SendError(request,
|
||||
protocol::ErrorCodes::ServerNotInitialized,
|
||||
"Server not initialized");
|
||||
return;
|
||||
}
|
||||
if (state_ == ServerState::kShutdownRequested)
|
||||
{
|
||||
SendError(request,
|
||||
protocol::ErrorCodes::InvalidRequest,
|
||||
"Server is shutting down");
|
||||
return;
|
||||
}
|
||||
|
||||
auto response = dispatcher_.Dispatch(request);
|
||||
SendMessage(response);
|
||||
SendMessage(dispatcher_.Dispatch(request));
|
||||
}
|
||||
|
||||
void LspServer::HandleNotification(const protocol::NotificationMessage& notification)
|
||||
@@ -291,21 +325,17 @@ namespace lsp::core
|
||||
|
||||
if (notification.method == "exit")
|
||||
{
|
||||
is_shutting_down_ = true;
|
||||
const bool orderly = state_ == ServerState::kShutdownRequested;
|
||||
state_ = ServerState::kExiting;
|
||||
exit_code_ = orderly ? 0 : 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理取消请求
|
||||
if (notification.method == "$/cancelRequest")
|
||||
if (state_ != ServerState::kRunning)
|
||||
{
|
||||
HandleCancelRequest(notification);
|
||||
return;
|
||||
}
|
||||
|
||||
// 未初始化时只接受 initialized/exit
|
||||
if (!is_initialized_ && notification.method != "initialized" && notification.method != "exit")
|
||||
{
|
||||
spdlog::warn("Server not initialized; ignoring notification: {}", notification.method);
|
||||
spdlog::warn("Ignoring notification {} in server state {}",
|
||||
notification.method,
|
||||
static_cast<int>(state_));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -315,108 +345,37 @@ namespace lsp::core
|
||||
void LspServer::HandleResponse(const protocol::ResponseMessage& response)
|
||||
{
|
||||
std::string id = "<no id>";
|
||||
if (response.id.has_value())
|
||||
id = transform::debug::GetIdString(response.id.value());
|
||||
if (response.id)
|
||||
id = transform::debug::GetIdString(*response.id);
|
||||
spdlog::debug("Received response: {}", id);
|
||||
// 当前服务器作为 client 的场景较少,这里暂时不处理
|
||||
}
|
||||
|
||||
void LspServer::OnLifecycleEvent(provider::ServerLifecycleEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case provider::ServerLifecycleEvent::kInitialized:
|
||||
is_initialized_ = true;
|
||||
spdlog::info("Server initialized");
|
||||
break;
|
||||
case provider::ServerLifecycleEvent::kShutdown:
|
||||
is_shutting_down_ = true;
|
||||
spdlog::info("Server shutting down");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool LspServer::RequiresSyncProcessing(const std::string& method) const
|
||||
{
|
||||
static const std::unordered_set<std::string> kSyncMethods = {
|
||||
"initialize",
|
||||
"shutdown",
|
||||
"exit",
|
||||
"$/setTrace",
|
||||
};
|
||||
return kSyncMethods.contains(method);
|
||||
}
|
||||
|
||||
bool LspServer::CanProcessRequest(const std::string& method) const
|
||||
{
|
||||
if (is_shutting_down_)
|
||||
return false;
|
||||
|
||||
// 初始化前,只处理 initialize 请求
|
||||
if (!is_initialized_ && method != "initialize")
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LspServer::HandleCancelRequest(const protocol::NotificationMessage& notification)
|
||||
{
|
||||
if (!notification.params.has_value())
|
||||
return;
|
||||
|
||||
protocol::CancelParams params =
|
||||
transform::FromLSPAny.template operator()<protocol::CancelParams>(notification.params.value());
|
||||
|
||||
const std::string id_string = std::visit([](const auto& value) -> std::string {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, int>)
|
||||
return std::to_string(value);
|
||||
else
|
||||
return value;
|
||||
},
|
||||
params.id);
|
||||
|
||||
spdlog::debug("Cancel request received for id: {}", id_string);
|
||||
// TODO: 实现请求取消逻辑
|
||||
}
|
||||
|
||||
void LspServer::InitializeManagerHub()
|
||||
{
|
||||
manager_hub_.Initialize();
|
||||
|
||||
if (!interpreter_path_.empty())
|
||||
if (interpreter_path_.empty())
|
||||
return;
|
||||
|
||||
const std::filesystem::path funcext_path =
|
||||
std::filesystem::path(interpreter_path_) / "funcext";
|
||||
if (!std::filesystem::exists(funcext_path))
|
||||
{
|
||||
std::filesystem::path base = interpreter_path_;
|
||||
std::filesystem::path funcext_path = base / "funcext";
|
||||
if (std::filesystem::exists(funcext_path))
|
||||
{
|
||||
manager::bootstrap::InitializeManagerHub(
|
||||
manager_hub_,
|
||||
async_executor_,
|
||||
{ funcext_path.string() });
|
||||
}
|
||||
else
|
||||
{
|
||||
spdlog::warn("Interpreter funcext path does not exist: {}", funcext_path.string());
|
||||
}
|
||||
spdlog::warn("Interpreter funcext path does not exist: {}",
|
||||
funcext_path.string());
|
||||
return;
|
||||
}
|
||||
|
||||
manager::bootstrap::InitializeManagerHub(
|
||||
manager_hub_, async_executor_, {funcext_path.string()});
|
||||
}
|
||||
|
||||
void LspServer::RegisterProviders()
|
||||
void LspServer::RegisterProviders(ProviderRegistrar registrar)
|
||||
{
|
||||
dispatcher_.SetRequestScheduler(&async_executor_);
|
||||
dispatcher_.SetManagerHub(&manager_hub_);
|
||||
|
||||
dispatcher_.RegisterLifecycleCallback([this](ServerLifecycleEvent event) {
|
||||
OnLifecycleEvent(event);
|
||||
});
|
||||
|
||||
spdlog::info("Registering LSP providers...");
|
||||
|
||||
provider::RegisterAllProviders(dispatcher_);
|
||||
|
||||
spdlog::info("Registered {} LSP providers", dispatcher_.GetAllSupportedMethods().size());
|
||||
registrar(dispatcher_);
|
||||
spdlog::info("Registered {} LSP providers",
|
||||
dispatcher_.GetAllSupportedMethods().size());
|
||||
}
|
||||
|
||||
void LspServer::RegisterDiagnosticsPublisher()
|
||||
@@ -425,12 +384,14 @@ namespace lsp::core
|
||||
|
||||
event_bus.Subscribe<manager::events::DocumentParsed>(
|
||||
[this](const manager::events::DocumentParsed& event) {
|
||||
PublishDiagnostics(event.item.uri, event.item.version, event.tree, event.item.text);
|
||||
PublishDiagnostics(
|
||||
event.item.uri, event.item.version, event.tree, event.item.text);
|
||||
});
|
||||
|
||||
event_bus.Subscribe<manager::events::DocumentReparsed>(
|
||||
[this](const manager::events::DocumentReparsed& event) {
|
||||
PublishDiagnostics(event.item.uri, event.item.version, event.tree, event.item.text);
|
||||
PublishDiagnostics(
|
||||
event.item.uri, event.item.version, event.tree, event.item.text);
|
||||
});
|
||||
|
||||
event_bus.Subscribe<manager::events::DocumentClosed>(
|
||||
@@ -496,7 +457,6 @@ namespace lsp::core
|
||||
spdlog::warn("Failed to serialize diagnostics notification for {}", uri);
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(*json);
|
||||
}
|
||||
|
||||
@@ -517,28 +477,13 @@ namespace lsp::core
|
||||
spdlog::warn("Failed to serialize diagnostics clear notification for {}", uri);
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(*json);
|
||||
}
|
||||
|
||||
void LspServer::SendError(const protocol::RequestMessage& request, protocol::ErrorCodes code, const std::string& message)
|
||||
void LspServer::SendError(const protocol::RequestMessage& request,
|
||||
protocol::ErrorCodes code,
|
||||
std::string_view message)
|
||||
{
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
protocol::ResponseError error;
|
||||
error.code = static_cast<protocol::integer>(code);
|
||||
error.message = message;
|
||||
response.error = error;
|
||||
auto json = transform::Serialize(response);
|
||||
if (json)
|
||||
{
|
||||
SendMessage(*json);
|
||||
}
|
||||
SendMessage(BuildErrorResponseMessage(request, code, message));
|
||||
}
|
||||
|
||||
void LspServer::SendStateError(const protocol::RequestMessage& request)
|
||||
{
|
||||
SendError(request, protocol::ErrorCodes::ServerNotInitialized, "Server not initialized");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,13 +4,10 @@ export module lsp.provider.base.interface;
|
||||
|
||||
import std;
|
||||
|
||||
// Thin bridge to core dispatcher interfaces and aliases for backward compatibility.
|
||||
export import lsp.core.dispatcher;
|
||||
|
||||
export namespace lsp::provider
|
||||
{
|
||||
using ServerLifecycleEvent = lsp::core::ServerLifecycleEvent;
|
||||
using LifecycleCallback = lsp::core::LifecycleCallback;
|
||||
using ExecutionContext = lsp::core::ExecutionContext;
|
||||
using IProvider = lsp::core::IProvider;
|
||||
using IRequestProvider = lsp::core::IRequestProvider;
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
module;
|
||||
|
||||
|
||||
export module lsp.provider.cancel_request.cancel_request;
|
||||
import spdlog;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.protocol.types;
|
||||
import lsp.codec.facade;
|
||||
import lsp.provider.base.interface;
|
||||
|
||||
namespace transform = lsp::codec;
|
||||
|
||||
export namespace lsp::provider
|
||||
{
|
||||
class CancelRequest : public AutoRegisterProvider<CancelRequest, INotificationProvider>
|
||||
{
|
||||
public:
|
||||
static constexpr std::string_view kMethod = "$/cancelRequest";
|
||||
static constexpr std::string_view kProviderName = "CancelRequest";
|
||||
CancelRequest() = default;
|
||||
void HandleNotification(const protocol::NotificationMessage& notification, ExecutionContext& context) override;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
void CancelRequest::HandleNotification(const protocol::NotificationMessage& notification, ExecutionContext& context)
|
||||
{
|
||||
spdlog::debug("CancelRequestProvider received {}", notification.method);
|
||||
|
||||
auto params = transform::FromLSPAny.template operator()<protocol::CancelParams>(notification.params.value());
|
||||
std::string id_to_cancel = transform::debug::GetIdString(params.id);
|
||||
spdlog::debug("Processing cancel request for ID: {}", id_to_cancel);
|
||||
|
||||
auto& scheduler = context.GetScheduler();
|
||||
bool cancelled = scheduler.Cancel(id_to_cancel);
|
||||
spdlog::debug("Cancel request {} {}", id_to_cancel, cancelled ? "succeeded" : "not found");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
module;
|
||||
|
||||
|
||||
export module lsp.provider.exit.exit;
|
||||
import spdlog;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.provider.base.interface;
|
||||
import lsp.protocol.types;
|
||||
|
||||
export namespace lsp::provider
|
||||
{
|
||||
class Exit : public AutoRegisterProvider<Exit, INotificationProvider>
|
||||
{
|
||||
public:
|
||||
static constexpr std::string_view kMethod = "exit";
|
||||
static constexpr std::string_view kProviderName = "Exit";
|
||||
Exit() = default;
|
||||
|
||||
void HandleNotification(const protocol::NotificationMessage& notification, ExecutionContext& context) override;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
void Exit::HandleNotification(const protocol::NotificationMessage& notification, ExecutionContext& context)
|
||||
{
|
||||
spdlog::debug("Exit notification {}", notification.method);
|
||||
spdlog::info("Exit notification received");
|
||||
|
||||
// 触发生命周期事件
|
||||
context.TriggerLifecycleEvent(ServerLifecycleEvent::kShuttingDown);
|
||||
|
||||
// 给一些时间完成清理
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
context.TriggerLifecycleEvent(ServerLifecycleEvent::kShutdown);
|
||||
|
||||
std::exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,11 +60,7 @@ namespace lsp::provider
|
||||
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);
|
||||
throw std::runtime_error("Failed to serialize initialize response");
|
||||
return json.value();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import lsp.provider.base.registry;
|
||||
import lsp.provider.completion_item.resolve;
|
||||
import lsp.provider.initialize.initialize;
|
||||
import lsp.provider.initialized.initialized;
|
||||
import lsp.provider.shutdown.shutdown;
|
||||
import lsp.provider.text_document.definition;
|
||||
import lsp.provider.text_document.did_change;
|
||||
import lsp.provider.text_document.did_close;
|
||||
@@ -20,13 +19,11 @@ import lsp.provider.trace.set_trace;
|
||||
// Uncomment when re-enabling additional capabilities.
|
||||
// import lsp.provider.call_hierarchy.incoming_calls;
|
||||
// import lsp.provider.call_hierarchy.outgoing_calls;
|
||||
// import lsp.provider.cancel_request.cancel_request;
|
||||
// import lsp.provider.client.register_capability;
|
||||
// import lsp.provider.client.unregister_capability;
|
||||
// import lsp.provider.code_action.resolve;
|
||||
// import lsp.provider.code_lens.resolve;
|
||||
// import lsp.provider.document_link.resolve;
|
||||
// import lsp.provider.exit.exit;
|
||||
// import lsp.provider.inlay_hint.resolve;
|
||||
// import lsp.provider.telemetry.event;
|
||||
// import lsp.provider.text_document.code_action;
|
||||
@@ -94,7 +91,6 @@ export namespace lsp::provider
|
||||
completion_item::Resolve,
|
||||
Initialize,
|
||||
Initialized,
|
||||
Shutdown,
|
||||
text_document::Completion,
|
||||
text_document::Definition,
|
||||
text_document::DidChange,
|
||||
@@ -107,18 +103,15 @@ export namespace lsp::provider
|
||||
// using AllProviders = ProviderRegistry<
|
||||
// call_hierarchy::IncomingCalls,
|
||||
// call_hierarchy::OutgoingCalls,
|
||||
// CancelRequest,
|
||||
// client::RegisterCapability,
|
||||
// client::UnregisterCapability,
|
||||
// code_action::Resolve,
|
||||
// code_lens::Resolve,
|
||||
// completion_item::Resolve,
|
||||
// document_link::Resolve,
|
||||
// Exit,
|
||||
// Initialize,
|
||||
// Initialized,
|
||||
// inlay_hint::Resolve,
|
||||
// Shutdown,
|
||||
// telemetry::Event,
|
||||
// text_document::CodeAction,
|
||||
// text_document::CodeLens,
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
module;
|
||||
|
||||
|
||||
export module lsp.provider.shutdown.shutdown;
|
||||
import spdlog;
|
||||
|
||||
import std;
|
||||
|
||||
import lsp.protocol;
|
||||
import lsp.codec.facade;
|
||||
import lsp.provider.base.interface;
|
||||
|
||||
namespace transform = lsp::codec;
|
||||
|
||||
export namespace lsp::provider
|
||||
{
|
||||
class Shutdown : public AutoRegisterProvider<Shutdown, IRequestProvider>
|
||||
{
|
||||
public:
|
||||
static constexpr std::string_view kMethod = "shutdown";
|
||||
static constexpr std::string_view kProviderName = "Shutdown";
|
||||
Shutdown() = default;
|
||||
|
||||
std::string ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context) override;
|
||||
};
|
||||
}
|
||||
|
||||
namespace lsp::provider
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
std::string Shutdown::ProvideResponse(const protocol::RequestMessage& request, ExecutionContext& context)
|
||||
{
|
||||
spdlog::debug("ShutdownProvider: Providing response for method {}", request.method);
|
||||
|
||||
// 触发关闭事件
|
||||
context.TriggerLifecycleEvent(ServerLifecycleEvent::kShuttingDown);
|
||||
|
||||
context.GetManagerHub().Shutdown();
|
||||
|
||||
// 构建响应 - shutdown 返回 null
|
||||
protocol::ResponseMessage response;
|
||||
response.id = request.id;
|
||||
auto json = transform::Serialize(response);
|
||||
if (!json.has_value())
|
||||
return BuildErrorResponseMessage(request, protocol::ErrorCodes::InternalError, "Failed to serialize response");
|
||||
spdlog::info("Shutdown request processed successfully");
|
||||
return json.value();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user