lsp-server first commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
#include "./dispacther.hpp"
|
||||
|
||||
namespace lsp {
|
||||
|
||||
|
||||
void RequestDispatcher::RegisterProvider(const std::string& method, RequestProvider handler)
|
||||
{
|
||||
providers_[method] = std::move(handler);
|
||||
}
|
||||
|
||||
nlohmann::json RequestDispatcher::Dispatch(const LspRequest& request)
|
||||
{
|
||||
auto it = providers_.find(request.method);
|
||||
if (it != providers_.end()) {
|
||||
try
|
||||
{
|
||||
return it->second(request);
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
return HandleException(request, e.what());
|
||||
}
|
||||
}
|
||||
return HandleUnknownMethod(request);
|
||||
}
|
||||
|
||||
bool RequestDispatcher::SupportsMethod(const std::string& method) const
|
||||
{
|
||||
return providers_.find(method) != providers_.end();
|
||||
}
|
||||
|
||||
std::vector<std::string> RequestDispatcher::GetSupportedMethods() const
|
||||
{
|
||||
std::vector<std::string> methods;
|
||||
for (const auto& pair : providers_) {
|
||||
methods.push_back(pair.first);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
nlohmann::json RequestDispatcher::HandleUnknownMethod(const LspRequest& request)
|
||||
{
|
||||
nlohmann::json resp;
|
||||
resp["jsonrpc"] = "2.0";
|
||||
resp["id"] = request.id;
|
||||
resp["error"] = {
|
||||
{"code", -32601},
|
||||
{"message", "Method not found: " + request.method}
|
||||
};
|
||||
return resp;
|
||||
}
|
||||
|
||||
nlohmann::json RequestDispatcher::HandleException(const LspRequest& request, const std::string& error_message)
|
||||
{
|
||||
nlohmann::json resp;
|
||||
resp["jsonrpc"] = "2.0";
|
||||
resp["id"] = request.id;
|
||||
resp["error"] = {
|
||||
{"code", -32603}, // Internal error
|
||||
{"message", "Internal error: " + error_message}
|
||||
};
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "./lsp_types.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
|
||||
// 请求处理函数类型
|
||||
using RequestProvider = std::function<nlohmann::json(const LspRequest&)>;
|
||||
|
||||
class RequestDispatcher
|
||||
{
|
||||
public:
|
||||
RequestDispatcher() = default;
|
||||
void RegisterProvider(const std::string& method, RequestProvider provider); // 可选:重命名
|
||||
nlohmann::json Dispatch(const LspRequest& request);
|
||||
bool SupportsMethod(const std::string& method) const;
|
||||
std::vector<std::string> GetSupportedMethods() const;
|
||||
|
||||
private:
|
||||
nlohmann::json HandleUnknownMethod(const LspRequest& request);
|
||||
nlohmann::json HandleException(const LspRequest& request, const std::string& error_message);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, RequestProvider> providers_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "./logger.hpp"
|
||||
|
||||
namespace lsp::log
|
||||
{
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
if (file_stream_.is_open())
|
||||
file_stream_.close();
|
||||
}
|
||||
|
||||
Logger& Logger::Instance()
|
||||
{
|
||||
static Logger logger;
|
||||
return logger;
|
||||
}
|
||||
|
||||
void Logger::SetLevel(LogLevel level)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
level_ = level;
|
||||
}
|
||||
|
||||
void Logger::SetLogFile(const std::string& filename)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (file_stream_.is_open())
|
||||
file_stream_.close();
|
||||
file_stream_.open(filename, std::ios::app);
|
||||
use_file_ = file_stream_.is_open();
|
||||
}
|
||||
|
||||
void Logger::EnableStderr(bool enable)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
use_stderr_ = enable;
|
||||
}
|
||||
|
||||
const char* Logger::LevelToString(LogLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel::kOff:
|
||||
return "OFF";
|
||||
case LogLevel::kError:
|
||||
return "ERROR";
|
||||
case LogLevel::kWarn:
|
||||
return "WARN";
|
||||
case LogLevel::kInfo:
|
||||
return "INFO";
|
||||
case LogLevel::kDebug:
|
||||
return "DEBUG";
|
||||
case LogLevel::kVerbose:
|
||||
return "VERBOSE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
|
||||
namespace lsp::log
|
||||
{
|
||||
enum class LogLevel
|
||||
{
|
||||
kOff = 0,
|
||||
kError = 1,
|
||||
kWarn = 2,
|
||||
kInfo = 3,
|
||||
kDebug = 4,
|
||||
kVerbose = 5
|
||||
};
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static Logger& Instance();
|
||||
void SetLevel(LogLevel level);
|
||||
void SetLogFile(const std::string& filename);
|
||||
void EnableStderr(bool enable);
|
||||
|
||||
template<typename... Args>
|
||||
void log(LogLevel level, Args&&... args) {
|
||||
if (level > level_)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "[TSL-LSP:" << LevelToString(level) << "] ";
|
||||
(oss << ... << args);
|
||||
oss << std::endl;
|
||||
|
||||
std::string message = oss.str();
|
||||
|
||||
if (use_stderr_)
|
||||
{
|
||||
std::cerr << message;
|
||||
}
|
||||
|
||||
if (use_file_ && file_stream_.is_open())
|
||||
{
|
||||
file_stream_ << message;
|
||||
file_stream_.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
~Logger();
|
||||
Logger(const Logger&) = delete;
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
|
||||
const char* LevelToString(LogLevel level);
|
||||
|
||||
private:
|
||||
LogLevel level_;
|
||||
bool use_file_ = false;
|
||||
bool use_stderr_ = false;
|
||||
std::ofstream file_stream_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void Error(Args&&... args) {
|
||||
Logger::Instance().log(LogLevel::kError, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Warn(Args&&... args) {
|
||||
Logger::Instance().log(LogLevel::kWarn, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Info(Args&&... args) {
|
||||
Logger::Instance().log(LogLevel::kInfo, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Debug(Args&&... args) {
|
||||
Logger::Instance().log(LogLevel::kDebug, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void Verbose(Args&&... args) {
|
||||
Logger::Instance().log(LogLevel::kVerbose, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
// LSP请求结构
|
||||
struct LspRequest
|
||||
{
|
||||
std::string jsonrpc;
|
||||
std::string method;
|
||||
nlohmann::json params;
|
||||
nlohmann::json id;
|
||||
|
||||
LspRequest(const nlohmann::json& json) :
|
||||
jsonrpc(json.value("jsonrpc", "2.0")),
|
||||
method(json.value("method", "")),
|
||||
params(json.value("params", nlohmann::json::object())),
|
||||
id(json.value("id", nlohmann::json::array())) {}
|
||||
};
|
||||
|
||||
// 补全项类型枚举
|
||||
enum class CompletionItemKind
|
||||
{
|
||||
kText = 1,
|
||||
kMethod = 2,
|
||||
kFunction = 3,
|
||||
kConstructor = 4,
|
||||
kField = 5,
|
||||
kVariable = 6,
|
||||
kClass = 7,
|
||||
kInterface = 8,
|
||||
kModule = 9,
|
||||
kProperty = 10,
|
||||
kUnit = 11,
|
||||
kValue = 12,
|
||||
kEnum = 13,
|
||||
kKeyword = 14,
|
||||
kSnippet = 15,
|
||||
kColor = 16,
|
||||
kFile = 17,
|
||||
kReference = 18,
|
||||
kFolder = 19,
|
||||
kEnumMember = 20,
|
||||
kConstant = 21,
|
||||
kStruct = 22,
|
||||
kEvent = 23,
|
||||
kOperator = 24,
|
||||
kTypeParameter = 25
|
||||
};
|
||||
|
||||
// 补全项目
|
||||
struct CompletionItem
|
||||
{
|
||||
std::string label;
|
||||
CompletionItemKind kind;
|
||||
std::optional<std::string> detail;
|
||||
std::optional<std::string> documentation;
|
||||
std::optional<std::string> insert_text;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include "../provider/base/provider_registry.hpp"
|
||||
#include "./server.hpp"
|
||||
#include "./logger.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
LspServer::LspServer()
|
||||
{
|
||||
providers::RegisterAllProviders(dispatcher_);
|
||||
log::Debug("LSP server initialized with providers.");
|
||||
}
|
||||
|
||||
void LspServer::Run()
|
||||
{
|
||||
log::Info("LSP server starting main loop...");
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::optional<std::string> message = ReadMessage();
|
||||
if (!message) continue;
|
||||
nlohmann::json response = HandleRequest(*message);
|
||||
if (!response.empty())
|
||||
SendResponse(response);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
log::Error("Error processing message: ", e.what());
|
||||
}
|
||||
}
|
||||
log::Info("LSP server main loop ended");
|
||||
}
|
||||
|
||||
std::optional<std::string> LspServer::ReadMessage()
|
||||
{
|
||||
std::string line;
|
||||
size_t content_length = 0;
|
||||
|
||||
// 读取 LSP Header
|
||||
while (std::getline(std::cin, line))
|
||||
{
|
||||
log::Verbose("Received header line: ", line);
|
||||
|
||||
// 去掉尾部 \r
|
||||
if (!line.empty() && line.back() == '\r')
|
||||
line.pop_back();
|
||||
if (line.empty())
|
||||
break;
|
||||
// 查找 Content-Length
|
||||
if (line.find("Content-Length:") == 0)
|
||||
{
|
||||
std::string length_str = line.substr(15); // 跳过 "Content-Length:"
|
||||
size_t start = length_str.find_first_not_of(" ");
|
||||
if (start != std::string::npos)
|
||||
{
|
||||
length_str = length_str.substr(start);
|
||||
try
|
||||
{
|
||||
content_length = std::stoul(length_str);
|
||||
log::Verbose("Content-Length: ", content_length);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::Error("Failed to parse Content-Length: ", e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (content_length == 0)
|
||||
{
|
||||
log::Warn("No Content-Length found in header");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 读取内容体
|
||||
std::string body(content_length, '\0');
|
||||
std::cin.read(&body[0], content_length);
|
||||
|
||||
log::Verbose("Message body: ", body);
|
||||
|
||||
if (std::cin.gcount() != static_cast<std::streamsize>(content_length))
|
||||
{
|
||||
log::Error("Read incomplete message body, expected: ", content_length, ", got: ", std::cin.gcount());
|
||||
return std::nullopt;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
nlohmann::json LspServer::HandleRequest(const std::string& raw_request)
|
||||
{
|
||||
try
|
||||
{
|
||||
nlohmann::json json = nlohmann::json::parse(raw_request);
|
||||
LspRequest request(json);
|
||||
log::Debug("Processing method: ", request.method);
|
||||
|
||||
nlohmann::json response = dispatcher_.Dispatch(request);
|
||||
return response;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::Error("Failed to handle request: ", e.what());
|
||||
return nlohmann::json();
|
||||
}
|
||||
}
|
||||
|
||||
void LspServer::SendResponse(const nlohmann::json& response)
|
||||
{
|
||||
std::string response_str = response.dump();
|
||||
size_t byte_length = response_str.length();
|
||||
|
||||
// 调试:显示实际发送的原始内容
|
||||
log::Debug("Response length: ", byte_length);
|
||||
log::Debug("Raw response content: [", response_str, "]");
|
||||
|
||||
std::cout << "Content-Length: " << byte_length << "\r\n\r\n";
|
||||
std::cout << response_str;
|
||||
std::cout.flush();
|
||||
|
||||
log::Verbose("Response sent successfully");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "./dispacther.hpp"
|
||||
|
||||
namespace lsp
|
||||
{
|
||||
|
||||
class LspServer
|
||||
{
|
||||
public:
|
||||
LspServer();
|
||||
~LspServer() = default;
|
||||
void Run();
|
||||
|
||||
private:
|
||||
// 读取LSP消息
|
||||
std::optional<std::string> ReadMessage();
|
||||
// 处理LSP请求
|
||||
nlohmann::json HandleRequest(const std::string& raw_request);
|
||||
// 发送LSP响应
|
||||
void SendResponse(const nlohmann::json& response);
|
||||
|
||||
private:
|
||||
RequestDispatcher dispatcher_;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user