This commit is contained in:
csh
2025-07-02 14:29:54 +08:00
parent 65b38b7fec
commit dbc95ff098
61 changed files with 6673 additions and 617 deletions
@@ -0,0 +1,23 @@
#include <spdlog/spdlog.h>
#include "./provider_interface.hpp"
namespace lsp::providers
{
std::string ILspProvider::BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message)
{
protocol::ResponseError error;
error.code = code;
error.message = message;
std::string json;
auto ec = glz::write_json(error, json);
if (ec)
{
spdlog::error("{}: Error", GetProviderName());
std::string errmsg = "Failed to serialize [" + GetProviderName() + "] error response: " + glz::format_error(ec);
throw std::runtime_error(errmsg);
}
return json;
}
}
@@ -1,7 +1,6 @@
#pragma once
#include <string>
#include "../../lsp/lsp_types.hpp"
#include "../../protocol/protocol.hpp"
namespace lsp::providers
{
@@ -13,11 +12,14 @@ namespace lsp::providers
virtual ~ILspProvider() = default;
// 处理LSP请求
virtual nlohmann::json ProvideResponse(const LspRequest& request) = 0;
virtual std::string ProvideResponse(const protocol::RequestMessage& request) = 0;
// 获取支持的LSP方法名
virtual std::string GetMethod() const = 0;
// 获取提供者名称(用于日志和调试)
virtual std::string GetProviderName() const = 0;
protected:
std::string BuildErrorMessageResponse(protocol::ErrorCode code, const std::string& message);
};
}
@@ -19,7 +19,7 @@ namespace lsp::providers
dispatcher.RegisterProvider(
provider->GetMethod(),
[provider](const LspRequest& request) -> nlohmann::json {
[provider](const protocol::RequestMessage& request) -> std::string {
return provider->ProvideResponse(request);
});
}
@@ -1,55 +1,44 @@
#include <spdlog/spdlog.h>
#include "./initialize_provider.hpp"
#include "../../protocol/transform/facade.hpp"
namespace lsp::providers::initialize
{
nlohmann::json InitializeProvider::ProvideResponse(const LspRequest& request)
std::string InitializeProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("InitializeProvider: Providing response for method {}", request.method);
nlohmann::json response;
response["jsonrpc"] = "2.0";
response["id"] = request.id;
response["result"] = BuildInitializeResult();
return response;
protocol::ResponseMessage response;
response.id = request.id;
response.result = transform::LSPAny(BuildInitializeResult());
std::string json;
auto ec = glz::write_json(response, json);
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
}
inline std::string InitializeProvider::GetMethod() const
std::string InitializeProvider::GetMethod() const
{
return "initialize";
}
inline std::string InitializeProvider::GetProviderName() const
std::string InitializeProvider::GetProviderName() const
{
return "InitializeProvider";
}
nlohmann::json InitializeProvider::BuildInitializeResult()
protocol::InitializeResult InitializeProvider::BuildInitializeResult()
{
nlohmann::json result;
result["capabilities"] = BuildServerCapabilities();
result["serverInfo"] = BuildServerInfo();
protocol::InitializeResult result;
result.serverInfo.name = "TSL Language Server";
result.serverInfo.version = "1.0.0";
protocol::TextDocumentSyncOptions opts;
opts.openClose = true;
opts.change = protocol::TextDocumentSyncKind::kIncremental;
protocol::CompletionOptions completion_provider;
completion_provider.resolveProvider = false;
result.capabilities.textDocumentSync = opts;
result.capabilities.completionProvider = completion_provider;
return result;
}
nlohmann::json InitializeProvider::BuildServerCapabilities()
{
nlohmann::json capabilities;
capabilities["textDocumentSync"] = nlohmann::json();
capabilities["textDocumentSync"]["change"] = 2;
capabilities["textDocumentSync"]["openClose"] = true;
capabilities["textDocumentSync"]["save"] = true;
capabilities["completionProvider"] = nlohmann::json();
capabilities["completionProvider"]["resolveProvider"] = false;
return capabilities;
}
nlohmann::json InitializeProvider::BuildServerInfo()
{
nlohmann::json serverInfo;
serverInfo["name"] = "TSL Language Server";
serverInfo["version"] = "1.0.0";
return serverInfo;
}
}
@@ -1,20 +1,18 @@
#pragma once
#include "../base/provider_interface.hpp"
#include <nlohmann/json.hpp>
namespace lsp::providers::initialize
{
using namespace lsp;
class InitializeProvider : public ILspProvider
{
public:
InitializeProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
private:
nlohmann::json BuildServerCapabilities();
nlohmann::json BuildServerInfo();
nlohmann::json BuildInitializeResult();
protocol::InitializeResult BuildInitializeResult();
};
}
@@ -4,18 +4,21 @@
namespace lsp::providers::initialized
{
nlohmann::json InitializedProvider::ProvideResponse(const LspRequest& request)
std::string InitializedProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("InitializeProvider: Providing response for method {}", request.method);
return nlohmann::json();
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
}
inline std::string InitializedProvider::GetMethod() const
std::string InitializedProvider::GetMethod() const
{
return "initialized";
}
inline std::string InitializedProvider::GetProviderName() const
std::string InitializedProvider::GetProviderName() const
{
return "InitializedProvider";
}
@@ -7,7 +7,7 @@ namespace lsp::providers::initialized
{
public:
InitializedProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
};
@@ -1,211 +1,159 @@
#include <spdlog/spdlog.h>
#include "./completion_provider.hpp"
#include "../../protocol/transform/facade.hpp"
namespace lsp::providers::text_document
{
nlohmann::json CompletionProvider::ProvideResponse(const LspRequest& request)
std::string CompletionProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("CompletionProvider: Providing response for method {}", request.method);
try
{
nlohmann::json response = BuildCompletionResponse(request);
return response;
}
catch (const std::exception& e)
{
spdlog::error("{}: Error - ", GetProviderName(), e.what());
nlohmann::json errorResponse = CreateErrorResponse(request.id, -32603, e.what());
return errorResponse;
try {
// 验证请求是否包含参数
if (!request.params.has_value()) {
spdlog::warn("{}: Missing params in request", GetProviderName());
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Missing params");
}
// 从 variant 中提取参数
protocol::CompletionParams completion_params = transform::As<protocol::CompletionParams>(request.params.value());
protocol::CompletionList completion_list = BuildCompletionResponse(completion_params);
// 构建响应消息
protocol::ResponseMessage response;
response.id = request.id;
response.result = transform::LSPAny(completion_list);
std::string json;
auto ec = glz::write_json(response, json);
if (ec) {
spdlog::error("{}: Failed to serialize response: {}", GetProviderName(), glz::format_error(ec, json));
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Failed to serialize response");
}
return json;
} catch (const transform::ConversionError& e) {
spdlog::error("{}: Failed to convert params: {}", GetProviderName(), e.what());
return BuildErrorMessageResponse(protocol::ErrorCode::kInvalidParams, "Invalid completion params");
} catch (const std::exception& e) {
spdlog::error("{}: Unexpected error: {}", GetProviderName(), e.what());
return BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error");
}
}
inline std::string CompletionProvider::GetMethod() const
std::string CompletionProvider::GetMethod() const
{
return "textDocument/completion";
}
inline std::string CompletionProvider::GetProviderName() const
std::string CompletionProvider::GetProviderName() const
{
return "CompletionProvider";
}
nlohmann::json CompletionProvider::BuildCompletionResponse(const LspRequest& request)
protocol::CompletionList CompletionProvider::BuildCompletionResponse(const protocol::CompletionParams& params)
{
nlohmann::json response;
response["jsonrpc"] = "2.0";
response["id"] = request.id;
spdlog::trace("{}: Processing completion request for URI='{}', Position=({}, {})",
GetProviderName(),
params.textDocument.uri,
params.position.line,
params.position.character);
// 验证必要参数
if (!request.params.contains("textDocument") || !request.params.contains("position"))
// 获取补全前缀
std::string prefix = ExtractPrefix(params.textDocument, params.position);
// 如果提供了 context,可以使用其中的信息
if (params.context.has_value())
{
spdlog::warn("{}: Missing required parameters in request", GetProviderName());
// 返回空补全列表而非错误
response["result"] = BuildCompletionResult({});
return response;
spdlog::trace("{}: Trigger kind: {}", GetProviderName(), static_cast<int>(params.context->triggerKind));
if (params.context->triggerCharacter.has_value())
spdlog::trace("{}: Trigger character: '{}'", GetProviderName(), params.context->triggerCharacter.value());
}
// 提取参数
std::string uri = ExtractDocumentUri(request.params);
nlohmann::json position = ExtractPosition(request.params);
std::string prefix = ExtractPrefix(request.params);
spdlog::trace("{}: Processing completion request for URI='{}', Position={}, prefix='{}'", GetProviderName(), uri, position.dump(), prefix);
// 收集所有补全项
std::vector<CompletionItem> allItems;
std::vector<protocol::CompletionItem> allItems;
// 添加关键字补全
auto keywordItems = ProvideKeywordCompletions(prefix);
allItems.insert(allItems.end(), keywordItems.begin(), keywordItems.end());
// 添加上下文相关补全
auto contextualItems = ProvideContextualCompletions(uri, position, prefix);
auto contextualItems = ProvideContextualCompletions(params.textDocument, params.position, prefix);
allItems.insert(allItems.end(), contextualItems.begin(), contextualItems.end());
// 构建响应
response["result"] = BuildCompletionResult(allItems);
// 构建补全列表
protocol::CompletionList result;
result.isIncomplete = false; // 表示这是完整的补全列表
result.items = std::move(allItems);
spdlog::info("{}: Provided {}", GetProviderName(), allItems.size());
return response;
}
nlohmann::json CompletionProvider::BuildCompletionResult(const std::vector<CompletionItem>& items)
{
nlohmann::json result;
result["isIncomplete"] = false; // 表示这是完整的补全列表
result["items"] = nlohmann::json::array();
for (const auto& item : items)
result["items"].push_back(CompletionItemToJson(item));
spdlog::info("{}: Provided {} completion items", GetProviderName(), result.items.size());
return result;
}
std::string CompletionProvider::ExtractDocumentUri(const nlohmann::json& params)
std::string CompletionProvider::ExtractPrefix(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position)
{
if (params.contains("textDocument") && params["textDocument"].contains("uri"))
{
std::string uri = params["textDocument"]["uri"].get<std::string>();
spdlog::trace("ExtractDocumentUri: Found URI: ", uri);
return uri;
}
spdlog::warn("ExtractDocumentUri: No URI found in parameters");
// TODO: 实现从文档内容和位置计算前缀
// 这需要访问文档管理器来获取文档内容
// 现在返回空字符串
spdlog::trace("{}: ExtractPrefix not implemented, returning empty string", GetProviderName());
return "";
}
nlohmann::json CompletionProvider::ExtractPosition(const nlohmann::json& params)
std::vector<protocol::CompletionItem> CompletionProvider::ProvideKeywordCompletions(const std::string& prefix)
{
if (params.contains("position"))
{
nlohmann::json pos = params["position"];
spdlog::trace("ExtractPosition: Found position: ", pos.dump());
return pos;
}
// 返回默认位置
nlohmann::json defaultPos;
defaultPos["line"] = 0;
defaultPos["character"] = 0;
spdlog::warn("ExtractPosition: No position found in parameters, using default (0, 0)");
return defaultPos;
}
std::vector<protocol::CompletionItem> items;
std::string CompletionProvider::ExtractPrefix(const nlohmann::json& params)
{
// 方法1: 直接从参数中获取prefix
if (params.contains("prefix"))
{
std::string prefix = params["prefix"].get<std::string>();
spdlog::trace("ExtractPrefix: Found prefix form params: '", prefix, "'");
return prefix;
}
// 方法2: 从context中获取prefix
if (params.contains("context") && params["context"].contains("prefix"))
{
std::string prefix = params["context"]["prefix"].get<std::string>();
spdlog::trace("ExtractPrefix: Found prefix form params: '", prefix, "'");
return prefix;
}
// TODO: 理想情况下,应该从文档内容和位置计算前缀
// 这需要维护文档内容的状态
spdlog::trace("ExtractPrefix: No prefix found, returning empty string");
return "";
}
std::vector<CompletionItem> CompletionProvider::ProvideKeywordCompletions(const std::string& prefix)
{
std::vector<CompletionItem> items;
// 从tsl_keywords_获取补全项
// 从 tsl_keywords_ 获取补全项
auto tslItems = tsl_keywords_.GetCompletionItems(prefix);
for (const auto& tslItem : tslItems)
{
CompletionItem item;
for (const auto& tslItem : tslItems) {
protocol::CompletionItem item;
item.label = tslItem.label;
item.kind = CompletionItemKind::kKeyword; // LSP CompletionItemKind.Keyword
item.kind = protocol::CompletionItemKind::kKeyword;
item.detail = "TSL Keyword";
item.documentation = "TSL language keyword";
item.insert_text = tslItem.label;
// 创建文档内容
protocol::MarkupContent documentation;
documentation.kind = protocol::MarkupKindLiterals::PlainText;
documentation.value = "TSL language keyword";
item.documentation = documentation;
item.insertText = tslItem.label;
items.push_back(item);
}
spdlog::debug("ProvideKeywordCompletions: Found ", items.size(), " keyword completions");
spdlog::debug("{}: Found {} keyword completions", GetProviderName(), items.size());
return items;
}
std::vector<CompletionItem> CompletionProvider::ProvideContextualCompletions(
const std::string& uri,
const nlohmann::json& position,
const std::string& prefix)
std::vector<protocol::CompletionItem> CompletionProvider::ProvideContextualCompletions(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position, const std::string& prefix)
{
spdlog::debug("ProvideContextualCompletions: Processing contextual completions for URI: ", uri);
std::vector<CompletionItem> items;
spdlog::debug("{}: Processing contextual completions for URI: {}", GetProviderName(), textDocument.uri);
std::vector<protocol::CompletionItem> items;
// TODO: 基于上下文提供补全
// 这里可以添加:
// - 变量名补全
// - 函数名补全
// - 类型补全
// - 属性补全等
spdlog::debug("ProvideContextualCompletions: Found ", items.size(), " contextual completions");
// 示例:添加一个变量补全
if (!prefix.empty() && prefix[0] == '$')
{
protocol::CompletionItem varItem;
varItem.label = "$myVariable";
varItem.kind = protocol::CompletionItemKind::kVariable;
varItem.detail = "Local variable";
varItem.insertText = "$myVariable";
protocol::MarkupContent doc;
doc.kind = protocol::MarkupKindLiterals::Markdown;
doc.value = "Example variable completion";
varItem.documentation = doc;
items.push_back(varItem);
}
spdlog::debug("{}: Found {} contextual completions", GetProviderName(), items.size());
return items;
}
nlohmann::json CompletionProvider::CompletionItemToJson(const CompletionItem& item)
{
nlohmann::json json;
json["label"] = item.label;
json["kind"] = item.kind;
if (!item.detail)
json["detail"] = item.detail;
if (!item.documentation)
json["documentation"] = item.documentation;
if (!item.insert_text)
json["insertText"] = item.insert_text;
return json;
}
nlohmann::json CompletionProvider::CreateErrorResponse(const nlohmann::json& id, int code, const std::string& message)
{
nlohmann::json response;
response["jsonrpc"] = "2.0";
response["id"] = id;
nlohmann::json error;
error["code"] = code;
error["message"] = GetProviderName() + ": " + message;
response["error"] = error;
spdlog::error("CreateErrorResponse: Created error response with code {} and message {}", code, message);
return response;
}
}
@@ -2,7 +2,7 @@
#include <string>
#include <vector>
#include "../base/provider_interface.hpp"
#include "../../lsp/lsp_types.hpp"
#include "../../protocol/protocol.hpp"
#include "../../language/tsl_keywords.hpp"
namespace lsp::providers::text_document
@@ -12,36 +12,20 @@ namespace lsp::providers::text_document
public:
CompletionProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
private:
// 构建完整的补全响应
nlohmann::json BuildCompletionResponse(const LspRequest& request);
protocol::CompletionList BuildCompletionResponse(const protocol::CompletionParams& params);
// 构建补全结果
nlohmann::json BuildCompletionResult(const std::vector<CompletionItem>& items);
// 从请求中提取文档信息
std::string ExtractDocumentUri(const nlohmann::json& params);
nlohmann::json ExtractPosition(const nlohmann::json& params);
// 获取补全前缀
std::string ExtractPrefix(const nlohmann::json& params);
// 获取补全前缀(从文档内容和位置计算)
std::string ExtractPrefix(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position);
// 提供不同类型的补全
std::vector<CompletionItem> ProvideKeywordCompletions(const std::string& prefix);
std::vector<CompletionItem> ProvideContextualCompletions(
const std::string& uri,
const nlohmann::json& position,
const std::string& prefix);
// 将CompletionItem转换为JSON
nlohmann::json CompletionItemToJson(const CompletionItem& item);
// 创建错误响应
nlohmann::json CreateErrorResponse(const nlohmann::json& id, int code, const std::string& message);
std::vector<protocol::CompletionItem> ProvideKeywordCompletions(const std::string& prefix);
std::vector<protocol::CompletionItem> ProvideContextualCompletions(const protocol::TextDocumentIdentifier& textDocument, const protocol::Position& position, const std::string& prefix);
private:
tsl::TslKeywords tsl_keywords_;
@@ -5,59 +5,23 @@
namespace lsp::providers::text_document
{
nlohmann::json DidChangeProvider::ProvideResponse(const LspRequest& request)
std::string DidChangeProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("DidChangeProvider: Providing response for method {}", request.method);
try
{
auto params = request.params;
if (params.contains("textDocument") && params.contains("contentChanges"))
{
auto textDoc = params["textDocument"];
std::string uri = textDoc["uri"];
auto changes = params["contentChanges"];
ApplyContentChanges(uri, changes);
}
}
catch (const std::exception& e)
{
// 处理错误,但不返回错误响应,因为这是通知
}
// 通知不需要响应
return nlohmann::json();
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
}
inline std::string DidChangeProvider::GetMethod() const
std::string DidChangeProvider::GetMethod() const
{
return "textDocument/didChange";
}
inline std::string DidChangeProvider::GetProviderName() const
std::string DidChangeProvider::GetProviderName() const
{
return "DidChangeProvider";
}
void DidChangeProvider::ApplyContentChanges(const std::string& uri, const nlohmann::json& changes)
{
// 简化实现:假设是全文替换
for (const auto& change : changes)
{
if (change.contains("text"))
{
// 如果没有range,表示全文替换
if (!change.contains("range"))
{
DidOpenProvider::document_store[uri] = change["text"];
}
else
{
// 这里可以实现增量更新,现在简化为全文替换
DidOpenProvider::document_store[uri] = change["text"];
}
}
}
}
}
@@ -7,11 +7,8 @@ namespace lsp::providers::text_document
{
public:
DidChangeProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
private:
void ApplyContentChanges(const std::string& uri, const nlohmann::json& changes);
};
}
@@ -3,46 +3,23 @@
namespace lsp::providers::text_document
{
std::unordered_map<std::string, std::string> DidOpenProvider::document_store;
nlohmann::json DidOpenProvider::ProvideResponse(const LspRequest& request)
std::string DidOpenProvider::ProvideResponse(const protocol::RequestMessage& request)
{
spdlog::debug("DidOpenProvider: Providing response for method {}", request.method);
try
{
auto params = request.params;
if (params.contains("textDocument"))
{
auto textDoc = params["textDocument"];
std::string uri = textDoc["uri"];
std::string text = textDoc["text"];
// 存储文档内容
document_store[uri] = text;
}
}
catch (const std::exception& e)
{
// 处理错误,但不返回错误响应,因为这是通知
}
// 通知不需要响应
return nlohmann::json();
std::string json;
glz::obj empty_obj{}; // glaze的对象类型
auto ec = glz::write_json(empty_obj, json);
return ec ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
}
inline std::string DidOpenProvider::GetMethod() const
std::string DidOpenProvider::GetMethod() const
{
return "textDocument/didOpen";
}
inline std::string DidOpenProvider::GetProviderName() const
std::string DidOpenProvider::GetProviderName() const
{
return "DidOpenProvider";
}
std::string DidOpenProvider::GetDocumentContent(const std::string& uri)
{
auto it = document_store.find(uri);
return (it != document_store.end()) ? it->second : "";
}
}
@@ -8,14 +8,8 @@ namespace lsp::providers::text_document
{
public:
DidOpenProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
// 静态方法用于获取文档内容
static std::string GetDocumentContent(const std::string& uri);
public:
static std::unordered_map<std::string, std::string> document_store;
};
}
@@ -1,35 +1,24 @@
#include <spdlog/spdlog.h>
#include "./set_trace_provider.hpp"
namespace lsp::providers::trace
{
nlohmann::json SetTraceProvider::ProvideResponse(const LspRequest& request)
std::string SetTraceProvider::ProvideResponse(const protocol::RequestMessage& request)
{
try
{
auto params = request.params;
if (params.contains("value"))
{
std::string trace_value = params["value"];
// 这里可以设置跟踪级别
// 例如:设置全局跟踪变量
}
}
catch (const std::exception& e)
{
// 处理错误
}
// 通知不需要响应
return nlohmann::json();
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 ? BuildErrorMessageResponse(protocol::ErrorCode::kInternalError, "Internal error") : json;
}
inline std::string SetTraceProvider::GetMethod() const
std::string SetTraceProvider::GetMethod() const
{
return "$/setTrace";
}
inline std::string SetTraceProvider::GetProviderName() const
std::string SetTraceProvider::GetProviderName() const
{
return "SetTraceProvider";
}
@@ -7,7 +7,7 @@ namespace lsp::providers::trace
{
public:
SetTraceProvider() = default;
nlohmann::json ProvideResponse(const LspRequest& request) override;
std::string ProvideResponse(const protocol::RequestMessage& request) override;
std::string GetMethod() const override;
std::string GetProviderName() const override;
};