#include #include #include "../../src/protocol/protocol.hpp" #include "../../src/protocol/transform/facade.hpp" using namespace lsp::protocol; using namespace lsp; template 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(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 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>(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 << 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 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{ "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(obj); // // 2. 从 variant 转换 // std::variant var = [> ... <]; // auto result = lsp::transform::As(var); // // 3. 从 optional 转换 // std::optional opt = [> ... <]; // auto result = lsp::transform::As(opt); // 返回 optional // // 4. 从复杂的嵌套类型转换 // std::optional> complex = [> ... <]; // auto result = lsp::transform::As(complex); // 返回 optional // // 5. 实际使用场景 // if (request.params.has_value()) { // // 直接处理 optional> // auto completionParams = lsp::transform::As(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; if constexpr (std::is_same_v) { std::cout << "ID (string): " << id << std::endl; } else if constexpr (std::is_same_v) { std::cout << "ID (integer): " << id << std::endl; } }, request.id); auto completionParams = transform::As(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::Incremental; 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::Invoked, .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; }