This commit is contained in:
csh 2025-07-05 10:38:05 +08:00
parent 3cc1fccc81
commit 0c4619261d
39 changed files with 2085 additions and 875 deletions

View File

@ -77,9 +77,9 @@ set(SOURCES
src/main.cpp src/main.cpp
src/utils/args_parser.cpp src/utils/args_parser.cpp
src/language/tsl_keywords.cpp src/language/tsl_keywords.cpp
src/lsp/dispacther.cpp src/core/dispacther.cpp
src/lsp/server.cpp src/core/server.cpp
src/lsp/request_scheduler.cpp src/scheduler/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
@ -88,6 +88,8 @@ set(SOURCES
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/shutdown/shutdown_provider.cpp
src/provider/exit/exit_provider.cpp
src/provider/cancel_request/cancel_request_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})

View File

@ -0,0 +1,193 @@
#include <spdlog/spdlog.h>
#include <mutex>
#include "./dispacther.hpp"
#include "../protocol/transform/facade.hpp"
namespace lsp::core
{
void RequestDispatcher::SetRequestScheduler(scheduler::RequestScheduler* scheduler)
{
scheduler_ = scheduler;
spdlog::debug("RequestScheduler set in dispatcher");
}
void RequestDispatcher::RegisterRequestProvider(std::shared_ptr<providers::IRequestProvider> provider)
{
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
std::string method = provider->GetMethod();
providers_[method] = provider;
spdlog::info("Registered request provider '{}' for method: {}", provider->GetProviderName(), method);
}
void RequestDispatcher::RegisterNotificationProvider(std::shared_ptr<providers::INotificationProvider> provider)
{
std::unique_lock<std::shared_mutex> lock(notification_providers_mutex_);
std::string method = provider->GetMethod();
notification_providers_[method] = provider;
spdlog::info("Registered notification provider '{}' for method: {}", provider->GetProviderName(), 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");
}
std::string RequestDispatcher::Dispatch(const protocol::RequestMessage& request)
{
providers::ProviderContext context(
scheduler_,
[this](ServerLifecycleEvent event)
{
NotifyAllLifecycleListeners(event);
});
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
auto it = providers_.find(request.method);
if (it != providers_.end())
{
auto provider = it->second;
lock.unlock();
try
{
spdlog::debug("Dispatching request '{}' to provider '{}'", request.method, provider->GetProviderName());
return provider->ProvideResponse(request, context);
}
catch (const std::exception& e)
{
spdlog::error("Provider error for method {}: {}", request.method, e.what());
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
}
}
return HandleUnknownRequest(request);
}
void RequestDispatcher::Dispatch(const protocol::NotificationMessage& notification)
{
// 创建 provider context
providers::ProviderContext context(
scheduler_,
[this](ServerLifecycleEvent event)
{
NotifyAllLifecycleListeners(event);
});
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
// 先尝试精确匹配
auto it = notification_providers_.find(notification.method);
if (it != notification_providers_.end())
{
auto provider = it->second;
lock.unlock();
try
{
spdlog::debug("Dispatching notification '{}' to provider '{}'", notification.method, provider->GetProviderName());
provider->HandleNotification(notification, context);
return;
}
catch (const std::exception& e)
{
spdlog::error("Notification provider '{}' threw exception for method '{}': {}", provider->GetProviderName(), notification.method, e.what());
return;
}
}
HandleUnknownNotification(notification);
}
bool RequestDispatcher::SupportsRequest(const std::string& method) const
{
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
return providers_.find(method) != providers_.end();
}
std::vector<std::string> RequestDispatcher::GetSupportedRequests() const
{
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
std::vector<std::string> methods;
methods.reserve(providers_.size());
for (const auto& [method, _] : providers_)
methods.push_back(method);
return methods;
}
std::vector<std::string> RequestDispatcher::GetSupportedNotifications() const
{
std::shared_lock<std::shared_mutex> lock(notification_providers_mutex_);
std::vector<std::string> methods;
methods.reserve(notification_providers_.size());
for (const auto& [method, provider] : notification_providers_)
methods.push_back(method);
return methods;
}
std::vector<std::string> RequestDispatcher::GetAllSupportedMethods() const
{
auto requests = GetSupportedRequests();
auto notifications = GetSupportedNotifications();
// 合并两个列表
requests.insert(requests.end(), notifications.begin(), notifications.end());
return requests;
}
std::string RequestDispatcher::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
{
return providers::IRequestProvider::BuildErrorResponseMessage(request, code, message);
}
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::HandleUnknownRequest(const protocol::RequestMessage& request)
{
return BuildErrorResponseMessage(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
}
void RequestDispatcher::HandleUnknownNotification(const protocol::NotificationMessage& notification)
{
spdlog::debug("No handler found for notification: {}", notification.method);
// 通知没有响应,所以只记录日志
}
}

View File

@ -0,0 +1,56 @@
#pragma once
#include <memory>
#include <vector>
#include <shared_mutex>
#include "../protocol/protocol.hpp"
#include "../provider/base/provider_interface.hpp"
namespace lsp::core
{
using ServerLifecycleEvent = providers::ServerLifecycleEvent;
using LifecycleCallback = providers::LifecycleCallback;
class RequestDispatcher
{
public:
RequestDispatcher() = default;
~RequestDispatcher() = default;
void SetRequestScheduler(scheduler::RequestScheduler* scheduler);
void RegisterRequestProvider(std::shared_ptr<providers::IRequestProvider> provider);
void RegisterNotificationProvider(std::shared_ptr<providers::INotificationProvider> provider);
void RegisterLifecycleCallback(LifecycleCallback callback);
std::string Dispatch(const protocol::RequestMessage& request);
void Dispatch(const protocol::NotificationMessage& notification);
bool SupportsRequest(const std::string& method) const;
bool SupportsNotification(const std::string& method) const;
std::vector<std::string> GetSupportedRequests() const;
std::vector<std::string> GetSupportedNotifications() const;
std::vector<std::string> GetAllSupportedMethods() const;
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
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<providers::IRequestProvider>> providers_;
mutable std::shared_mutex notification_providers_mutex_;
std::unordered_map<std::string, std::shared_ptr<providers::INotificationProvider>> notification_providers_;
std::mutex callbacks_mutex_;
std::vector<LifecycleCallback> lifecycle_callbacks_;
scheduler::RequestScheduler* scheduler_ = nullptr;
};
}

View File

@ -1,4 +1,3 @@
#include "request_scheduler.hpp"
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
@ -8,15 +7,18 @@
#endif #endif
#include "../provider/base/provider_registry.hpp" #include "../provider/base/provider_registry.hpp"
#include "../protocol/transform/facade.hpp" #include "../protocol/transform/facade.hpp"
#include "../scheduler/request_scheduler.hpp"
#include "./server.hpp" #include "./server.hpp"
namespace lsp namespace lsp::core
{ {
LspServer::LspServer(size_t concurrency) : LspServer::LspServer(size_t concurrency) :
scheduler_(4) scheduler_(4)
{ {
spdlog::info("Initializing LSP server with {} worker threads", concurrency); spdlog::info("Initializing LSP server with {} worker threads", concurrency);
dispatcher_.SetRequestScheduler(&scheduler_);
dispatcher_.RegisterLifecycleCallback( dispatcher_.RegisterLifecycleCallback(
[this](providers::ServerLifecycleEvent event) { [this](providers::ServerLifecycleEvent event) {
OnLifecycleEvent(event); OnLifecycleEvent(event);
@ -27,7 +29,7 @@ namespace lsp
SendResponse(response); SendResponse(response);
}); });
spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetSupportedMethods().size()); spdlog::debug("LSP server initialized with {} providers.", dispatcher_.GetAllSupportedMethods().size());
} }
LspServer::~LspServer() LspServer::~LspServer()
@ -53,6 +55,11 @@ namespace lsp
std::optional<std::string> message = ReadMessage(); std::optional<std::string> message = ReadMessage();
if (!message) if (!message)
{ {
if (std::cin.eof())
{
spdlog::info("End of input stream, exiting main loop");
break; // EOF
}
spdlog::debug("No message received, continuing..."); spdlog::debug("No message received, continuing...");
continue; continue;
} }
@ -129,71 +136,14 @@ namespace lsp
void LspServer::HandleMessage(const std::string& raw_message) void LspServer::HandleMessage(const std::string& raw_message)
{ {
try if (auto request = transform::Deserialize<protocol::RequestMessage>(raw_message))
{ HandleRequest(*request);
// 解析 JSON 判断消息类型 else if (auto notification = transform::Deserialize<protocol::NotificationMessage>(raw_message))
glz::json_t doc; HandleNotification(*notification);
auto error = glz::read_json(doc, raw_message); else if (auto response = transform::Deserialize<protocol::ResponseMessage>(raw_message))
if (error) HandleResponse(*response);
{ else
spdlog::error("Failed to parse message as JSON: {}", glz::format_error(error, raw_message)); spdlog::error("Failed to deserialize message as any LSP message type");
return;
}
auto& obj = doc.get<glz::json_t::object_t>();
bool has_method = obj.contains("method");
if (has_method)
{
bool has_id = obj.contains("id");
if (has_id)
{
// RequestMessage
protocol::RequestMessage request;
error = glz::read_json(request, raw_message);
if (error)
{
spdlog::error("Failed to parse request: {}", glz::format_error(error, raw_message));
return;
}
HandleRequest(request);
}
else
{
// NotificationMessage
protocol::NotificationMessage notification;
error = glz::read_json(notification, raw_message);
if (error)
{
spdlog::error("Failed to parse notification: {}", glz::format_error(error, raw_message));
return;
}
HandleNotification(notification);
}
}
else if (obj.contains("id") && (obj.contains("result") || obj.contains("error")))
{
// ResponseMessage
protocol::ResponseMessage response;
error = glz::read_json(response, raw_message);
if (error)
{
spdlog::error("Failed to parse response: {}",
glz::format_error(error, raw_message));
return;
}
HandleResponse(response);
}
else
{
spdlog::error("Unknown message type");
}
}
catch (const std::exception& e)
{
spdlog::error("Failed to handle message: {}", e.what());
}
} }
void LspServer::HandleRequest(const protocol::RequestMessage& request) void LspServer::HandleRequest(const protocol::RequestMessage& request)
@ -204,88 +154,52 @@ namespace lsp
// 检查是否可以处理请求 // 检查是否可以处理请求
if (!CanProcessRequest(request.method)) if (!CanProcessRequest(request.method))
{ {
protocol::ErrorCode error_code; SendStateError(request);
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 else
{ {
// 异步处理 // 决定同步还是异步处理
scheduler_.Submit(request_id, [this, request]() -> std::optional<std::string> { if (RequiresSyncProcessing(request.method))
if (is_shutting_down_) {
{ SendResponse(dispatcher_.Dispatch(request));
spdlog::debug("Skipping request {} due to shutdown", request.method); }
return std::nullopt; 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 try
{ {
return dispatcher_.Dispatch(request); return dispatcher_.Dispatch(request);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
spdlog::error("Request processing failed: {}", e.what()); spdlog::error("Request processing failed: {}", e.what());
return dispatcher_.BuildErrorResponseMessage( request, protocol::ErrorCode::kInternalError, e.what()); return dispatcher_.BuildErrorResponseMessage( request, protocol::ErrorCode::kInternalError, e.what());
} }
}); });
}
spdlog::debug("Processing request method: {}", request.method);
} }
spdlog::debug("Processing request method: {}", request.method);
} }
void 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);
// 处理 $/ 开头的通知 try
if (notification.method.starts_with("$/"))
{ {
if (notification.method == "$/cancelRequest") dispatcher_.Dispatch(notification);
{
HandleCancelRequest(notification);
}
else
{
spdlog::debug("Ignoring protocol-specific notification: {}", notification.method);
}
return;
} }
catch (const std::exception& e)
// 处理标准通知
if (notification.method == "initialized")
{ {
spdlog::info("Client acknowledged initialization"); spdlog::error("Notification processing failed for '{}': {}", notification.method, e.what());
}
else if (notification.method == "exit")
{
spdlog::info("Exit notification received");
is_shutting_down_ = true;
// 给一点时间让任务完成
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::exit(0);
} }
} }
@ -339,15 +253,11 @@ namespace lsp
{ {
// 未初始化状态 // 未初始化状态
if (!is_initialized_) if (!is_initialized_)
{
return method == "initialize" || method == "exit"; return method == "initialize" || method == "exit";
}
// 关闭中状态 // 关闭中状态
if (is_shutting_down_) if (is_shutting_down_)
{
return method == "exit"; return method == "exit";
}
// 正常状态 - 接受所有请求 // 正常状态 - 接受所有请求
return true; return true;
@ -373,4 +283,21 @@ namespace lsp
spdlog::trace("Response sent - length: {}", byte_length); spdlog::trace("Response sent - length: {}", byte_length);
spdlog::trace("Response sent - body: {}", response); spdlog::trace("Response sent - body: {}", response);
} }
void LspServer::SendError(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
{
spdlog::warn("Sending error response - method: {}, code: {}, message: {}", request.method, static_cast<int>(code), message);
std::string error_response = dispatcher_.BuildErrorResponseMessage(request, code, message);
SendResponse(error_response);
}
void LspServer::SendStateError(const protocol::RequestMessage& request)
{
if (!is_initialized_)
SendError(request, protocol::ErrorCode::kServerNotInitialized, "Server not initialized");
else if (is_shutting_down_)
SendError(request, protocol::ErrorCode::kInvalidRequest, "Server is shutting down, only 'exit' is allowed");
else
SendError(request, protocol::ErrorCode::kInternalError, "Request not allowed in current state");
}
} }

