312 lines
9.1 KiB
C++
312 lines
9.1 KiB
C++
#include <iostream>
|
|
#include <vector>
|
|
#include "../lsp-server/src/protocol/protocol.hpp"
|
|
#include "../lsp-server/src/protocol/transform/facade.hpp"
|
|
|
|
using namespace lsp::protocol;
|
|
using namespace lsp;
|
|
|
|
template<typename T>
|
|
void print_json(const string& name, const T& obj)
|
|
{
|
|
if (auto result = glz::write_json(obj); result)
|
|
{
|
|
std::cout << name << " = " << *result << std::endl;
|
|
} else
|
|
{
|
|
std::cerr << "Error: " << result.error() << "\n";
|
|
}
|
|
}
|
|
|
|
void test_basic_conversion()
|
|
{
|
|
std::cout << "\n=== Testing Basic Conversion ===" << std::endl;
|
|
|
|
// 测试 struct 转换
|
|
RequestMessage msg;
|
|
msg.method = "textDocument/completion";
|
|
msg.id = 42;
|
|
|
|
// Struct -> LSPAny
|
|
LSPAny any = transform::LSPAny(msg);
|
|
std::string json;
|
|
auto ce = glz::write_json(any, json);
|
|
if(ce)
|
|
std::cout << "Error" << std::endl;
|
|
std::cout << "Message as JSON: " << json << std::endl;
|
|
|
|
// LSPAny -> Struct
|
|
RequestMessage restored = transform::As<RequestMessage>(any);
|
|
std::cout << "Restored method: " << restored.method << std::endl;
|
|
std::cout << "id = ";
|
|
std::visit([](const auto& value)
|
|
{
|
|
std::cout << value;
|
|
}, restored.id);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void test_vector_conversion()
|
|
{
|
|
std::cout << "\n=== Testing Vector Conversion ===" << std::endl;
|
|
|
|
std::vector<Position> positions = {
|
|
{10, 5},
|
|
{20, 15},
|
|
{30, 25}
|
|
};
|
|
|
|
// Vector -> LSPAny
|
|
LSPAny any = transform::LSPAny(positions);
|
|
|
|
std::string json;
|
|
auto ce = glz::write_json(any, json);
|
|
std::cout << "Vector as JSON: " << json << std::endl;
|
|
|
|
// LSPAny -> Vector
|
|
auto restored = transform::As<std::vector<Position>>(any);
|
|
std::cout << "Restored " << restored.size() << " positions" << std::endl;
|
|
}
|
|
|
|
void test_json_string()
|
|
{
|
|
std::cout << "\n=== Test json_string ===" << std::endl;
|
|
|
|
string json = R"({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":"file:///tmp","workDoneToken":"abc"}})";
|
|
RequestMessage request;
|
|
auto ret = glz::read_json(request, json);
|
|
std::cout << "jsonrpc = " << request.jsonrpc << std::endl;
|
|
std::cout << "method = " << request.method << std::endl;
|
|
std::cout << "id = ";
|
|
std::visit([](const auto& value)
|
|
{
|
|
std::cout << value;
|
|
}, request.id);
|
|
std::cout << std::endl;
|
|
|
|
auto result = glz::write_json(request.params);
|
|
std::cout << *result << std::endl;
|
|
InitializeParams params;
|
|
// std::string buffer = R"({"workDoneToken":123,"processId":"id","clientInfo":{"name":"VSCode","version":"1.0.0"},"rootPath":"456","initializationOptions":"options","trace":"messages"})";
|
|
auto r2= glz::read_json(params, *result);
|
|
if (params.processId.has_value())
|
|
std::cout << "processId = " << params.processId.value() << "\n";
|
|
else
|
|
std::cout << "processId = null\n";
|
|
std::cout << "rootUri = " << params.rootUri.value() << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void test_basic_types()
|
|
{
|
|
std::cout << "\n=== Test basic_types.hpp ===" << std::endl;
|
|
Range range =
|
|
{
|
|
.start = {1, 3},
|
|
.end = {2, 4}
|
|
};
|
|
|
|
DocumentFilter df = {
|
|
.language = "en",
|
|
.scheme = "scheme",
|
|
.pattern = "pattern",
|
|
};
|
|
|
|
AnnotatedTextEdit ate;
|
|
ate.range = {.start = {1, 3}, .end = {2, 4}};
|
|
ate.newText = "text_edit";
|
|
ate.annotationId = "id";
|
|
|
|
Location location =
|
|
{
|
|
.uri = "location_uri",
|
|
.range = {.start = {1, 3}, .end = {2, 4}}
|
|
};
|
|
|
|
Command command1 =
|
|
{
|
|
.title = "command_title",
|
|
.command = "command_command",
|
|
};
|
|
Command command2 =
|
|
{
|
|
.title = "command_title",
|
|
.command = "command_command",
|
|
.arguments = "any_string"
|
|
};
|
|
Command command3 =
|
|
{
|
|
.title = "command_title",
|
|
.command = "command_command",
|
|
.arguments = 123
|
|
};
|
|
std::vector<LSPAny> array = {
|
|
1.0, // decimal
|
|
string("two"),
|
|
3.0, // decimal
|
|
true,
|
|
nullptr
|
|
};
|
|
LSPAny array_val = array;
|
|
LSPObject object = {
|
|
{"name", string("test object")},
|
|
{"count", 42.0}, // decimal
|
|
{"active", boolean(true)},
|
|
{"data", array_val},
|
|
{"metadata", nullptr}
|
|
};
|
|
Command command4 =
|
|
{
|
|
.title = "command_title",
|
|
.command = "command_command",
|
|
.arguments = object
|
|
};
|
|
|
|
MarkdownClientCapabilities mkcp =
|
|
{
|
|
.parser = "parse",
|
|
.allowedTags = std::vector<string>{"h1", "h2", "p", "code", "pre"}
|
|
};
|
|
std::cout << "Test....basic_types" << std::endl;
|
|
print_json("Range", range);
|
|
print_json("DocumentFilter", df);
|
|
print_json("AnnotatedTextEdit", ate);
|
|
print_json("Location", location);
|
|
print_json("Command1", command1);
|
|
print_json("Command2", command2);
|
|
print_json("Command3", command3);
|
|
print_json("Command4", command4);
|
|
print_json("MarkdownClientCapabilities", mkcp);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void test_capabilities()
|
|
{
|
|
std::cout << "\n=== Test capabilities.hpp ===" << std::endl;
|
|
InitializeParams ip;
|
|
ip.workDoneToken = 123;
|
|
ip.processId = std::nullopt;
|
|
ip.clientInfo = InitializeParams::ClientInfo{"VSCode", "1.0.0"};
|
|
ip.rootPath = "456";
|
|
ip.initializationOptions = "options";
|
|
ip.trace = TraceValueLiterals::Messages;
|
|
|
|
std::cout << "Test....capabilities" << std::endl;
|
|
print_json("InitializeParams", ip);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void test_RequestMessage_serialize()
|
|
{
|
|
// // 1. 直接从 LSPObject 转换
|
|
// lsp::protocol::LSPObject obj = [> ... <];
|
|
// auto result = lsp::transform::As<CompletionParams>(obj);
|
|
|
|
// // 2. 从 variant 转换
|
|
// std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject> var = [> ... <];
|
|
// auto result = lsp::transform::As<CompletionParams>(var);
|
|
|
|
// // 3. 从 optional 转换
|
|
// std::optional<lsp::protocol::LSPObject> opt = [> ... <];
|
|
// auto result = lsp::transform::As<CompletionParams>(opt); // 返回 optional<CompletionParams>
|
|
|
|
// // 4. 从复杂的嵌套类型转换
|
|
// std::optional<std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject>> complex = [> ... <];
|
|
// auto result = lsp::transform::As<CompletionParams>(complex); // 返回 optional<CompletionParams>
|
|
|
|
// // 5. 实际使用场景
|
|
// if (request.params.has_value()) {
|
|
// // 直接处理 optional<variant<LSPArray, LSPObject>>
|
|
// auto completionParams = lsp::transform::As<lsp::protocol::CompletionParams>(request.params);
|
|
// if (completionParams.has_value()) {
|
|
// std::cout << "URI: " << completionParams->textDocument.uri << std::endl;
|
|
// }
|
|
// }
|
|
std::string json = R"({
|
|
"jsonrpc":"2.0",
|
|
"id":"4",
|
|
"method":"textDocument/completion",
|
|
"params":{
|
|
"context":{"triggerKind":1},
|
|
"partialResultToken":0,
|
|
"position":{"character":12,"line":22},
|
|
"textDocument":{"uri":"file://path/to_file.ts"},
|
|
"workDoneToken":0
|
|
}
|
|
})";
|
|
|
|
RequestMessage request;
|
|
auto error = glz::read_json(request, json);
|
|
|
|
if (error) {
|
|
std::cerr << "Failed to parse JSON: " << glz::format_error(error, json) << std::endl;
|
|
}
|
|
|
|
std::cout << "jsonrpc: " << request.jsonrpc << std::endl;
|
|
std::cout << "method: " << request.method << std::endl;
|
|
std::visit([](const auto& id)
|
|
{
|
|
using T = std::decay_t<decltype(id)>;
|
|
if constexpr (std::is_same_v<T, lsp::protocol::string>) {
|
|
std::cout << "ID (string): " << id << std::endl;
|
|
} else if constexpr (std::is_same_v<T, lsp::protocol::integer>) {
|
|
std::cout << "ID (integer): " << id << std::endl;
|
|
}
|
|
}, request.id);
|
|
|
|
auto completionParams = transform::As<CompletionParams>(request.params.value());
|
|
std::cout << "URI: " << completionParams.textDocument.uri << std::endl;
|
|
|
|
// std::visit([](const auto& value)
|
|
// {
|
|
// std::cout << value;
|
|
// }, request.id);
|
|
|
|
// std::visit([](const auto& params) {
|
|
|
|
// }, request.params.value());
|
|
}
|
|
|
|
void test_message()
|
|
{
|
|
std::cout << "\n=== Test message.hpp ===" << std::endl;
|
|
ResponseMessage response;
|
|
response.id = "123";
|
|
InitializeResult result;
|
|
result.serverInfo.name = "TSL Language Server";
|
|
result.serverInfo.version = "1.0.0";
|
|
TextDocumentSyncOptions opts;
|
|
opts.openClose = true;
|
|
opts.change = TextDocumentSyncKind::kIncremental;
|
|
result.capabilities.textDocumentSync = opts;
|
|
|
|
CompletionParams comparams;
|
|
comparams.textDocument.uri = "file://path/to_file.ts";
|
|
comparams.position.character = 12;
|
|
comparams.position.line = 22;
|
|
comparams.context = CompletionContext{
|
|
.triggerKind = CompletionTriggerKind::kInvoked,
|
|
.triggerCharacter = std::nullopt
|
|
};
|
|
RequestMessage rm;
|
|
rm.id = "4";
|
|
rm.method = "textDocument/completion";
|
|
rm.params = transform::LSPObject(comparams);
|
|
|
|
print_json("ResponseMessage", response);
|
|
print_json("rm", rm);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
// test_basic_conversion();
|
|
// test_vector_conversion();
|
|
// test_json_string();
|
|
// test_basic_types();
|
|
// test_capabilities();
|
|
test_message();
|
|
test_RequestMessage_serialize();
|
|
return 0;
|
|
}
|