🐛 fix(core): enforce strict LSP lifecycle

This commit is contained in:
csh
2026-07-13 21:35:40 +08:00
parent 5edd4b3637
commit 06a0da5124
21 changed files with 555 additions and 664 deletions
+11 -4
View File
@@ -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;
}
+97 -139
View File
@@ -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
View File
@@ -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");
}
}
-47
View File
@@ -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();
}
-7
View File
@@ -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();
}
}