View File

@ -3,10 +3,10 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include "./dispacther.hpp" #include "./dispacther.hpp"
#include "./request_scheduler.hpp" #include "../scheduler/request_scheduler.hpp"
#include "../provider/base/provider_registry.hpp" #include "../provider/base/provider_registry.hpp"
namespace lsp namespace lsp::core
{ {
class LspServer class LspServer
{ {
@ -42,9 +42,13 @@ namespace lsp
// 处理取消请求 // 处理取消请求
void HandleCancelRequest(const protocol::NotificationMessage& notification); void HandleCancelRequest(const protocol::NotificationMessage& notification);
private:
void SendError(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
void SendStateError(const protocol::RequestMessage& request);
private: private:
RequestDispatcher dispatcher_; RequestDispatcher dispatcher_;
RequestScheduler scheduler_; scheduler::RequestScheduler scheduler_;
std::atomic<bool> is_initialized_ = false; std::atomic<bool> is_initialized_ = false;
std::atomic<bool> is_shutting_down_ = false; std::atomic<bool> is_shutting_down_ = false;

View File

@ -1,124 +0,0 @@
#include <spdlog/spdlog.h>
#include <mutex>
#include "./dispacther.hpp"
#include "../protocol/transform/facade.hpp"
namespace lsp
{
void RequestDispatcher::RegisterProvider(std::shared_ptr<providers::ILspProvider> provider)
{
std::unique_lock<std::shared_mutex> lock(providers_mutex_);
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);
}
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::shared_lock<std::shared_mutex> lock(providers_mutex_);
auto it = providers_.find(request.method);
if (it != providers_.end())
{
auto provider = it->second;
lock.unlock();
try
{
return provider->ProvideResponse(request);
}
catch (const std::exception& e)
{
spdlog::error("Provider error for method {}: {}", request.method, e.what());
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, e.what());
}
}
return HandleUnknownMethod(request);
}
bool RequestDispatcher::SupportsMethod(const std::string& method) const
{
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
return providers_.find(method) != providers_.end();
}
std::vector<std::string> RequestDispatcher::GetSupportedMethods() const
{
std::shared_lock<std::shared_mutex> lock(providers_mutex_);
std::vector<std::string> methods;
methods.reserve(providers_.size());
for (const auto& [method, _] : providers_)
{
methods.push_back(method);
}
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)
{
return BuildErrorResponseMessage(request, protocol::ErrorCode::kMethodNotFound, "Method not found: " + request.method);
}
std::string RequestDispatcher::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
{
return providers::ILspProvider::BuildErrorResponseMessage(request, code, message);
}
}

View File

@ -1,38 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include <shared_mutex>
#include "../protocol/protocol.hpp"
#include "../provider/base/provider_interface.hpp"
namespace lsp
{
using ServerLifecycleEvent = providers::ServerLifecycleEvent;
using LifecycleCallback = providers::LifecycleCallback;
class RequestDispatcher
{
public:
RequestDispatcher() = default;
void RegisterProvider(std::shared_ptr<providers::ILspProvider> provider);
void RegisterLifecycleCallback(LifecycleCallback callback);
std::string Dispatch(const protocol::RequestMessage& request);
bool SupportsMethod(const std::string& method) const;
std::vector<std::string> GetSupportedMethods() const;
std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
private:
void NotifyAllLifecycleListeners(ServerLifecycleEvent event);
std::string HandleUnknownMethod(const protocol::RequestMessage& request);
private:
mutable std::shared_mutex providers_mutex_;
std::unordered_map<std::string, std::shared_ptr<providers::ILspProvider>> providers_;
std::mutex callbacks_mutex_;
std::vector<LifecycleCallback> lifecycle_callbacks_;
};
}

View File

@ -1,11 +1,9 @@
#include <iostream> #include <iostream>
#include <exception> #include <exception>
#include <memory>
#include <vector>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_sinks.h> #include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/sinks/basic_file_sink.h> #include <spdlog/sinks/basic_file_sink.h>
#include "./lsp/server.hpp" #include "./core/server.hpp"
#include "./utils/args_parser.hpp" #include "./utils/args_parser.hpp"
int main(int argc, char* argv[]) int main(int argc, char* argv[])
@ -23,7 +21,7 @@ int main(int argc, char* argv[])
try try
{ {
spdlog::info("TSL-LSP server starting..."); spdlog::info("TSL-LSP server starting...");
lsp::LspServer server(config.thread_count); lsp::core::LspServer server(config.thread_count);
server.Run(); server.Run();
} }
catch (const std::exception& e) catch (const std::exception& e)

View File

@ -5,6 +5,12 @@ namespace lsp::transform
{ {
// ===== 全局便利函数 ===== // ===== 全局便利函数 =====
template<typename T>
std::optional<T> Deserialize(const std::string& json);
template<typename T>
std::optional<std::string> Serialize(const T& obj);
// 基本类型 // 基本类型
template<typename T> template<typename T>
protocol::LSPAny LSPAny(const T& obj); protocol::LSPAny LSPAny(const T& obj);

View File

@ -3,6 +3,28 @@
namespace lsp::transform namespace lsp::transform
{ {
template<typename T>
inline std::optional<T> Deserialize(const std::string& json)
{
T obj;
auto ce = glz::read_json(obj, json);
if (ce)
return std::nullopt;
else
return obj;
}
template<typename T>
std::optional<std::string> Serialize(const T& obj)
{
std::string json;
auto ce = glz::write_json(obj, json);
if (ce)
return std::nullopt;
else
return json;
}
template<typename T> template<typename T>
inline protocol::LSPAny LSPAny(const T& obj) inline protocol::LSPAny LSPAny(const T& obj)
{ {

View File

@ -1,10 +1,9 @@
#include <spdlog/spdlog.h>
#include "./provider_interface.hpp" #include "./provider_interface.hpp"
namespace lsp::providers namespace lsp::providers
{ {
std::string ILspProvider::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message) std::string IRequestProvider::BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message)
{ {
protocol::ResponseMessage response; protocol::ResponseMessage response;
response.id = request.id; response.id = request.id;
@ -23,18 +22,4 @@ namespace lsp::providers
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));
}
}
} }

View File

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <string> #include <string>
#include <spdlog/spdlog.h>
#include "../../protocol/protocol.hpp" #include "../../protocol/protocol.hpp"
#include "../../scheduler/request_scheduler.hpp"
namespace lsp::providers namespace lsp::providers
{ {
@ -15,37 +17,57 @@ namespace lsp::providers
using LifecycleCallback = std::function<void(ServerLifecycleEvent)>; using LifecycleCallback = std::function<void(ServerLifecycleEvent)>;
class ProviderContext;
// LSP请求提供者接口基类 // LSP请求提供者接口基类
class ILspProvider class IProvider
{ {
public: public:
virtual ~ILspProvider() = default; virtual ~IProvider() = default;
// 处理LSP请求
virtual std::string ProvideResponse(const protocol::RequestMessage& request) = 0;
// 获取支持的LSP方法名 // 获取支持的LSP方法名
virtual std::string GetMethod() const = 0; virtual std::string GetMethod() const = 0;
// 获取提供者名称(用于日志和调试) // 获取提供者名称(用于日志和调试)
virtual std::string GetProviderName() const = 0; virtual std::string GetProviderName() const = 0;
};
// LSP 请求处理器接口
class IRequestProvider : public IProvider
{
public:
virtual ~IRequestProvider() = default;
// 处理LSP请求
virtual std::string ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context) = 0;
static std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message); static std::string BuildErrorResponseMessage(const protocol::RequestMessage& request, protocol::ErrorCode code, const std::string& message);
}; };
// 生命周期感知的 Provider 接口 // LSP 通知处理器接口
class ILifecycleAwareProvider : public ILspProvider class INotificationProvider : public IProvider
{ {
public: public:
virtual ~ILifecycleAwareProvider() = default; virtual ~INotificationProvider() = default;
// 设置生命周期回调 // 处理LSP通知
void SetLifecycleCallback(LifecycleCallback callback); virtual void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) = 0;
protected:
// 触发生命周期事件
void NotifyLifecycleEvent(ServerLifecycleEvent event);
private:
LifecycleCallback lifecycle_callback_;
}; };
class ProviderContext
{
public:
ProviderContext(scheduler::RequestScheduler* scheduler, LifecycleCallback lifecycle_callback) :
scheduler_(scheduler), lifecycle_callback_(lifecycle_callback) {}
scheduler::RequestScheduler* GetScheduler() const { return scheduler_; }
void TriggerLifecycleEvent(ServerLifecycleEvent event) const
{
if (lifecycle_callback_)
lifecycle_callback_(event);
}
private:
scheduler::RequestScheduler* scheduler_;
LifecycleCallback lifecycle_callback_;
};
} }

View File

@ -7,11 +7,13 @@
#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" #include "../shutdown/shutdown_provider.hpp"
#include "../cancel_request/cancel_request_provider.hpp"
#include "../exit/exit_provider.hpp"
namespace lsp::providers namespace lsp::providers
{ {
void RegisterAllProviders(RequestDispatcher& dispatcher) void RegisterAllProviders(core::RequestDispatcher& dispatcher)
{ {
spdlog::info("Registering LSP providers..."); spdlog::info("Registering LSP providers...");
@ -20,10 +22,12 @@ namespace lsp::providers
RegisterProvider<text_document::DidOpenProvider>(dispatcher); RegisterProvider<text_document::DidOpenProvider>(dispatcher);
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<set_trace::SetTraceProvider>(dispatcher);
RegisterProvider<shutdown::ShutdownProvider>(dispatcher); RegisterProvider<shutdown::ShutdownProvider>(dispatcher);
RegisterProvider<cancel_request::CancelRequestProvider>(dispatcher);
RegisterProvider<exit::ExitProvider>(dispatcher);
spdlog::info("Successfully registered {} LSP providers", dispatcher.GetSupportedMethods().size()); spdlog::info("Successfully registered {} LSP providers", dispatcher.GetAllSupportedMethods().size());
} }
} }

View File

@ -1,24 +1,32 @@
#pragma once #pragma once
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "../../lsp/dispacther.hpp" #include <type_traits>
#include "../../core/dispacther.hpp"
#include "./provider_interface.hpp" #include "./provider_interface.hpp"
namespace lsp::providers namespace lsp::providers
{ {
// 模板函数注册provider // 注册请求处理器的模板函数
template<typename ProviderClass> template<typename ProviderClass>
void RegisterProvider(RequestDispatcher& dispatcher) typename std::enable_if_t<std::is_base_of_v<IRequestProvider, ProviderClass>>
RegisterProvider(core::RequestDispatcher& dispatcher)
{ {
static_assert(std::is_base_of_v<ILspProvider, ProviderClass>,
"Provider must inherit from ILspProvider");
auto provider = std::make_shared<ProviderClass>(); auto provider = std::make_shared<ProviderClass>();
dispatcher.RegisterProvider(provider); dispatcher.RegisterRequestProvider(provider);
spdlog::info("Registered request provider '{}' for method: {}", provider->GetProviderName(), provider->GetMethod());
}
spdlog::info("Registering {} for method: {}", provider->GetProviderName(), provider->GetMethod()); // 注册通知处理器的模板函数
template<typename ProviderClass>
typename std::enable_if_t<std::is_base_of_v<INotificationProvider, ProviderClass>>
RegisterProvider(core::RequestDispatcher& dispatcher)
{
auto provider = std::make_shared<ProviderClass>();
dispatcher.RegisterNotificationProvider(provider);
spdlog::info("Registered notification provider '{}' for method: {}", provider->GetProviderName(), provider->GetMethod());
} }
// 批量注册provider // 批量注册provider
void RegisterAllProviders(RequestDispatcher& dispatcher); void RegisterAllProviders(core::RequestDispatcher& dispatcher);
} }

View File

@ -0,0 +1,34 @@
#include "./cancel_request_provider.hpp"
namespace lsp::providers::cancel_request
{
std::string CancelRequestProvider::GetMethod() const
{
return "$/cancelRequest";
}
std::string CancelRequestProvider::GetProviderName() const
{
return "CancelRequestProvider";
}
void CancelRequestProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
try
{
auto params = transform::As<protocol::CancelParams>(notification.params.value());
std::string id_to_cancel = transform::debug::GetIdString(params.id);
spdlog::info("Processing cancel request for ID: {}", id_to_cancel);
if (auto* scheduler = context.GetScheduler())
{
bool cancelled = scheduler->Cancel(id_to_cancel);
spdlog::info("Cancel request {} result: {}", id_to_cancel, cancelled ? "success" : "not found");
}
}
catch (const std::exception& e)
{
spdlog::error("Error handling cancel request: {}", e.what());
}
}
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <spdlog/spdlog.h>
#include "../base/provider_interface.hpp"
#include "../../scheduler/request_scheduler.hpp"
#include "../../protocol/transform/facade.hpp"
namespace lsp::providers::cancel_request
{
class CancelRequestProvider : public INotificationProvider
{
public:
std::string GetMethod() const override;
std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
};
}

View File

@ -0,0 +1,33 @@
#include "./exit_provider.hpp"
namespace lsp::providers::exit
{
std::string ExitProvider::GetMethod() const
{
return "exit";
}
std::string ExitProvider::GetProviderName() const
{
return "ExitProvider";
}
void ExitProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
// static_cast<void>(context);
spdlog::debug("ExitProvider: Providing response for method {}", 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);
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "../base/provider_interface.hpp"
namespace lsp::providers::exit
{
class ExitProvider : public INotificationProvider
{
public:
std::string GetMethod() const override;
std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
};
}

View File

@ -4,7 +4,17 @@
namespace lsp::providers::initialize namespace lsp::providers::initialize
{ {
std::string InitializeProvider::ProvideResponse(const protocol::RequestMessage& request) std::string InitializeProvider::GetMethod() const
{
return "initialize";
}
std::string InitializeProvider::GetProviderName() const
{
return "InitializeProvider";
}
std::string InitializeProvider::ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context)
{ {
spdlog::debug("InitializeProvider: Providing response for method {}", request.method); spdlog::debug("InitializeProvider: Providing response for method {}", request.method);
protocol::ResponseMessage response; protocol::ResponseMessage response;
@ -14,23 +24,13 @@ namespace lsp::providers::initialize
auto ec = glz::write_json(response, json); auto ec = glz::write_json(response, json);
if (ec) if (ec)
{ {
NotifyLifecycleEvent(ServerLifecycleEvent::kInitializeFailed); context.TriggerLifecycleEvent(ServerLifecycleEvent::kInitializeFailed);
return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error"); return BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error");
} }
NotifyLifecycleEvent(ServerLifecycleEvent::kInitialized); context.TriggerLifecycleEvent(ServerLifecycleEvent::kInitialized);
return json; return json;
} }
std::string InitializeProvider::GetMethod() const
{
return "initialize";
}
std::string InitializeProvider::GetProviderName() const
{
return "InitializeProvider";
}
protocol::InitializeResult InitializeProvider::BuildInitializeResult() protocol::InitializeResult InitializeProvider::BuildInitializeResult()
{ {
protocol::InitializeResult result; protocol::InitializeResult result;

View File

@ -4,11 +4,11 @@
namespace lsp::providers::initialize namespace lsp::providers::initialize
{ {
using namespace lsp; using namespace lsp;
class InitializeProvider : public ILifecycleAwareProvider class InitializeProvider : public IRequestProvider
{ {
public: public:
InitializeProvider() = default; InitializeProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override; std::string ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;

View File

@ -4,15 +4,6 @@
namespace lsp::providers::initialized namespace lsp::providers::initialized
{ {
std::string InitializedProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("InitializeProvider: Providing response for method {}", request.method);
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
}
std::string InitializedProvider::GetMethod() const std::string InitializedProvider::GetMethod() const
{ {
return "initialized"; return "initialized";
@ -23,4 +14,10 @@ namespace lsp::providers::initialized
return "InitializedProvider"; return "InitializedProvider";
} }
void InitializedProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
static_cast<void>(context); // 如果不需要上下文,可以忽略
spdlog::debug("InitializeProvider: Providing response for method {}", notification.method);
}
} }

View File

@ -3,12 +3,12 @@
namespace lsp::providers::initialized namespace lsp::providers::initialized
{ {
class InitializedProvider : public ILifecycleAwareProvider class InitializedProvider : public INotificationProvider
{ {
public: public:
InitializedProvider() = default; InitializedProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
}; };
} }

View File

@ -4,14 +4,24 @@
namespace lsp::providers::shutdown namespace lsp::providers::shutdown
{ {
std::string ShutdownProvider::ProvideResponse(const protocol::RequestMessage& request) std::string ShutdownProvider::GetMethod() const
{
return "shutdown";
}
std::string ShutdownProvider::GetProviderName() const
{
return "ShutdownProvider";
}
std::string ShutdownProvider::ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context)
{ {
spdlog::debug("ShutdownProvider: Providing response for method {}", request.method); spdlog::debug("ShutdownProvider: Providing response for method {}", request.method);
try try
{ {
// 触发关闭事件 // 触发关闭事件
NotifyLifecycleEvent(ServerLifecycleEvent::kShuttingDown); context.TriggerLifecycleEvent(ServerLifecycleEvent::kShuttingDown);
// 构建响应 - shutdown 返回 null // 构建响应 - shutdown 返回 null
protocol::ResponseMessage response; protocol::ResponseMessage response;
@ -34,13 +44,4 @@ namespace lsp::providers::shutdown
} }
} }
std::string ShutdownProvider::GetMethod() const
{
return "shutdown";
}
std::string ShutdownProvider::GetProviderName() const
{
return "ShutdownProvider";
}
} }

View File

@ -3,13 +3,13 @@
namespace lsp::providers::shutdown namespace lsp::providers::shutdown
{ {
class ShutdownProvider : public ILifecycleAwareProvider class ShutdownProvider : public IRequestProvider
{ {
public: public:
ShutdownProvider() = default; ShutdownProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
std::string ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context) override;
}; };
} }

View File

@ -4,13 +4,25 @@
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
std::string CompletionProvider::ProvideResponse(const protocol::RequestMessage& request) std::string CompletionProvider::GetMethod() const
{ {
return "textDocument/completion";
}
std::string CompletionProvider::GetProviderName() const
{
return "CompletionProvider";
}
std::string CompletionProvider::ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context)
{
static_cast<void>(context);
spdlog::debug("CompletionProvider: Providing response for method {}", request.method); spdlog::debug("CompletionProvider: Providing response for method {}", request.method);
try { try {
// 验证请求是否包含参数 // 验证请求是否包含参数
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 BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Missing params"); return BuildErrorResponseMessage(request, protocol::ErrorCode::kInvalidParams, "Missing params");
} }
@ -42,15 +54,6 @@ namespace lsp::providers::text_document
} }
} }
std::string CompletionProvider::GetMethod() const
{
return "textDocument/completion";
}
std::string CompletionProvider::GetProviderName() const
{
return "CompletionProvider";
}
protocol::CompletionList CompletionProvider::BuildCompletionResponse(const protocol::CompletionParams& params) protocol::CompletionList CompletionProvider::BuildCompletionResponse(const protocol::CompletionParams& params)
{ {

View File

@ -7,14 +7,14 @@
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
class CompletionProvider : public ILspProvider class CompletionProvider : public IRequestProvider
{ {
public: public:
CompletionProvider() = default; CompletionProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
std::string ProvideResponse(const protocol::RequestMessage& request, ProviderContext& context) override;
private: private:
// 构建完整的补全响应 // 构建完整的补全响应

View File

@ -1,19 +1,9 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "./did_change_provider.hpp" #include "./did_change_provider.hpp"
#include "./did_open_provider.hpp"
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
std::string DidChangeProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("DidChangeProvider: Providing response for method {}", request.method);
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
}
std::string DidChangeProvider::GetMethod() const std::string DidChangeProvider::GetMethod() const
{ {
return "textDocument/didChange"; return "textDocument/didChange";
@ -24,4 +14,10 @@ namespace lsp::providers::text_document
return "DidChangeProvider"; return "DidChangeProvider";
} }
void DidChangeProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
static_cast<void>(context);
spdlog::debug("DidChangeProvider: Providing response for method {}", notification.method);
}
} }

View File

@ -3,12 +3,12 @@
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
class DidChangeProvider : public ILspProvider class DidChangeProvider : public INotificationProvider
{ {
public: public:
DidChangeProvider() = default; DidChangeProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
}; };
} }

