feat: support concurrency
This commit is contained in:
@@ -59,6 +59,7 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".so")
|
|||||||
find_package(glaze CONFIG REQUIRED)
|
find_package(glaze CONFIG REQUIRED)
|
||||||
find_package(spdlog CONFIG REQUIRED)
|
find_package(spdlog CONFIG REQUIRED)
|
||||||
find_package(fmt CONFIG REQUIRED)
|
find_package(fmt CONFIG REQUIRED)
|
||||||
|
find_package(Taskflow REQUIRED)
|
||||||
|
|
||||||
if(NOT TARGET spdlog::spdlog_header_only)
|
if(NOT TARGET spdlog::spdlog_header_only)
|
||||||
message(WARNING "spdlog header-only target not found, using shared library")
|
message(WARNING "spdlog header-only target not found, using shared library")
|
||||||
@@ -74,9 +75,11 @@ endif()
|
|||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/utils/args_parser.cpp
|
||||||
src/language/tsl_keywords.cpp
|
src/language/tsl_keywords.cpp
|
||||||
src/lsp/dispacther.cpp
|
src/lsp/dispacther.cpp
|
||||||
src/lsp/server.cpp
|
src/lsp/server.cpp
|
||||||
|
src/lsp/request_scheduler.cpp
|
||||||
src/provider/base/provider_registry.cpp
|
src/provider/base/provider_registry.cpp
|
||||||
src/provider/base/provider_interface.cpp
|
src/provider/base/provider_interface.cpp
|
||||||
src/provider/initialize/initialize_provider.cpp
|
src/provider/initialize/initialize_provider.cpp
|
||||||
@@ -84,6 +87,7 @@ set(SOURCES
|
|||||||
src/provider/text_document/did_open_provider.cpp
|
src/provider/text_document/did_open_provider.cpp
|
||||||
src/provider/text_document/did_change_provider.cpp
|
src/provider/text_document/did_change_provider.cpp
|
||||||
src/provider/text_document/completion_provider.cpp
|
src/provider/text_document/completion_provider.cpp
|
||||||
|
src/provider/shutdown/shutdown_provider.cpp
|
||||||
src/provider/trace/set_trace_provider.cpp)
|
src/provider/trace/set_trace_provider.cpp)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||||
@@ -93,8 +97,8 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
|||||||
FMT_HEADER_ONLY)
|
FMT_HEADER_ONLY)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
${PROJECT_NAME} PRIVATE glaze::glaze spdlog::spdlog_header_only
|
${PROJECT_NAME} PRIVATE glaze::glaze Taskflow::Taskflow
|
||||||
fmt::fmt-header-only)
|
spdlog::spdlog_header_only fmt::fmt-header-only)
|
||||||
|
|
||||||
# Linux 需要链接 pthread
|
# Linux 需要链接 pthread
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
|
|||||||
@@ -5,29 +5,51 @@
|
|||||||
|
|
||||||
namespace lsp
|
namespace lsp
|
||||||
{
|
{
|
||||||
void RequestDispatcher::RegisterProvider(const std::string& method, RequestProvider handler)
|
void RequestDispatcher::RegisterProvider(std::shared_ptr<providers::ILspProvider> provider)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
|
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
|
||||||
providers_[method] = std::move(handler);
|
std::string method = provider->GetMethod();
|
||||||
|
|
||||||
|
// 如果是生命周期感知的 Provider,设置回调
|
||||||
|
if (auto lifecycle_aware = std::dynamic_pointer_cast<providers::ILifecycleAwareProvider>(provider))
|
||||||
|
{
|
||||||
|
lifecycle_aware->SetLifecycleCallback(
|
||||||
|
[this](ServerLifecycleEvent event) {
|
||||||
|
NotifyAllLifecycleListeners(event);
|
||||||
|
});
|
||||||
|
spdlog::debug("Registered lifecycle-aware provider for method: {}", method);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spdlog::debug("Registered standard provider for method: {}", method);
|
||||||
|
}
|
||||||
|
providers_[method] = provider;
|
||||||
spdlog::debug("Registered provider for method: {}", method);
|
spdlog::debug("Registered provider for method: {}", method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestDispatcher::RegisterLifecycleCallback(LifecycleCallback callback)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||||
|
lifecycle_callbacks_.push_back(std::move(callback));
|
||||||
|
spdlog::debug("Registered lifecycle callback, total callbacks: {}", lifecycle_callbacks_.size());
|
||||||
|
}
|
||||||
|
|
||||||
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
|
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
|
||||||
auto it = providers_.find(request.method);
|
auto it = providers_.find(request.method);
|
||||||
if (it != providers_.end())
|
if (it != providers_.end())
|
||||||
{
|
{
|
||||||
RequestProvider provider = it->second;
|
auto provider = it->second;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return provider(request);
|
return provider->ProvideResponse(request);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
spdlog::error("Provider error for method {}: {}", request.method, e.what());
|
spdlog::error("Provider error for method {}: {}", request.method, e.what());
|
||||||
return HandleException(request, e.what());
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return HandleUnknownMethod(request);
|
return HandleUnknownMethod(request);
|
||||||
@@ -51,36 +73,52 @@ namespace lsp
|
|||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestDispatcher::NotifyAllLifecycleListeners(ServerLifecycleEvent event)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(callbacks_mutex_);
|
||||||
|
|
||||||
|
std::string event_name;
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case ServerLifecycleEvent::kInitializing:
|
||||||
|
event_name = "Initializing";
|
||||||
|
break;
|
||||||
|
case ServerLifecycleEvent::kInitialized:
|
||||||
|
event_name = "Initialized";
|
||||||
|
break;
|
||||||
|
case ServerLifecycleEvent::kInitializeFailed:
|
||||||
|
event_name = "InitializeFailed";
|
||||||
|
break;
|
||||||
|
case ServerLifecycleEvent::kShuttingDown:
|
||||||
|
event_name = "ShuttingDown";
|
||||||
|
break;
|
||||||
|
case ServerLifecycleEvent::kShutdown:
|
||||||
|
event_name = "Shutdown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::info("Lifecycle event: {}", event_name);
|
||||||
|
|
||||||
|
for (const auto& callback : lifecycle_callbacks_)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
spdlog::error("Lifecycle callback error: {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string RequestDispatcher::HandleUnknownMethod(const protocol::RequestMessage& request)
|
std::string RequestDispatcher::HandleUnknownMethod(const protocol::RequestMessage& request)
|
||||||
{
|
{
|
||||||
return BuildErrorResponse(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RequestDispatcher::HandleException(const protocol::RequestMessage& request, const std::string& error_message)
|
std::string RequestDispatcher::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
||||||
{
|
{
|
||||||
return BuildErrorResponse(request, protocol::ErrorCode::kInternalError, "Internal error: " + error_message);
|
return providers::ILspProvider::BuildErrorResponseMessage(request, code, message);
|
||||||
}
|
|
||||||
|
|
||||||
std::string RequestDispatcher::BuildErrorResponse(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
|
||||||
{
|
|
||||||
protocol::ResponseMessage response;
|
|
||||||
response.jsonrpc = "2.0";
|
|
||||||
response.id = request.id;
|
|
||||||
|
|
||||||
protocol::ResponseError error;
|
|
||||||
error.code = code;
|
|
||||||
error.message = message;
|
|
||||||
response.error = error;
|
|
||||||
|
|
||||||
std::string json;
|
|
||||||
auto ec = glz::write_json(response, json);
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
spdlog::error("Failed to serialize error response: {}", glz::format_error(ec, json));
|
|
||||||
// 返回一个硬编码的错误响应作为后备
|
|
||||||
return R"({"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to serialize error response"}})";
|
|
||||||
}
|
|
||||||
|
|
||||||
return json;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <functional>
|
#include <memory>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include "../protocol/protocol.hpp"
|
#include "../protocol/protocol.hpp"
|
||||||
|
#include "../provider/base/provider_interface.hpp"
|
||||||
|
|
||||||
namespace lsp
|
namespace lsp
|
||||||
{
|
{
|
||||||
// 请求处理函数类型 - 返回序列化后的 JSON 字符串
|
|
||||||
using RequestProvider = std::function<std::string(const protocol::RequestMessage&)>;
|
using ServerLifecycleEvent = providers::ServerLifecycleEvent;
|
||||||
|
using LifecycleCallback = providers::LifecycleCallback;
|
||||||
|
|
||||||
class RequestDispatcher
|
class RequestDispatcher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RequestDispatcher() = default;
|
RequestDispatcher() = default;
|
||||||
|
|
||||||
void RegisterProvider(const std::string& method, RequestProvider provider);
|
void RegisterProvider(std::shared_ptr<providers::ILspProvider> provider);
|
||||||
|
void RegisterLifecycleCallback(LifecycleCallback callback);
|
||||||
std::string Dispatch(const protocol::RequestMessage& request);
|
std::string Dispatch(const protocol::RequestMessage& request);
|
||||||
bool SupportsMethod(const std::string& method) const;
|
bool SupportsMethod(const std::string& method) const;
|
||||||
std::vector<std::string> GetSupportedMethods() const;
|
std::vector<std::string> GetSupportedMethods() const;
|
||||||
|
|
||||||
|
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void NotifyAllLifecycleListeners(ServerLifecycleEvent event);
|
||||||
std::string HandleUnknownMethod(const protocol::RequestMessage& request);
|
std::string HandleUnknownMethod(const protocol::RequestMessage& request);
|
||||||
std::string HandleException(const protocol::RequestMessage& request, const std::string& error_message);
|
|
||||||
std::string BuildErrorResponse(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable std::shared_mutex providers_mutex_;
|
mutable std::shared_mutex providers_mutex_;
|
||||||
std::unordered_map<std::string, RequestProvider> providers_;
|
std::unordered_map<std::string, std::shared_ptr<providers::ILspProvider>> providers_;
|
||||||
|
|
||||||
|
std::mutex callbacks_mutex_;
|
||||||
|
std::vector<LifecycleCallback> lifecycle_callbacks_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,101 @@
|
|||||||
#include <mutex>
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
#include "./request_scheduler.hpp"
|
#include "./request_scheduler.hpp"
|
||||||
|
|
||||||
namespace lsp
|
namespace lsp
|
||||||
{
|
{
|
||||||
|
|
||||||
RequestScheduler::RequestScheduler(size_t concurrency) :
|
RequestScheduler::RequestScheduler(size_t concurrency) :
|
||||||
executor_(concurrency)
|
executor_(concurrency)
|
||||||
{
|
{
|
||||||
spdlog::info("RequestScheduler initialized with {} threads", concurrency);
|
spdlog::info("RequestScheduler initialized with {} threads", concurrency);
|
||||||
}
|
}
|
||||||
RequestScheduler::~RequestScheduler() = default;
|
|
||||||
|
|
||||||
void RequestScheduler::Sumbit(const std::string& request_id, TaskFunc task)
|
RequestScheduler::~RequestScheduler()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(task_mutex_);
|
WaitAll();
|
||||||
auto future = executor_.silent_async([this, request_id, task = std::move(task)] {
|
}
|
||||||
|
|
||||||
|
void RequestScheduler::Submit(const std::string& request_id, TaskFunc task)
|
||||||
|
{
|
||||||
|
auto context = std::make_shared<TaskContext>();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
|
// 取消旧任务
|
||||||
|
auto it = running_tasks_.find(request_id);
|
||||||
|
if (it != running_tasks_.end())
|
||||||
|
{
|
||||||
|
it->second->cancelled.store(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
running_tasks_[request_id] = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
executor_.async([this, request_id, task = std::move(task), context]() {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (context->cancelled.load())
|
||||||
|
{
|
||||||
|
spdlog::debug("Task {} was cancelled", request_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto result = task();
|
auto result = task();
|
||||||
if (result)
|
|
||||||
|
if (!context->cancelled.load() && result)
|
||||||
|
{
|
||||||
SendResponse(*result);
|
SendResponse(*result);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
spdlog::error("Task {} failed: {}", request_id, e.what());
|
spdlog::error("Task {} failed: {}", request_id, e.what());
|
||||||
}
|
}
|
||||||
std::lock_guard<std::mutex> lock(cancel_mutex_);
|
|
||||||
|
// 清理
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
running_tasks_.erase(request_id);
|
running_tasks_.erase(request_id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
running_tasks_[request_id] = std::move(future);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestScheduler::Cancel(const std::string& request_id)
|
bool RequestScheduler::Cancel(const std::string& request_id)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(cancel_mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
// Taskflow doesn't support preemptive cancel yet; you can set a flag here for cooperative cancel
|
|
||||||
spdlog::warn("Cancel not implemented for request_id = {} (requires cooperative cancel)", request_id);
|
auto it = running_tasks_.find(request_id);
|
||||||
|
if (it != running_tasks_.end())
|
||||||
|
{
|
||||||
|
it->second->cancelled.store(true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestScheduler::SetOutputFallback(std::function<void(const std::string&)> callback)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestScheduler::SetResponseCallback(ResponseCallback callback)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(output_mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
send_response_ = std::move(callback);
|
response_callback_ = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestScheduler::WaitAll()
|
||||||
|
{
|
||||||
|
executor_.wait_for_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestScheduler::SendResponse(const std::string& response)
|
void RequestScheduler::SendResponse(const std::string& response)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(output_mutex_);
|
ResponseCallback callback;
|
||||||
if (send_response_)
|
{
|
||||||
send_response_(response);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
callback = response_callback_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback)
|
||||||
|
callback(response);
|
||||||
else
|
else
|
||||||
spdlog::error("No response callback set! Unable to send: {}", response);
|
spdlog::error("No response callback set!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
// request_scheduler.hpp
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <mutex>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <taskflow/taskflow.hpp>
|
#include <taskflow/taskflow.hpp>
|
||||||
|
|
||||||
@@ -12,23 +14,28 @@ namespace lsp
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using TaskFunc = std::function<std::optional<std::string>()>;
|
using TaskFunc = std::function<std::optional<std::string>()>;
|
||||||
explicit RequestScheduler(size_t concurrency);
|
using ResponseCallback = std::function<void(const std::string&)>;
|
||||||
|
|
||||||
|
explicit RequestScheduler(size_t concurrency = std::thread::hardware_concurrency());
|
||||||
~RequestScheduler();
|
~RequestScheduler();
|
||||||
|
|
||||||
void Sumbit(const std::string& request_id, TaskFunc task);
|
void Submit(const std::string& request_id, TaskFunc task);
|
||||||
void Cancel(const std::string& request_id);
|
bool Cancel(const std::string& request_id);
|
||||||
void SetOutputFallback(std::function<void(const std::string&)> callback);
|
void SetResponseCallback(ResponseCallback callback);
|
||||||
|
void WaitAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct TaskContext
|
||||||
|
{
|
||||||
|
std::atomic<bool> cancelled{false};
|
||||||
|
};
|
||||||
|
|
||||||
void SendResponse(const std::string& response);
|
void SendResponse(const std::string& response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tf::Executor executor_;
|
tf::Executor executor_;
|
||||||
std::mutex task_mutex_;
|
mutable std::mutex mutex_;
|
||||||
std::mutex cancel_mutex_;
|
std::unordered_map<std::string, std::shared_ptr<TaskContext>> running_tasks_;
|
||||||
std::mutex output_mutex_;
|
ResponseCallback response_callback_;
|
||||||
|
|
||||||
std::unordered_map<std::string, tf::Future<void>> running_tasks_;
|
|
||||||
std::function<void(const std::string&)> send_response_;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+183
-52
@@ -1,3 +1,4 @@
|
|||||||
|
#include "request_scheduler.hpp"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
@@ -11,13 +12,29 @@
|
|||||||
|
|
||||||
namespace lsp
|
namespace lsp
|
||||||
{
|
{
|
||||||
LspServer::LspServer()
|
LspServer::LspServer(size_t concurrency) :
|
||||||
|
scheduler_(4)
|
||||||
{
|
{
|
||||||
|
spdlog::info("Initializing LSP server with {} worker threads", concurrency);
|
||||||
|
|
||||||
|
dispatcher_.RegisterLifecycleCallback(
|
||||||
|
[this](providers::ServerLifecycleEvent event) {
|
||||||
|
OnLifecycleEvent(event);
|
||||||
|
});
|
||||||
providers::RegisterAllProviders(dispatcher_);
|
providers::RegisterAllProviders(dispatcher_);
|
||||||
|
|
||||||
|
scheduler_.SetResponseCallback([this](const std::string& response) {
|
||||||
|
SendResponse(response);
|
||||||
|
});
|
||||||
|
|
||||||
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetSupportedMethods().size());
|
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetSupportedMethods().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
LspServer::~LspServer() = default;
|
LspServer::~LspServer()
|
||||||
|
{
|
||||||
|
is_shutting_down_ = true;
|
||||||
|
spdlog::info("LSP server shutting down...");
|
||||||
|
}
|
||||||
|
|
||||||
void LspServer::Run()
|
void LspServer::Run()
|
||||||
{
|
{
|
||||||
@@ -29,7 +46,7 @@ namespace lsp
|
|||||||
_setmode(_fileno(stdin), _O_BINARY);
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (true)
|
while (!is_shutting_down_)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -40,11 +57,7 @@ namespace lsp
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string response = HandleMessage(*message);
|
HandleMessage(*message);
|
||||||
if (!response.empty())
|
|
||||||
{
|
|
||||||
SendResponse(response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
@@ -106,9 +119,7 @@ namespace lsp
|
|||||||
|
|
||||||
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
|
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
|
||||||
{
|
{
|
||||||
spdlog::error("Read incomplete message body, expected: {}, got: {}",
|
spdlog::error("Read incomplete message body, expected: {}, got: {}", content_length, std::cin.gcount());
|
||||||
content_length,
|
|
||||||
std::cin.gcount());
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,122 +127,242 @@ namespace lsp
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LspServer::HandleMessage(const std::string& raw_message)
|
void LspServer::HandleMessage(const std::string& raw_message)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 首先尝试解析为通用的 JSON 来判断消息类型
|
// 解析 JSON 判断消息类型
|
||||||
glz::json_t doc;
|
glz::json_t doc;
|
||||||
auto error = glz::read_json(doc, raw_message);
|
auto error = glz::read_json(doc, raw_message);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
spdlog::error("Failed to parse message as JSON: {}",
|
spdlog::error("Failed to parse message as JSON: {}", glz::format_error(error, raw_message));
|
||||||
glz::format_error(error, raw_message));
|
return;
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& obj = doc.get<glz::json_t::object_t>();
|
auto& obj = doc.get<glz::json_t::object_t>();
|
||||||
|
|
||||||
// 判断消息类型
|
|
||||||
bool has_id = obj.contains("id");
|
|
||||||
bool has_method = obj.contains("method");
|
bool has_method = obj.contains("method");
|
||||||
bool has_result = obj.contains("result");
|
|
||||||
bool has_error = obj.contains("error");
|
|
||||||
|
|
||||||
if (has_method && has_id)
|
if (has_method)
|
||||||
{
|
{
|
||||||
// Request
|
bool has_id = obj.contains("id");
|
||||||
|
|
||||||
|
if (has_id)
|
||||||
|
{
|
||||||
|
// RequestMessage
|
||||||
protocol::RequestMessage request;
|
protocol::RequestMessage request;
|
||||||
error = glz::read_json(request, raw_message);
|
error = glz::read_json(request, raw_message);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
spdlog::error("Failed to parse request: {}",
|
spdlog::error("Failed to parse request: {}", glz::format_error(error, raw_message));
|
||||||
glz::format_error(error, raw_message));
|
return;
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
return HandleRequest(request);
|
HandleRequest(request);
|
||||||
}
|
}
|
||||||
else if (has_method && !has_id)
|
else
|
||||||
{
|
{
|
||||||
// Notification
|
// NotificationMessage
|
||||||
protocol::NotificationMessage notification;
|
protocol::NotificationMessage notification;
|
||||||
error = glz::read_json(notification, raw_message);
|
error = glz::read_json(notification, raw_message);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
spdlog::error("Failed to parse notification: {}",
|
spdlog::error("Failed to parse notification: {}", glz::format_error(error, raw_message));
|
||||||
glz::format_error(error, raw_message));
|
return;
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
return HandleNotification(notification);
|
HandleNotification(notification);
|
||||||
}
|
}
|
||||||
else if (has_id && (has_result || has_error))
|
}
|
||||||
|
else if (obj.contains("id") && (obj.contains("result") || obj.contains("error")))
|
||||||
{
|
{
|
||||||
// Response
|
// ResponseMessage
|
||||||
protocol::ResponseMessage response;
|
protocol::ResponseMessage response;
|
||||||
error = glz::read_json(response, raw_message);
|
error = glz::read_json(response, raw_message);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
spdlog::error("Failed to parse response: {}",
|
spdlog::error("Failed to parse response: {}",
|
||||||
glz::format_error(error, raw_message));
|
glz::format_error(error, raw_message));
|
||||||
return "";
|
return;
|
||||||
}
|
}
|
||||||
HandleResponse(response);
|
HandleResponse(response);
|
||||||
return ""; // 响应不需要回复
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
spdlog::error("Unknown message type");
|
spdlog::error("Unknown message type");
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
spdlog::error("Failed to handle message: {}", e.what());
|
spdlog::error("Failed to handle message: {}", e.what());
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LspServer::HandleRequest(const protocol::RequestMessage& request)
|
void LspServer::HandleRequest(const protocol::RequestMessage& request)
|
||||||
{
|
{
|
||||||
spdlog::debug("Processing request method: {}", request.method);
|
std::string request_id = transform::debug::GetIdString(request.id);
|
||||||
|
spdlog::debug("Processing request - id: {}, method: {}", request_id, request.method);
|
||||||
|
|
||||||
// 特殊处理 initialize 请求
|
// 检查是否可以处理请求
|
||||||
if (request.method == "initialize")
|
if (!CanProcessRequest(request.method))
|
||||||
{
|
{
|
||||||
is_initialized_ = true;
|
protocol::ErrorCode error_code;
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
if (!is_initialized_)
|
||||||
|
{
|
||||||
|
error_code = protocol::ErrorCode::kServerNotInitialized;
|
||||||
|
message = "Server not initialized";
|
||||||
|
}
|
||||||
|
else if (is_shutting_down_)
|
||||||
|
{
|
||||||
|
error_code = protocol::ErrorCode::kInvalidRequest;
|
||||||
|
message = "Server is shutting down, only 'exit' is allowed";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_code = protocol::ErrorCode::kInternalError;
|
||||||
|
message = "Request not allowed in current state";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendResponse(dispatcher_.BuildErrorResponseMessage(request, error_code, message));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 决定同步还是异步处理
|
||||||
|
if (RequiresSyncProcessing(request.method))
|
||||||
|
{
|
||||||
|
SendResponse(dispatcher_.Dispatch(request));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 异步处理
|
||||||
|
scheduler_.Submit(request_id, [this, request]() -> std::optional<std::string> {
|
||||||
|
if (is_shutting_down_)
|
||||||
|
{
|
||||||
|
spdlog::debug("Skipping request {} due to shutdown", request.method);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
return dispatcher_.Dispatch(request);
|
return dispatcher_.Dispatch(request);
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
spdlog::error("Request processing failed: {}", e.what());
|
||||||
|
return dispatcher_.BuildErrorResponseMessage( request, protocol::ErrorCode::kInternalError, e.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
spdlog::debug("Processing request method: {}", request.method);
|
||||||
|
}
|
||||||
|
|
||||||
std::string LspServer::HandleNotification(const protocol::NotificationMessage& notification)
|
void LspServer::HandleNotification(const protocol::NotificationMessage& notification)
|
||||||
{
|
{
|
||||||
spdlog::debug("Processing notification - method: {}", notification.method);
|
spdlog::debug("Processing notification - method: {}", notification.method);
|
||||||
|
|
||||||
// 特殊处理某些通知
|
// 处理 $/ 开头的通知
|
||||||
|
if (notification.method.starts_with("$/"))
|
||||||
|
{
|
||||||
|
if (notification.method == "$/cancelRequest")
|
||||||
|
{
|
||||||
|
HandleCancelRequest(notification);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spdlog::debug("Ignoring protocol-specific notification: {}", notification.method);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理标准通知
|
||||||
if (notification.method == "initialized")
|
if (notification.method == "initialized")
|
||||||
{
|
{
|
||||||
spdlog::info("Client initialized");
|
spdlog::info("Client acknowledged initialization");
|
||||||
}
|
}
|
||||||
else if (notification.method == "exit")
|
else if (notification.method == "exit")
|
||||||
{
|
{
|
||||||
spdlog::info("Exit notification received");
|
spdlog::info("Exit notification received");
|
||||||
|
is_shutting_down_ = true;
|
||||||
|
// 给一点时间让任务完成
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通知不需要响应
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LspServer::HandleResponse(const protocol::ResponseMessage& response)
|
void LspServer::HandleResponse(const protocol::ResponseMessage& response)
|
||||||
{
|
{
|
||||||
|
std::string id_str = transform::debug::GetIdString(response.id);
|
||||||
|
spdlog::debug("Received response - id: {}", id_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LspServer::OnLifecycleEvent(ServerLifecycleEvent event)
|
||||||
|
{
|
||||||
|
switch (event)
|
||||||
|
{
|
||||||
|
case ServerLifecycleEvent::kInitializing:
|
||||||
|
spdlog::info("Server initializing...");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerLifecycleEvent::kInitialized:
|
||||||
|
is_initialized_ = true;
|
||||||
|
spdlog::info("Server initialized successfully");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerLifecycleEvent::kInitializeFailed:
|
||||||
|
is_initialized_ = false;
|
||||||
|
spdlog::error("Server initialization failed");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerLifecycleEvent::kShuttingDown:
|
||||||
|
is_shutting_down_ = true;
|
||||||
|
spdlog::info("Server entering shutdown state");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerLifecycleEvent::kShutdown:
|
||||||
|
is_shutting_down_ = true;
|
||||||
|
spdlog::info("Server shutdown complete");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LspServer::RequiresSyncProcessing(const std::string& method) const
|
||||||
|
{
|
||||||
|
static const std::unordered_set<std::string> sync_methods = {
|
||||||
|
"initialize", // 必须同步完成
|
||||||
|
"shutdown" // 必须同步完成
|
||||||
|
};
|
||||||
|
|
||||||
|
return sync_methods.count(method) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LspServer::CanProcessRequest(const std::string& method) const
|
||||||
|
{
|
||||||
|
// 未初始化状态
|
||||||
|
if (!is_initialized_)
|
||||||
|
{
|
||||||
|
return method == "initialize" || method == "exit";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭中状态
|
||||||
|
if (is_shutting_down_)
|
||||||
|
{
|
||||||
|
return method == "exit";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正常状态 - 接受所有请求
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LspServer::HandleCancelRequest(const protocol::NotificationMessage& notification)
|
||||||
|
{
|
||||||
|
spdlog::info("Handle cancel request - method: {}", notification.method);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LspServer::SendResponse(const std::string& response)
|
void LspServer::SendResponse(const std::string& response)
|
||||||
{
|
{
|
||||||
size_t byte_length = response.length();
|
std::lock_guard<std::mutex> lock(output_mutex_);
|
||||||
|
|
||||||
// 构建完整消息
|
size_t byte_length = response.length();
|
||||||
std::string header = "Content-Length: " + std::to_string(byte_length) + "\r\n\r\n";
|
std::string header = "Content-Length: " + std::to_string(byte_length) + "\r\n\r\n";
|
||||||
|
|
||||||
// 发送 header 和 body
|
// 发送 header 和 body
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "./dispacther.hpp"
|
#include "./dispacther.hpp"
|
||||||
|
#include "./request_scheduler.hpp"
|
||||||
|
#include "../provider/base/provider_registry.hpp"
|
||||||
|
|
||||||
namespace lsp
|
namespace lsp
|
||||||
{
|
{
|
||||||
class LspServer
|
class LspServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LspServer();
|
LspServer(size_t concurrency = std::thread::hardware_concurrency());
|
||||||
~LspServer();
|
~LspServer();
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
@@ -17,18 +20,34 @@ namespace lsp
|
|||||||
std::optional<std::string> ReadMessage();
|
std::optional<std::string> ReadMessage();
|
||||||
|
|
||||||
// 处理LSP请求 - 返回序列化的响应或空字符串(对于通知)
|
// 处理LSP请求 - 返回序列化的响应或空字符串(对于通知)
|
||||||
std::string HandleMessage(const std::string& raw_message);
|
void HandleMessage(const std::string& raw_message);
|
||||||
|
|
||||||
// 发送LSP响应
|
// 发送LSP响应
|
||||||
void SendResponse(const std::string& response);
|
void SendResponse(const std::string& response);
|
||||||
|
|
||||||
// 处理不同类型的消息
|
// 处理不同类型的消息
|
||||||
std::string HandleRequest(const protocol::RequestMessage& request);
|
void HandleRequest(const protocol::RequestMessage& request);
|
||||||
std::string HandleNotification(const protocol::NotificationMessage& notification);
|
void HandleNotification(const protocol::NotificationMessage& notification);
|
||||||
void HandleResponse(const protocol::ResponseMessage& response);
|
void HandleResponse(const protocol::ResponseMessage& response);
|
||||||
|
|
||||||
|
// 生命周期事件处理
|
||||||
|
void OnLifecycleEvent(providers::ServerLifecycleEvent event);
|
||||||
|
|
||||||
|
// 判断是否需要同步处理
|
||||||
|
bool RequiresSyncProcessing(const std::string& method) const;
|
||||||
|
|
||||||
|
// 检查是否可以处理请求
|
||||||
|
bool CanProcessRequest(const std::string& method) const;
|
||||||
|
|
||||||
|
// 处理取消请求
|
||||||
|
void HandleCancelRequest(const protocol::NotificationMessage& notification);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RequestDispatcher dispatcher_;
|
RequestDispatcher dispatcher_;
|
||||||
bool is_initialized_ = false;
|
RequestScheduler scheduler_;
|
||||||
|
|
||||||
|
std::atomic<bool> is_initialized_ = false;
|
||||||
|
std::atomic<bool> is_shutting_down_ = false;
|
||||||
|
std::mutex output_mutex_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace lsp::protocol
|
|||||||
|
|
||||||
struct WorkDoneProgressOptions
|
struct WorkDoneProgressOptions
|
||||||
{
|
{
|
||||||
boolean workDoneProgress;
|
std::optional<boolean> workDoneProgress;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PartialResultParams
|
struct PartialResultParams
|
||||||
|
|||||||
@@ -87,6 +87,16 @@ namespace lsp::transform
|
|||||||
return "null";
|
return "null";
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string GetIdString(const std::variant<int, std::string>& id)
|
||||||
|
{
|
||||||
|
return 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;
|
||||||
|
}, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,20 +4,37 @@
|
|||||||
namespace lsp::providers
|
namespace lsp::providers
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string ILspProvider::BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message)
|
std::string ILspProvider::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
|
||||||
{
|
{
|
||||||
|
protocol::ResponseMessage response;
|
||||||
|
response.id = request.id;
|
||||||
|
|
||||||
protocol::ResponseError error;
|
protocol::ResponseError error;
|
||||||
error.code = code;
|
error.code = code;
|
||||||
error.message = message;
|
error.message = message;
|
||||||
|
response.error = error;
|
||||||
std::string json;
|
std::string json;
|
||||||
auto ec = glz::write_json(error, json);
|
auto ec = glz::write_json(error, json);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
spdlog::error("{}: Error", GetProviderName());
|
spdlog::error("Failed to serialize error response: {}", glz::format_error(ec, json));
|
||||||
std::string errmsg = "Failed to serialize [" + GetProviderName() + "] error response: " + glz::format_error(ec);
|
return R"({"jsonrpc":"2.0","id":null,"error":{"code":-32603,"message":"Failed to serialize error response"}})";
|
||||||
throw std::runtime_error(errmsg);
|
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ILifecycleAwareProvider::SetLifecycleCallback(LifecycleCallback callback)
|
||||||
|
{
|
||||||
|
lifecycle_callback_ = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILifecycleAwareProvider::NotifyLifecycleEvent(ServerLifecycleEvent event)
|
||||||
|
{
|
||||||
|
if (lifecycle_callback_)
|
||||||
|
{
|
||||||
|
lifecycle_callback_(event);
|
||||||
|
spdlog::debug("Provider {} triggered event: {}", GetProviderName(), static_cast<int>(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,16 @@
|
|||||||
|
|
||||||
namespace lsp::providers
|
namespace lsp::providers
|
||||||
{
|
{
|
||||||
|
enum class ServerLifecycleEvent
|
||||||
|
{
|
||||||
|
kInitializing,
|
||||||
|
kInitialized,
|
||||||
|
kInitializeFailed,
|
||||||
|
kShuttingDown,
|
||||||
|
kShutdown
|
||||||
|
};
|
||||||
|
|
||||||
|
using LifecycleCallback = std::function<void(ServerLifecycleEvent)>;
|
||||||
|
|
||||||
// LSP请求提供者接口基类
|
// LSP请求提供者接口基类
|
||||||
class ILspProvider
|
class ILspProvider
|
||||||
@@ -18,8 +28,24 @@ namespace lsp::providers
|
|||||||
// 获取提供者名称(用于日志和调试)
|
// 获取提供者名称(用于日志和调试)
|
||||||
virtual std::string GetProviderName() const = 0;
|
virtual std::string GetProviderName() const = 0;
|
||||||
|
|
||||||
|
static std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 生命周期感知的 Provider 接口
|
||||||
|
class ILifecycleAwareProvider : public ILspProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ILifecycleAwareProvider() = default;
|
||||||
|
|
||||||
|
// 设置生命周期回调
|
||||||
|
void SetLifecycleCallback(LifecycleCallback callback);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message);
|
// 触发生命周期事件
|
||||||
|
void NotifyLifecycleEvent(ServerLifecycleEvent event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
LifecycleCallback lifecycle_callback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "../text_document/did_change_provider.hpp"
|
#include "../text_document/did_change_provider.hpp"
|
||||||
#include "../text_document/completion_provider.hpp"
|
#include "../text_document/completion_provider.hpp"
|
||||||
#include "../trace/set_trace_provider.hpp"
|
#include "../trace/set_trace_provider.hpp"
|
||||||
|
#include "../shutdown/shutdown_provider.hpp"
|
||||||
|
|
||||||
namespace lsp::providers
|
namespace lsp::providers
|
||||||
{
|
{
|
||||||
@@ -20,6 +21,7 @@ namespace lsp::providers
|
|||||||
RegisterProvider<text_document::DidChangeProvider>(dispatcher);
|
RegisterProvider<text_document::DidChangeProvider>(dispatcher);
|
||||||
RegisterProvider<text_document::CompletionProvider>(dispatcher);
|
RegisterProvider<text_document::CompletionProvider>(dispatcher);
|
||||||
RegisterProvider<trace::SetTraceProvider>(dispatcher);
|
RegisterProvider<trace::SetTraceProvider>(dispatcher);
|
||||||
|
RegisterProvider<shutdown::ShutdownProvider>(dispatcher);
|
||||||
|
|
||||||
spdlog::info("Successfully registered {} LSP providers", dispatcher.GetSupportedMethods().size());
|
spdlog::info("Successfully registered {} LSP providers", dispatcher.GetSupportedMethods().size());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
namespace lsp::providers
|
namespace lsp::providers
|
||||||
{
|
{
|
||||||
|
|
||||||
// 模板函数:注册provider
|
// 模板函数:注册provider
|
||||||
template<typename ProviderClass>
|
template<typename ProviderClass>
|
||||||
void RegisterProvider(RequestDispatcher& dispatcher)
|
void RegisterProvider(RequestDispatcher& dispatcher)
|
||||||
@@ -14,14 +13,9 @@ namespace lsp::providers
|
|||||||
"Provider must inherit from ILspProvider");
|
"Provider must inherit from ILspProvider");
|
||||||
|
|
||||||
auto provider = std::make_shared<ProviderClass>();
|
auto provider = std::make_shared<ProviderClass>();
|
||||||
|
dispatcher.RegisterProvider(provider);
|
||||||
|
|
||||||
spdlog::info("Registering {} for method: {}", provider->GetProviderName(), provider->GetMethod());
|
spdlog::info("Registering {} for method: {}", provider->GetProviderName(), provider->GetMethod());
|
||||||
|
|
||||||
dispatcher.RegisterProvider(
|
|
||||||
provider->GetMethod(),
|
|
||||||
[provider](const protocol::RequestMessage& request) -> std::string {
|
|
||||||
return provider->ProvideResponse(request);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量注册provider
|
// 批量注册provider
|
||||||
|
|||||||
@@ -12,7 +12,13 @@ namespace lsp::providers::initialize
|
|||||||
response.result = transform::LSPAny(BuildInitializeResult());
|
response.result = transform::LSPAny(BuildInitializeResult());
|
||||||
std::string json;
|
std::string json;
|
||||||
auto ec = glz::write_json(response, json);
|
auto ec = glz::write_json(response, json);
|
||||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
if (ec)
|
||||||
|
{
|
||||||
|
NotifyLifecycleEvent(ServerLifecycleEvent::kInitializeFailed);
|
||||||
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error");
|
||||||
|
}
|
||||||
|
NotifyLifecycleEvent(ServerLifecycleEvent::kInitialized);
|
||||||
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string InitializeProvider::GetMethod() const
|
std::string InitializeProvider::GetMethod() const
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
namespace lsp::providers::initialize
|
namespace lsp::providers::initialize
|
||||||
{
|
{
|
||||||
using namespace lsp;
|
using namespace lsp;
|
||||||
class InitializeProvider : public ILspProvider
|
class InitializeProvider : public ILifecycleAwareProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitializeProvider() = default;
|
InitializeProvider() = default;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace lsp::providers::initialized
|
|||||||
std::string json;
|
std::string json;
|
||||||
glz::obj empty_obj{}; // glaze的对象类型
|
glz::obj empty_obj{}; // glaze的对象类型
|
||||||
auto ec = glz::write_json(empty_obj, json);
|
auto ec = glz::write_json(empty_obj, json);
|
||||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string InitializedProvider::GetMethod() const
|
std::string InitializedProvider::GetMethod() const
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace lsp::providers::initialized
|
namespace lsp::providers::initialized
|
||||||
{
|
{
|
||||||
class InitializedProvider : public ILspProvider
|
class InitializedProvider : public ILifecycleAwareProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitializedProvider() = default;
|
InitializedProvider() = default;
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include "./shutdown_provider.hpp"
|
||||||
|
#include "../../protocol/transform/facade.hpp"
|
||||||
|
|
||||||
|
namespace lsp::providers::shutdown
|
||||||
|
{
|
||||||
|
std::string ShutdownProvider::ProvideResponse(const protocol::RequestMessage& request)
|
||||||
|
{
|
||||||
|
spdlog::debug("ShutdownProvider: Providing response for method {}", request.method);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 触发关闭事件
|
||||||
|
NotifyLifecycleEvent(ServerLifecycleEvent::kShuttingDown);
|
||||||
|
|
||||||
|
// 构建响应 - shutdown 返回 null
|
||||||
|
protocol::ResponseMessage response;
|
||||||
|
response.id = request.id;
|
||||||
|
|
||||||
|
std::string json;
|
||||||
|
auto ec = glz::write_json(response, json);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::info("Shutdown request processed successfully");
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
spdlog::error("Shutdown request failed: {}", e.what());
|
||||||
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ShutdownProvider::GetMethod() const
|
||||||
|
{
|
||||||
|
return "shutdown";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ShutdownProvider::GetProviderName() const
|
||||||
|
{
|
||||||
|
return "ShutdownProvider";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../base/provider_interface.hpp"
|
||||||
|
|
||||||
|
namespace lsp::providers::shutdown
|
||||||
|
{
|
||||||
|
class ShutdownProvider : public ILifecycleAwareProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShutdownProvider() = default;
|
||||||
|
|
||||||
|
std::string ProvideResponse(const protocol::RequestMessage& request) override;
|
||||||
|
std::string GetMethod() const override;
|
||||||
|
std::string GetProviderName() const override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ namespace lsp::providers::text_document
|
|||||||
// 验证请求是否包含参数
|
// 验证请求是否包含参数
|
||||||
if (!request.params.has_value()) {
|
if (!request.params.has_value()) {
|
||||||
spdlog::warn("{}: Missing params in request", GetProviderName());
|
spdlog::warn("{}: Missing params in request", GetProviderName());
|
||||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Missing params");
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Missing params");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 variant 中提取参数
|
// 从 variant 中提取参数
|
||||||
@@ -28,17 +28,17 @@ namespace lsp::providers::text_document
|
|||||||
auto ec = glz::write_json(response, json);
|
auto ec = glz::write_json(response, json);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
spdlog::error("{}: Failed to serialize response: {}", GetProviderName(), glz::format_error(ec, json));
|
spdlog::error("{}: Failed to serialize response: {}", GetProviderName(), glz::format_error(ec, json));
|
||||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Failed to serialize response");
|
||||||
}
|
}
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
|
|
||||||
} catch (const transform::ConversionError& e) {
|
} catch (const transform::ConversionError& e) {
|
||||||
spdlog::error("{}: Failed to convert params: {}", GetProviderName(), e.what());
|
spdlog::error("{}: Failed to convert params: {}", GetProviderName(), e.what());
|
||||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Invalid completion params");
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Invalid completion params");
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::error("{}: Unexpected error: {}", GetProviderName(), e.what());
|
spdlog::error("{}: Unexpected error: {}", GetProviderName(), e.what());
|
||||||
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error");
|
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace lsp::providers::text_document
|
|||||||
std::string json;
|
std::string json;
|
||||||
glz::obj empty_obj{}; // glaze的对象类型
|
glz::obj empty_obj{}; // glaze的对象类型
|
||||||
auto ec = glz::write_json(empty_obj, json);
|
auto ec = glz::write_json(empty_obj, json);
|
||||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DidChangeProvider::GetMethod() const
|
std::string DidChangeProvider::GetMethod() const
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace lsp::providers::text_document
|
|||||||
std::string json;
|
std::string json;
|
||||||
glz::obj empty_obj{}; // glaze的对象类型
|
glz::obj empty_obj{}; // glaze的对象类型
|
||||||
auto ec = glz::write_json(empty_obj, json);
|
auto ec = glz::write_json(empty_obj, json);
|
||||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DidOpenProvider::GetMethod() const
|
std::string DidOpenProvider::GetMethod() const
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace lsp::providers::trace
|
|||||||
std::string json;
|
std::string json;
|
||||||
glz::obj empty_obj{}; // glaze的对象类型
|
glz::obj empty_obj{}; // glaze的对象类型
|
||||||
auto ec = glz::write_json(empty_obj, json);
|
auto ec = glz::write_json(empty_obj, json);
|
||||||
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
|
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SetTraceProvider::GetMethod() const
|
std::string SetTraceProvider::GetMethod() const
|
||||||
|
|||||||
Reference in New Issue
Block a user