Merge branch 'lsp-server'

This commit is contained in:
csh
2025-07-02 14:39:21 +08:00
73 changed files with 6768 additions and 823 deletions
+311
View File
@@ -0,0 +1,311 @@
#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;
}
+3 -1
View File
@@ -1,3 +1,5 @@
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
JSON='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":"file:///tmp","capabilities":{}}}'
LENGTH=$(echo -n "$JSON" | wc -c)
printf "Content-Length: %d\r\n\r\n%s" $LENGTH "$JSON" | ../lsp-server/build/arch/tsl-server --log=verbose --log-stderr
printf "Content-Length: %d\r\n\r\n%s" $LENGTH "$JSON" | "$SCRIPT_DIR/../vscode/bin/tsl-server" --log=verbose --log-stderr
+711
View File
@@ -0,0 +1,711 @@
#include <glaze/glaze.hpp>
#include <variant>
#include <map>
#include <vector>
#include <string>
#include <cstdint>
#include <optional>
#include <type_traits>
using integer = std::int32_t;
using uinteger = std::uint32_t;
using decimal = double;
using boolean = bool;
using string = std::string;
// 前向声明
struct LSPAny;
using LSPObject = std::map<string, LSPAny>;
using LSPArray = std::vector<LSPAny>;
using LSPAnyVariant = std::variant<
LSPObject,
LSPArray,
string,
decimal, // 放在前面,优先匹配数字
boolean,
std::nullptr_t
>;
struct LSPAny {
LSPAnyVariant value;
// 默认构造函数
LSPAny() : value(nullptr) {}
// 拷贝和移动构造函数
LSPAny(const LSPAny& other) : value(other.value) {}
LSPAny(LSPAny&& other) noexcept : value(std::move(other.value)) {}
// 针对每种支持的类型的构造函数
LSPAny(const std::map<string, LSPAny>& val) : value(val) {}
LSPAny(std::map<string, LSPAny>&& val) : value(std::move(val)) {}
LSPAny(const std::vector<LSPAny>& val) : value(val) {}
LSPAny(std::vector<LSPAny>&& val) : value(std::move(val)) {}
LSPAny(const string& val) : value(val) {}
LSPAny(string&& val) : value(std::move(val)) {}
LSPAny(const char* val) : value(string(val)) {}
// 所有数字类型都转换为 decimal
LSPAny(int val) : value(static_cast<decimal>(val)) {}
LSPAny(long val) : value(static_cast<decimal>(val)) {}
LSPAny(long long val) : value(static_cast<decimal>(val)) {}
LSPAny(unsigned int val) : value(static_cast<decimal>(val)) {}
LSPAny(unsigned long val) : value(static_cast<decimal>(val)) {}
LSPAny(unsigned long long val) : value(static_cast<decimal>(val)) {}
LSPAny(float val) : value(static_cast<decimal>(val)) {}
LSPAny(double val) : value(val) {}
LSPAny(long double val) : value(static_cast<decimal>(val)) {}
LSPAny(boolean val) : value(val) {}
LSPAny(std::nullptr_t) : value(nullptr) {}
// 赋值操作符
LSPAny& operator=(const LSPAny& other) {
value = other.value;
return *this;
}
LSPAny& operator=(LSPAny&& other) noexcept {
value = std::move(other.value);
return *this;
}
// 针对每种支持的类型的赋值操作符
LSPAny& operator=(const std::map<string, LSPAny>& val) {
value = val;
return *this;
}
LSPAny& operator=(std::map<string, LSPAny>&& val) {
value = std::move(val);
return *this;
}
LSPAny& operator=(const std::vector<LSPAny>& val) {
value = val;
return *this;
}
LSPAny& operator=(std::vector<LSPAny>&& val) {
value = std::move(val);
return *this;
}
LSPAny& operator=(const string& val) {
value = val;
return *this;
}
LSPAny& operator=(string&& val) {
value = std::move(val);
return *this;
}
LSPAny& operator=(const char* val) {
value = string(val);
return *this;
}
// 所有数字类型都转换为 decimal
LSPAny& operator=(int val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long long val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned int val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long long val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(float val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(double val) {
value = val;
return *this;
}
LSPAny& operator=(long double val) {
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(boolean val) {
value = val;
return *this;
}
LSPAny& operator=(std::nullptr_t) {
value = nullptr;
return *this;
}
// 类型检查辅助函数
template<typename T>
bool is() const { return std::holds_alternative<T>(value); }
template<typename T>
T& get() { return std::get<T>(value); }
template<typename T>
const T& get() const { return std::get<T>(value); }
// 访问操作符
template<typename Visitor>
auto visit(Visitor&& visitor) const {
return std::visit(std::forward<Visitor>(visitor), value);
}
template<typename Visitor>
auto visit(Visitor&& visitor) {
return std::visit(std::forward<Visitor>(visitor), value);
}
};
// glaze 自动支持 std::variant,无需额外配置
namespace glz {
template <>
struct meta<LSPAny> {
using T = LSPAny;
static constexpr auto value = &T::value;
};
}
// ===== 简单清晰的转换模板 =====
// 转换工具类
struct LSPConvert {
// === 基本类型的转换(优先级最高) ===
// boolean
static LSPAny ToLSPAny(boolean value) {
return LSPAny(value);
}
// 整数类型
static LSPAny ToLSPAny(int value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(long value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(long long value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned int value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long long value) {
return LSPAny(value);
}
// 浮点类型
static LSPAny ToLSPAny(float value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(double value) {
return LSPAny(value);
}
static LSPAny ToLSPAny(long double value) {
return LSPAny(value);
}
// string
static LSPAny ToLSPAny(const string& str) {
return LSPAny(str);
}
static LSPAny ToLSPAny(const char* str) {
return LSPAny(str);
}
// nullptr
static LSPAny ToLSPAny(std::nullptr_t) {
return LSPAny(nullptr);
}
// LSPAny 自身
static LSPAny ToLSPAny(const LSPAny& any) {
return any;
}
// === 容器类型的转换 ===
// vector
template<typename T>
static LSPAny ToLSPAny(const std::vector<T>& vec) {
LSPArray arr;
arr.reserve(vec.size());
for (const auto& item : vec) {
arr.push_back(ToLSPAny(item));
}
return LSPAny(std::move(arr));
}
// map
template<typename T>
static LSPAny ToLSPAny(const std::map<string, T>& map) {
LSPObject obj;
for (const auto& [key, value] : map) {
obj[key] = ToLSPAny(value);
}
return LSPAny(std::move(obj));
}
// optional
template<typename T>
static LSPAny ToLSPAny(const std::optional<T>& opt) {
if (opt.has_value()) {
return ToLSPAny(*opt);
}
return LSPAny(nullptr);
}
// === Struct 到 LSPAny 的转换(最低优先级) ===
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny
>::type ToLSPAny(const T& obj) {
// 序列化为 JSON 字符串
std::string json;
auto ec = glz::write_json(obj, json);
if (ec) {
throw std::runtime_error("Failed to serialize to JSON");
}
// 直接解析为 LSPAny
LSPAny result;
ec = glz::read_json(result, json);
if (ec) {
throw std::runtime_error("Failed to parse JSON to LSPAny");
}
return result;
}
// === LSPAny 到基本类型的转换 ===
// boolean
static boolean BoolFromLSPAny(const LSPAny& any) {
if (!any.is<boolean>()) {
throw std::runtime_error("LSPAny is not a boolean");
}
return any.get<boolean>();
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
NumberFromLSPAny(const LSPAny& any) {
if (!any.is<decimal>()) {
throw std::runtime_error("LSPAny is not a number");
}
return static_cast<T>(any.get<decimal>());
}
// string
static string StringFromLSPAny(const LSPAny& any) {
if (!any.is<string>()) {
throw std::runtime_error("LSPAny is not a string");
}
return any.get<string>();
}
// === LSPAny 到容器类型的转换 ===
// vector
template<typename T>
static std::vector<T> VectorFromLSPAny(const LSPAny& any) {
if (!any.is<LSPArray>()) {
throw std::runtime_error("LSPAny is not an array");
}
const auto& arr = any.get<LSPArray>();
std::vector<T> result;
result.reserve(arr.size());
for (const auto& item : arr) {
result.push_back(FromLSPAny<T>(item));
}
return result;
}
// optional
template<typename T>
static std::optional<T> OptionalFromLSPAny(const LSPAny& any) {
if (any.is<std::nullptr_t>()) {
return std::nullopt;
}
return FromLSPAny<T>(any);
}
// === LSPAny 到 Struct 的转换 ===
template<typename T>
static T FromLSPAny(const LSPAny& any) {
return FromLSPAnyImpl<T>(any);
}
private:
// 内部实现,使用重载来处理不同类型
// boolean
static boolean FromLSPAnyImpl(const LSPAny& any, boolean*) {
return BoolFromLSPAny(any);
}
// string
static string FromLSPAnyImpl(const LSPAny& any, string*) {
return StringFromLSPAny(any);
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
FromLSPAnyImpl(const LSPAny& any, T*) {
return NumberFromLSPAny<T>(any);
}
// LSPAny 自身
static LSPAny FromLSPAnyImpl(const LSPAny& any, LSPAny*) {
return any;
}
// struct 类型
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, LSPAny>::value,
T
>::type FromLSPAnyImpl(const LSPAny& any, T*) {
// 序列化 LSPAny 为 JSON
std::string json;
auto ec = glz::write_json(any.value, json);
if (ec) {
throw std::runtime_error("Failed to serialize LSPAny to JSON");
}
// 解析 JSON 到目标类型
T result;
ec = glz::read_json(result, json);
if (ec) {
throw std::runtime_error("Failed to parse JSON to target type");
}
return result;
}
// 通过指针类型来分派
template<typename T>
static T FromLSPAnyImpl(const LSPAny& any) {
return FromLSPAnyImpl(any, static_cast<T*>(nullptr));
}
};
// ===== 便利函数(可选) =====
// 基本类型的便利函数
inline LSPAny ToLSPAny(boolean value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(float value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(const string& str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(const char* str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(std::nullptr_t) { return LSPConvert::ToLSPAny(nullptr); }
inline LSPAny ToLSPAny(const LSPAny& any) { return LSPConvert::ToLSPAny(any); }
// 容器类型的便利函数
template<typename T>
LSPAny ToLSPAny(const std::vector<T>& vec) {
return LSPConvert::ToLSPAny(vec);
}
template<typename T>
LSPAny ToLSPAny(const std::map<string, T>& map) {
return LSPConvert::ToLSPAny(map);
}
template<typename T>
LSPAny ToLSPAny(const std::optional<T>& opt) {
return LSPConvert::ToLSPAny(opt);
}
// struct 类型的便利函数
template<typename T>
typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny
>::type ToLSPAny(const T& value) {
return LSPConvert::ToLSPAny(value);
}
// FromLSPAny 便利函数
template<typename T>
T FromLSPAny(const LSPAny& any) {
return LSPConvert::FromLSPAny<T>(any);
}
// ===== 测试代码 =====
// 测试用的结构体
struct Message {
string jsonrpc = "2.0";
string method;
int id = 0;
};
struct Position {
int line;
int character;
};
struct Range {
Position start;
Position end;
};
struct TextDocumentIdentifier {
string uri;
};
struct TextDocumentPositionParams {
TextDocumentIdentifier textDocument;
Position position;
};
struct CompletionItem {
string label;
std::optional<int> kind;
std::optional<string> detail;
std::optional<string> documentation;
std::optional<boolean> deprecated;
std::optional<boolean> preselect;
std::optional<string> sortText;
std::optional<string> filterText;
std::optional<string> insertText;
};
// 为测试结构体提供 glaze 元数据
template <>
struct glz::meta<Message> {
using T = Message;
static constexpr auto value = object(
"jsonrpc", &T::jsonrpc,
"method", &T::method,
"id", &T::id
);
};
template <>
struct glz::meta<Position> {
using T = Position;
static constexpr auto value = object(
"line", &T::line,
"character", &T::character
);
};
template <>
struct glz::meta<Range> {
using T = Range;
static constexpr auto value = object(
"start", &T::start,
"end", &T::end
);
};
template <>
struct glz::meta<TextDocumentIdentifier> {
using T = TextDocumentIdentifier;
static constexpr auto value = object(
"uri", &T::uri
);
};
template <>
struct glz::meta<TextDocumentPositionParams> {
using T = TextDocumentPositionParams;
static constexpr auto value = object(
"textDocument", &T::textDocument,
"position", &T::position
);
};
template <>
struct glz::meta<CompletionItem> {
using T = CompletionItem;
static constexpr auto value = object(
"label", &T::label,
"kind", &T::kind,
"detail", &T::detail,
"documentation", &T::documentation,
"deprecated", &T::deprecated,
"preselect", &T::preselect,
"sortText", &T::sortText,
"filterText", &T::filterText,
"insertText", &T::insertText
);
};
// 测试函数
#include <iostream>
void test_basic_conversion() {
std::cout << "=== Testing Basic Conversion ===" << std::endl;
// 测试 struct 转换
Message msg;
msg.method = "textDocument/completion";
msg.id = 42;
// Struct -> LSPAny
LSPAny any = ToLSPAny(msg);
// 序列化查看
std::string json;
glz::write_json(any, json);
std::cout << "Message as JSON: " << json << std::endl;
// LSPAny -> Struct
Message restored = FromLSPAny<Message>(any);
std::cout << "Restored method: " << restored.method << std::endl;
std::cout << "Restored id: " << restored.id << 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 = ToLSPAny(positions);
std::string json;
glz::write_json(any, json);
std::cout << "Vector as JSON: " << json << std::endl;
// LSPAny -> Vector
auto restored = LSPConvert::VectorFromLSPAny<Position>(any);
std::cout << "Restored " << restored.size() << " positions" << std::endl;
}
void test_optional_conversion() {
std::cout << "\n=== Testing Optional Conversion ===" << std::endl;
CompletionItem item;
item.label = "std::vector";
item.kind = 1;
item.detail = "template<typename T> class vector";
LSPAny any = ToLSPAny(item);
std::string json;
glz::write_json(any, json);
std::cout << "CompletionItem as JSON: " << json << std::endl;
// 测试 null optional
std::optional<string> empty_opt;
LSPAny null_any = ToLSPAny(empty_opt);
glz::write_json(null_any, json);
std::cout << "Empty optional as JSON: " << json << std::endl;
}
void test_mixed_usage() {
std::cout << "\n=== Testing Mixed Usage ===" << std::endl;
// 创建复杂对象
LSPObject obj;
obj["message"] = ToLSPAny(Message{"2.0", "test/method", 123});
obj["position"] = ToLSPAny(Position{10, 20});
obj["numbers"] = ToLSPAny(std::vector<int>{1, 2, 3});
obj["flag"] = LSPAny(true);
obj["value"] = LSPAny(3.14);
obj["text"] = LSPAny("Hello LSP");
obj["empty"] = LSPAny(nullptr);
LSPAny root(obj);
std::string json;
glz::write_json(root, json);
std::cout << "Complex object: " << json << std::endl;
// 提取值
if (root.is<LSPObject>()) {
auto& root_obj = root.get<LSPObject>();
Message msg = FromLSPAny<Message>(root_obj["message"]);
std::cout << "Extracted message method: " << msg.method << std::endl;
Position pos = FromLSPAny<Position>(root_obj["position"]);
std::cout << "Extracted position: " << pos.line << ", " << pos.character << std::endl;
}
}
int main() {
try {
test_basic_conversion();
test_vector_conversion();
test_optional_conversion();
test_mixed_usage();
std::cout << "\nAll tests completed!" << std::endl;
} catch (const std::exception& e) {
std::cout << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}