View File

@ -3,15 +3,6 @@
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
std::string DidOpenProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("DidOpenProvider: Providing response for method {}", request.method);
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
}
std::string DidOpenProvider::GetMethod() const std::string DidOpenProvider::GetMethod() const
{ {
return "textDocument/didOpen"; return "textDocument/didOpen";
@ -22,4 +13,10 @@ namespace lsp::providers::text_document
return "DidOpenProvider"; return "DidOpenProvider";
} }
void DidOpenProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
static_cast<void>(context);
spdlog::debug("DidOpenProvider: Providing response for method {}", notification.method);
}
} }

View File

@ -4,12 +4,12 @@
namespace lsp::providers::text_document namespace lsp::providers::text_document
{ {
class DidOpenProvider : public ILspProvider class DidOpenProvider : public INotificationProvider
{ {
public: public:
DidOpenProvider() = default; DidOpenProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
}; };
} }

View File

@ -1,18 +1,8 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "./set_trace_provider.hpp" #include "./set_trace_provider.hpp"
namespace lsp::providers::trace namespace lsp::providers::set_trace
{ {
std::string SetTraceProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("SetTraceProvider: Providing response for method {}", request.method);
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorResponseMessage(request, protocol::ErrorCode::kInternalError, "Internal error") : json;
}
std::string SetTraceProvider::GetMethod() const std::string SetTraceProvider::GetMethod() const
{ {
return "$/setTrace"; return "$/setTrace";
@ -23,4 +13,10 @@ namespace lsp::providers::trace
return "SetTraceProvider"; return "SetTraceProvider";
} }
void SetTraceProvider::HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context)
{
static_cast<void>(context);
spdlog::debug("SetTraceProvider: Providing response for method {}", notification.method);
}
} }

View File

@ -1,14 +1,14 @@
#pragma once #pragma once
#include "../base/provider_interface.hpp" #include "../base/provider_interface.hpp"
namespace lsp::providers::trace namespace lsp::providers::set_trace
{ {
class SetTraceProvider : public ILspProvider class SetTraceProvider : public INotificationProvider
{ {
public: public:
SetTraceProvider() = default; SetTraceProvider() = default;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override; std::string GetMethod() const override;
std::string GetProviderName() const override; std::string GetProviderName() const override;
void HandleNotification(const protocol::NotificationMessage& notification, ProviderContext& context) override;
}; };
} }

View File

@ -1,7 +1,7 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "./request_scheduler.hpp" #include "./request_scheduler.hpp"
namespace lsp namespace lsp::scheduler
{ {
RequestScheduler::RequestScheduler(size_t concurrency) : RequestScheduler::RequestScheduler(size_t concurrency) :
executor_(concurrency) executor_(concurrency)

View File

@ -8,7 +8,7 @@
#include <unordered_map> #include <unordered_map>
#include <taskflow/taskflow.hpp> #include <taskflow/taskflow.hpp>
namespace lsp namespace lsp::scheduler
{ {
class RequestScheduler class RequestScheduler
{ {

View File

@ -0,0 +1,821 @@
#include <algorithm>
#include "./document.hpp"
namespace lsp::services
{
// ===== Document 实现 =====
Document::Document(const protocol::TextDocumentItem& item) :
item_(item), last_modified_time_(std::chrono::system_clock::now())
{
UpdateInternalState();
spdlog::trace("Created document: {} (version {}, {} bytes)", item_.uri, item_.version, item_.text.length());
}
void Document::SetContent(int32_t newVersion, const std::string& newText)
{
item_.version = newVersion;
item_.text = newText;
is_dirty_ = true;
last_modified_time_ = std::chrono::system_clock::now();
UpdateInternalState();
spdlog::trace("Document {} updated to version {} ({} bytes)", item_.uri, item_.version, item_.text.length());
}
void Document::ApplyContentChange(protocol::integer version, const std::vector<protocol::TextDocumentContentChangeEvent>& changes)
{
// 应用所有变更
for (const auto& change : changes)
{
ApplyContentChange(change);
}
item_.version = version;
is_dirty_ = true;
last_modified_time_ = std::chrono::system_clock::now();
UpdateInternalState();
spdlog::trace("Document {} updated to version {} with {} changes", item_.uri, item_.version, changes.size());
}
void Document::ApplyContentChange(const protocol::TextDocumentContentChangeEvent& change)
{
// 增量更新
size_t startOffset = PositionToOffset(change.range.start);
size_t endOffset = PositionToOffset(change.range.end);
// 替换指定范围
item_.text = item_.text.substr(0, startOffset) + change.text + item_.text.substr(endOffset);
}
size_t Document::PositionToOffset(const protocol::Position& position) const
{
if (position.line >= lines_.size())
{
return item_.text.length();
}
size_t offset = line_offsets_[position.line];
// 根据编码计算字符偏移
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8)
{
// 直接使用字节偏移
offset += std::min(static_cast<size_t>(position.character), lines_[position.line].length());
}
else
{
// UTF-16 或 UTF-32
offset += CharacterToByteOffset(lines_[position.line], position.character);
}
return offset;
}
protocol::Position Document::OffsetToPosition(size_t offset) const
{
protocol::Position pos;
pos.line = 0;
pos.character = 0;
// 二分查找行号
auto it = std::upper_bound(line_offsets_.begin(), line_offsets_.end(), offset);
if (it != line_offsets_.begin())
{
--it;
pos.line = static_cast<int32_t>(std::distance(line_offsets_.begin(), it));
size_t lineOffset = *it;
size_t byteOffset = offset - lineOffset;
// 根据编码计算字符位置
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8)
{
pos.character = static_cast<int32_t>(byteOffset);
}
else
{
pos.character = ByteOffsetToCharacter(lines_[pos.line], byteOffset);
}
}
return pos;
}
std::string Document::GetTextInRange(const protocol::Range& range) const
{
size_t start = PositionToOffset(range.start);
size_t end = PositionToOffset(range.end);
if (start >= item_.text.length())
{
return "";
}
end = std::min(end, item_.text.length());
return item_.text.substr(start, end - start);
}
std::optional<char> Document::GetCharAt(const protocol::Position& position) const
{
if (position.line >= lines_.size())
{
return std::nullopt;
}
const std::string& line = lines_[position.line];
size_t byteOffset = CharacterToByteOffset(line, position.character);
if (byteOffset >= line.length())
{
return std::nullopt;
}
return line[byteOffset];
}
std::string Document::GetLine(size_t lineNumber) const
{
if (lineNumber < lines_.size())
{
return lines_[lineNumber];
}
return "";
}
std::string Document::GetLineAt(const protocol::Position& position) const
{
return GetLine(position.line);
}
std::string Document::GetWordAt(const protocol::Position& position) const
{
if (position.line >= lines_.size())
{
return "";
}
const std::string& line = lines_[position.line];
size_t bytePos = CharacterToByteOffset(line, position.character);
// 找到单词边界
size_t start = bytePos;
while (start > 0 && IsWordChar(line[start - 1]))
{
--start;
}
size_t end = bytePos;
while (end < line.length() && IsWordChar(line[end]))
{
++end;
}
return line.substr(start, end - start);
}
protocol::Range Document::GetWordRangeAt(const protocol::Position& position) const
{
if (position.line >= lines_.size())
{
return protocol::Range{ position, position };
}
const std::string& line = lines_[position.line];
size_t bytePos = CharacterToByteOffset(line, position.character);
// 找到单词边界
size_t start = bytePos;
while (start > 0 && IsWordChar(line[start - 1]))
{
--start;
}
size_t end = bytePos;
while (end < line.length() && IsWordChar(line[end]))
{
++end;
}
protocol::Range range;
range.start.line = position.line;
range.start.character = ByteOffsetToCharacter(line, start);
range.end.line = position.line;
range.end.character = ByteOffsetToCharacter(line, end);
return range;
}
void Document::UpdateInternalState()
{
UpdateLines();
UpdateLineOffsets();
}
void Document::UpdateLines()
{
lines_.clear();
size_t start = 0;
for (size_t i = 0; i < item_.text.length(); ++i)
{
if (item_.text[i] == '\n')
{
lines_.push_back(item_.text.substr(start, i - start));
start = i + 1;
}
else if (item_.text[i] == '\r')
{
if (i + 1 < item_.text.length() && item_.text[i + 1] == '\n')
{
lines_.push_back(item_.text.substr(start, i - start));
start = i + 2;
++i; // Skip \n
}
else
{
lines_.push_back(item_.text.substr(start, i - start));
start = i + 1;
}
}
}
// 添加最后一行
if (start <= item_.text.length())
{
lines_.push_back(item_.text.substr(start));
}
}
void Document::UpdateLineOffsets()
{
line_offsets_.clear();
line_offsets_.reserve(lines_.size() + 1);
size_t offset = 0;
line_offsets_.push_back(0);
for (size_t i = 0; i < item_.text.length(); ++i)
{
if (item_.text[i] == '\n')
{
line_offsets_.push_back(i + 1);
}
else if (item_.text[i] == '\r')
{
if (i + 1 < item_.text.length() && item_.text[i + 1] == '\n')
{
line_offsets_.push_back(i + 2);
++i;
}
else
{
line_offsets_.push_back(i + 1);
}
}
}
}
bool Document::IsWordChar(char c) const
{
return std::isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$';
}
size_t Document::CharacterToByteOffset(const std::string& line, int32_t character) const
{
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8)
{
return std::min(static_cast<size_t>(character), line.length());
}
// UTF-16 编码:需要正确计算
size_t byteOffset = 0;
int32_t charCount = 0;
while (byteOffset < line.length() && charCount < character)
{
unsigned char c = line[byteOffset];
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF16)
{
// UTF-16: 计算代码单元
if ((c & 0x80) == 0)
{
// ASCII
byteOffset += 1;
charCount += 1;
}
else if ((c & 0xE0) == 0xC0)
{
// 2字节UTF-8 -> 1个UTF-16单元
byteOffset += 2;
charCount += 1;
}
else if ((c & 0xF0) == 0xE0)
{
// 3字节UTF-8 -> 1个UTF-16单元
byteOffset += 3;
charCount += 1;
}
else if ((c & 0xF8) == 0xF0)
{
// 4字节UTF-8 -> 2个UTF-16单元代理对
byteOffset += 4;
charCount += 2;
}
else
{
byteOffset += 1; // 错误情况
}
}
else // UTF32
{
// UTF-32: 每个Unicode代码点算一个
if ((c & 0x80) == 0)
{
byteOffset += 1;
}
else if ((c & 0xE0) == 0xC0)
{
byteOffset += 2;
}
else if ((c & 0xF0) == 0xE0)
{
byteOffset += 3;
}
else if ((c & 0xF8) == 0xF0)
{
byteOffset += 4;
}
else
{
byteOffset += 1;
}
charCount += 1;
}
}
return byteOffset;
}
int32_t Document::ByteOffsetToCharacter(const std::string& line, size_t byteOffset) const
{
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF8)
{
return static_cast<int32_t>(byteOffset);
}
int32_t charCount = 0;
size_t pos = 0;
while (pos < byteOffset && pos < line.length())
{
unsigned char c = line[pos];
if (encoding_ == protocol::PositionEncodingKindLiterals::UTF16)
{
if ((c & 0x80) == 0)
{
pos += 1;
charCount += 1;
}
else if ((c & 0xE0) == 0xC0)
{
pos += 2;
charCount += 1;
}
else if ((c & 0xF0) == 0xE0)
{
pos += 3;
charCount += 1;
}
else if ((c & 0xF8) == 0xF0)
{
pos += 4;
charCount += 2; // 代理对
}
else
{
pos += 1;
charCount += 1;
}
}
else // UTF32
{
if ((c & 0x80) == 0)
{
pos += 1;
}
else if ((c & 0xE0) == 0xC0)
{
pos += 2;
}
else if ((c & 0xF0) == 0xE0)
{
pos += 3;
}
else if ((c & 0xF8) == 0xF0)
{
pos += 4;
}
else
{
pos += 1;
}
charCount += 1;
}
}
return charCount;
}
// ===== DocumentManager 实现 =====
void DocumentManager::DidOpenTextDocument(const protocol::DidOpenTextDocumentParams& params)
{
std::unique_lock lock(mutex_);
// 检查文档大小
if (config_.max_document_size > 0 &&
params.textDocument.text.length() > config_.max_document_size)
{
spdlog::error("Document {} exceeds maximum size ({} > {})",
params.textDocument.uri,
params.textDocument.text.length(),
config_.max_document_size);
return;
}
// 创建新文档
auto doc = std::make_shared<Document>(params.textDocument);
doc->SetEncoding(config_.default_encoding);
documents_[params.textDocument.uri] = doc;
spdlog::info("Opened document: {} (version {}, {} bytes, language: {})",
params.textDocument.uri,
params.textDocument.version,
params.textDocument.text.length(),
params.textDocument.languageId);
}
void DocumentManager::DidChangeTextDocument(const protocol::DidChangeTextDocumentParams& params)
{
std::unique_lock lock(mutex_);
auto it = documents_.find(params.textDocument.uri);
if (it == documents_.end())
{
spdlog::error("Attempt to change non-existent document: {}",
params.textDocument.uri);
return;
}
auto& doc = it->second;
// 版本检查
if (params.textDocument.version)
{
protocol::integer expectedVersion = params.textDocument.version;
if (expectedVersion <= doc->GetVersion())
{
spdlog::warn("Ignoring stale change for {}: version {} <= current {}",
params.textDocument.uri,
expectedVersion,
doc->GetVersion());
return;
}
}
// 应用变更
if (params.contentChanges.empty())
{
spdlog::warn("Empty content changes for document: {}", params.textDocument.uri);
return;
}
// 检查是全文还是增量
if (params.contentChanges.size() == 1)
{
// 全文更新
// doc->SetContent(params.textDocument.version(doc->GetVersion() + 1), params.contentChanges[0].text);
}
else
{
// 增量更新
// doc->ApplyContentChanges( params.textDocument.version(doc->GetVersion() + 1), params.contentChanges);
}
spdlog::debug("Changed document: {} to version {} ({} changes)", params.textDocument.uri, doc->GetVersion(), params.contentChanges.size());
}
void DocumentManager::DidCloseTextDocument(const protocol::DidCloseTextDocumentParams& params)
{
std::unique_lock lock(mutex_);
auto it = documents_.find(params.textDocument.uri);
if (it == documents_.end())
{
spdlog::warn("Attempt to close non-existent document: {}",
params.textDocument.uri);
return;
}
documents_.erase(it);
spdlog::info("Closed document: {}", params.textDocument.uri);
}
void DocumentManager::DidSaveTextDocument(const protocol::DidSaveTextDocumentParams& params)
{
std::shared_lock lock(mutex_);
auto it = documents_.find(params.textDocument.uri);
if (it == documents_.end())
{
spdlog::warn("Attempt to save non-existent document: {}",
params.textDocument.uri);
return;
}
it->second->SetDirty(false);
// 如果保存通知包含文本,可以验证同步状态
if (params.text.has_value())
{
if (params.text.value() != it->second->GetText())
{
spdlog::error("Document content mismatch on save for: {}", params.textDocument.uri);
}
}
spdlog::info("Saved document: {}", params.textDocument.uri);
}
std::shared_ptr<Document> DocumentManager::GetDocument(const std::string& uri) const
{
std::shared_lock lock(mutex_);
auto it = documents_.find(uri);
if (it != documents_.end())
{
return it->second;
}
return nullptr;
}
std::vector<std::string> DocumentManager::GetAllUris() const
{
std::shared_lock lock(mutex_);
std::vector<std::string> uris;
uris.reserve(documents_.size());
for (const auto& [uri, doc] : documents_)
{
uris.push_back(uri);
}
return uris;
}
std::vector<std::shared_ptr<Document>> DocumentManager::GetAllDocuments() const
{
std::shared_lock lock(mutex_);
std::vector<std::shared_ptr<Document>> docs;
docs.reserve(documents_.size());
for (const auto& [uri, doc] : documents_)
{
docs.push_back(doc);
}
return docs;
}
std::vector<std::shared_ptr<Document>> DocumentManager::GetDocumentsByLanguage(
const std::string& languageId) const
{
std::shared_lock lock(mutex_);
std::vector<std::shared_ptr<Document>> docs;
for (const auto& [uri, doc] : documents_)
{
if (doc->GetLanguageId() == languageId)
{
docs.push_back(doc);
}
}
return docs;
}
bool DocumentManager::HasDocument(const std::string& uri) const
{
std::shared_lock lock(mutex_);
return documents_.find(uri) != documents_.end();
}
size_t DocumentManager::GetDocumentCount() const
{
std::shared_lock lock(mutex_);
return documents_.size();
}
std::vector<std::string> DocumentManager::GetDirtyDocuments() const
{
std::shared_lock lock(mutex_);
std::vector<std::string> dirtyUris;
for (const auto& [uri, doc] : documents_)
{
if (doc->IsDirty())
{
dirtyUris.push_back(uri);
}
}
return dirtyUris;
}
std::string DocumentManager::ResolveUri(const std::string& uri) const
{
// 如果已经是绝对URI直接返回
if (utils::IsFileUri(uri))
{
return uri;
}
// 尝试相对于工作区文件夹解析
for (const auto& folder : workspace_folders_)
{
std::string folderPath = utils::UriToPath(folder.uri);
std::string resolvedPath = folderPath + "/" + uri;
// 检查文件是否存在(这里简化处理)
return utils::PathToUri(resolvedPath);
}
return uri;
}
// ===== 工具函数实现 =====
namespace utils
{
std::string NormalizeUri(const std::string& uri)
{
std::string normalized = uri;
// 确保使用正斜杠
std::replace(normalized.begin(), normalized.end(), '\\', '/');
// 移除重复的斜杠
auto newEnd = std::unique(normalized.begin(), normalized.end(), [](char a, char b) { return a == '/' && b == '/'; });
normalized.erase(newEnd, normalized.end());
return normalized;
}
std::string UriToPath(const std::string& uri)
{
if (uri.substr(0, 7) == "file://")
{
std::string path = uri.substr(7);
// Windows路径处理
#ifdef _WIN32
if (path.length() >= 3 && path[0] == '/' &&
std::isalpha(path[1]) && path[2] == ':')
{
path = path.substr(1);
}
#endif
return path;
}
return uri;
}
std::string PathToUri(const std::string& path)
{
std::string uri = "file://";
#ifdef _WIN32
// Windows路径
if (path.length() >= 2 && std::isalpha(path[0]) && path[1] == ':')
{
uri += "/";
}
#endif
uri += path;
return NormalizeUri(uri);
}
bool IsFileUri(const std::string& uri)
{
return uri.substr(0, 7) == "file://";
}
protocol::TextEdit CreateReplace(const protocol::Range& range, const std::string& newText)
{
protocol::TextEdit edit;
edit.range = range;
edit.newText = newText;
return edit;
}
protocol::TextEdit CreateInsert(const protocol::Position& position, const std::string& text)
{
return CreateReplace(protocol::Range{ position, position }, text);
}
protocol::TextEdit CreateDelete(const protocol::Range& range)
{
return CreateReplace(range, "");
}
bool IsPositionInRange(const protocol::Position& position, const protocol::Range& range)
{
if (position.line < range.start.line || position.line > range.end.line)
{
return false;
}
if (position.line == range.start.line && position.character < range.start.character)
{
return false;
}
if (position.line == range.end.line && position.character >= range.end.character)
{
return false;
}
return true;
}
bool IsRangeOverlapping(const protocol::Range& a, const protocol::Range& b)
{
return !(a.end.line < b.start.line ||
(a.end.line == b.start.line && a.end.character <= b.start.character) ||
b.end.line < a.start.line ||
(b.end.line == a.start.line && b.end.character <= a.start.character));
}
protocol::Range ExtendRange(const protocol::Range& range, int32_t lines)
{
protocol::Range extended = range;
extended.start.line = std::max(static_cast<std::int32_t>(0), static_cast<std::int32_t>(extended.start.line - lines));
extended.end.line += lines;
return extended;
}
std::string ApplyTextEdits(const std::string& text,
const std::vector<protocol::TextEdit>& edits)
{
if (edits.empty())
{
return text;
}
// 排序编辑(从后向前,避免偏移问题)
std::vector<protocol::TextEdit> sortedEdits = edits;
std::sort(sortedEdits.begin(), sortedEdits.end(), [](const protocol::TextEdit& a, const protocol::TextEdit& b) {
if (a.range.start.line != b.range.start.line)
{
return a.range.start.line > b.range.start.line;
}
return a.range.start.character > b.range.start.character;
});
// 创建临时文档来应用编辑
protocol::TextDocumentItem tempItem;
tempItem.uri = "temp://";
tempItem.languageId = "";
tempItem.version = 0;
tempItem.text = text;
Document tempDoc(tempItem);
std::string result = text;
for (const auto& edit : sortedEdits)
{
size_t start = tempDoc.PositionToOffset(edit.range.start);
size_t end = tempDoc.PositionToOffset(edit.range.end);
result = result.substr(0, start) + edit.newText + result.substr(end);
// 更新临时文档
tempDoc.SetContent(0, result);
}
return result;
}
}
}

View File

@ -0,0 +1,238 @@
#pragma once
#include <string>
#include <vector>
#include <optional>
#include <chrono>
#include <shared_mutex>
#include <spdlog/spdlog.h>
#include "../protocol/protocol.hpp"
namespace lsp::services
{
class Document
{
public:
Document(const protocol::TextDocumentItem& item);
const protocol::DocumentUri& GetUri() const { return item_.uri; }
const protocol::string& GetLanguageId() const { return item_.languageId; }
protocol::integer GetVersion() const { return item_.version; }
const protocol::string& GetText() const { return item_.text; }
const protocol::TextDocumentItem& GetItem() const { return item_; }
protocol::TextDocumentIdentifier GetIdentifier() const
{
return protocol::TextDocumentIdentifier{item_.uri};
}
protocol::VersionedTextDocumentIdentifier GetVersionedIdentifier() const
{
protocol::VersionedTextDocumentIdentifier id;
id.uri = item_.uri;
id.version = item_.version;
return id;
}
// ===== 位置和范围操作 =====
size_t PositionToOffset(const protocol::Position& position) const;
protocol::Position OffsetToPosition(size_t offset) const;
std::string GetTextInRange(const protocol::Range& range) const;
// 内容更新
void SetContent(protocol::integer version, const protocol::string& new_text);
void ApplyContentChange(protocol::integer version, const std::vector<protocol::TextDocumentContentChangeEvent>& changes);
// 获取指定位置的字符
std::optional<char> GetCharAt(const protocol::Position& position) const;
// ===== 行操作 =====
const std::vector<std::string>& GetLines() const { return lines_; }
size_t GetLineCount() const { return lines_.size(); }
std::string GetLine(size_t lineNumber) const;
std::string GetLineAt(const protocol::Position& position) const;
// ===== 单词和符号操作 =====
std::string GetWordAt(const protocol::Position& position) const;
protocol::Range GetWordRangeAt(const protocol::Position& position) const;
// ===== 实用方法 =====
// 创建一个Location
protocol::Location CreateLocation(const protocol::Range& range) const
{
return protocol::Location{item_.uri, range};
}
// 创建一个TextDocumentPositionParams
protocol::TextDocumentPositionParams CreatePositionParams(const protocol::Position& position) const
{
protocol::TextDocumentPositionParams params;
params.textDocument = GetIdentifier();
params.position = position;
return params;
}
// ===== 元数据 =====
// 文档是否被修改(相对于上次保存)
bool IsDirty() const { return is_dirty_; }
void SetDirty(bool dirty) { is_dirty_ = dirty; }
// 最后修改时间
std::chrono::system_clock::time_point GetLastModified() const { return last_modified_time_; }
void SetEncoding(protocol::PositionEncodingKind encoding) { encoding_ = encoding; }
protocol::PositionEncodingKind GetEncoding() const { return encoding_; }
private:
// 更新内部缓存
void UpdateInternalState();
void UpdateLines();
void UpdateLineOffsets();
// 辅助方法
bool IsWordChar(char c) const;
size_t CharacterToByteOffset(const std::string& line, std::int32_t character) const;
std::int32_t ByteOffsetToCharacter(const std::string& line, size_t byteOffset) const;
// 应用单个内容变更
void ApplyContentChange(const protocol::TextDocumentContentChangeEvent& change);
private:
protocol::TextDocumentItem item_;
// 缓存行的信息
std::vector<std::string> lines_;
std::vector<size_t> line_offsets_;
bool is_dirty_ = false;
std::chrono::system_clock::time_point last_modified_time_;
protocol::PositionEncodingKind encoding_ = protocol::PositionEncodingKindLiterals::UTF16;
};
/**
* - 使protocol类型作为接口
*/
class DocumentManager
{
public:
DocumentManager() = default;
~DocumentManager() = default;
// 禁止拷贝
DocumentManager(const DocumentManager&) = delete;
DocumentManager& operator=(const DocumentManager&) = delete;
// ===== 文档生命周期管理 - 直接使用protocol类型 =====
// 处理 textDocument/didOpen
void DidOpenTextDocument(const protocol::DidOpenTextDocumentParams& params);
// 处理 textDocument/didChange
void DidChangeTextDocument(const protocol::DidChangeTextDocumentParams& params);
// 处理 textDocument/didClose
void DidCloseTextDocument(const protocol::DidCloseTextDocumentParams& params);
// 处理 textDocument/didSave
void DidSaveTextDocument(const protocol::DidSaveTextDocumentParams& params);
// ===== 文档访问 - 支持多种查询方式 =====
// 通过URI获取
std::shared_ptr<Document> GetDocument(const std::string& uri) const;
// 通过标识符获取
std::shared_ptr<Document> GetDocument(const protocol::TextDocumentIdentifier& identifier) const
{
return GetDocument(identifier.uri);
}
// 通过版本化标识符获取
std::shared_ptr<Document> GetDocument(const protocol::VersionedTextDocumentIdentifier& identifier) const
{
auto doc = GetDocument(identifier.uri);
if (doc && identifier.version && doc->GetVersion() != identifier.version)
{
spdlog::warn("Version mismatch for {}: expected {}, got {}", identifier.uri, identifier.version, doc->GetVersion());
}
return doc;
}
// 通过TextDocumentPositionParams获取
std::shared_ptr<Document> GetDocument(const protocol::TextDocumentPositionParams& params) const
{
return GetDocument(params.textDocument);
}
// ===== 批量操作 =====
std::vector<std::string> GetAllUris() const;
std::vector<std::shared_ptr<Document>> GetAllDocuments() const;
std::vector<std::shared_ptr<Document>> GetDocumentsByLanguage(const std::string& languageId) const;
// ===== 查询 =====
bool HasDocument(const std::string& uri) const;
bool IsDocumentOpen(const protocol::TextDocumentIdentifier& identifier) const
{
return HasDocument(identifier.uri);
}
size_t GetDocumentCount() const;
// ===== 诊断支持 =====
// 获取需要诊断的文档(已修改的)
std::vector<std::string> GetDirtyDocuments() const;
// ===== 工作区支持 =====
// 设置工作区文件夹(用于相对路径解析)
void SetWorkspaceFolders(const std::vector<protocol::WorkspaceFolder>& folders)
{
workspace_folders_ = folders;
}
const std::vector<protocol::WorkspaceFolder>& GetWorkspaceFolders() const
{
return workspace_folders_;
}
// 解析相对URI
std::string ResolveUri(const std::string& uri) const;
// ===== 配置 =====
struct Configuration {
size_t max_document_size = 10 * 1024 * 1024; // 10MB
bool validate_utf8 = true;
protocol::PositionEncodingKind default_encoding = protocol::PositionEncodingKindLiterals::UTF16;
};
void SetConfiguration(const Configuration& config) { config_ = config; }
const Configuration& GetConfiguration() const { return config_; }
private:
mutable std::shared_mutex mutex_;
std::unordered_map<std::string, std::shared_ptr<Document>> documents_;
std::vector<protocol::WorkspaceFolder> workspace_folders_;
Configuration config_;
};
// ===== 工具函数 =====
namespace utils
{
// URI处理
std::string NormalizeUri(const std::string& uri);
std::string UriToPath(const std::string& uri);
std::string PathToUri(const std::string& path);
bool IsFileUri(const std::string& uri);
// 创建TextEdit
protocol::TextEdit CreateReplace(const protocol::Range& range, const std::string& newText);
protocol::TextEdit CreateInsert(const protocol::Position& position, const std::string& text);
protocol::TextEdit CreateDelete(const protocol::Range& range);
// 范围操作
bool IsPositionInRange(const protocol::Position& position, const protocol::Range& range);
bool IsRangeOverlapping(const protocol::Range& a, const protocol::Range& b);
protocol::Range ExtendRange(const protocol::Range& range, int32_t lines);
// 应用编辑
std::string ApplyTextEdits(const std::string& text, const std::vector<protocol::TextEdit>& edits);
}
}

View File

@ -103,7 +103,7 @@ namespace lsp::utils
<< "Usage: " << program_name << " [options]\n" << "Usage: " << program_name << " [options]\n"
<< "\n" << "\n"
<< "Options:\n" << "Options:\n"
<< " --help, -h Show this help message and exit\n" << " --help Show this help message and exit\n"
<< "\n" << "\n"
<< "Logging options:\n" << "Logging options:\n"
<< " --log=LEVEL Set log level (trace, debug, info, warn, error, off)\n" << " --log=LEVEL Set log level (trace, debug, info, warn, error, off)\n"