feat: Add LSP plugin unit tests and frontend common initialization library
Some checks failed
CI / Determine matrix (push) Has been cancelled
CI / Sanitizer (ASan+UBSan) / ubuntu-24.04 (push) Has been cancelled
CI / Coverage (gcovr) / ubuntu-24.04 (push) Has been cancelled
CI / ${{ matrix.os }} / ${{ matrix.build_type }} (push) Has been cancelled

- Introduced `dstalk_lsp_plugin_test` for testing LSP plugin functionalities including `lsp_trim`, `lsp_frame_message`, and `lsp_parse_content_length`.
- Created `dstalk_frontend_common` static library to encapsulate shared initialization logic for frontend components (CLI, GUI, Web).
- Implemented configuration file discovery and service querying in `dstalk_frontend_init`.
- Added internal headers for LSP and Anthropic plugins to facilitate unit testing.
- Established a mailroom system for asynchronous message passing between stateless agents, enhancing coordination and context management.
This commit is contained in:
2026-06-01 08:51:40 +08:00
parent 8faa02c3d5
commit c0af9c65c7
17 changed files with 1235 additions and 69 deletions

View File

@@ -0,0 +1,22 @@
// ============================================================================
// lsp_internal.hpp — 内部声明:供单元测试访问的 LSP 工具函数
// ============================================================================
// 仅在 tests 中使用;非 plugin 公共 API
// ============================================================================
#ifndef LSP_INTERNAL_HPP
#define LSP_INTERNAL_HPP
#include <string>
#include <string_view>
// ---- 字符串 trim ----
std::string_view lsp_trim(std::string_view sv);
// ---- 构建 LSP frame (Content-Length header + body) ----
std::string lsp_frame_message(const std::string& body);
// ---- 解析 Content-Length header ----
int lsp_parse_content_length(const std::string& line);
#endif // LSP_INTERNAL_HPP

View File

@@ -12,6 +12,7 @@
#include "dstalk/dstalk_host.h"
#include "dstalk/dstalk_services.h"
#include "lsp_internal.hpp"
#include <boost/json.hpp>
#include <boost/json/src.hpp>
@@ -311,7 +312,7 @@ static LspState g_lsp;
// ============================================================================
// 去除 string_view 首尾空白 / Trim leading and trailing whitespace from a string_view.
static std::string_view trim(std::string_view sv) {
std::string_view lsp_trim(std::string_view sv) {
while (!sv.empty() && (sv.front() == ' ' || sv.front() == '\t' ||
sv.front() == '\r' || sv.front() == '\n'))
sv.remove_prefix(1);
@@ -322,7 +323,7 @@ static std::string_view trim(std::string_view sv) {
}
// 将 JSON-RPC 消息体包装在 LSP 头中 (Content-Length: ...\r\n\r\n) / Wrap a JSON-RPC message body in an LSP header (Content-Length: ...\r\n\r\n).
static std::string frame_message(const std::string& body) {
std::string lsp_frame_message(const std::string& body) {
std::string frame;
frame.reserve(64 + body.size());
frame += "Content-Length: ";
@@ -333,8 +334,8 @@ static std::string frame_message(const std::string& body) {
}
// 从 LSP 头行中解析 Content-Length 值。解析失败返回 -1 / Parse the Content-Length value from an LSP header line. Returns -1 on parse failure.
static int parse_content_length(const std::string& line) {
auto sv = trim(std::string_view(line));
int lsp_parse_content_length(const std::string& line) {
auto sv = lsp_trim(std::string_view(line));
const char prefix[] = "Content-Length:";
const size_t prefix_len = sizeof(prefix) - 1;
@@ -368,7 +369,7 @@ static int send_request(const std::string& method, const json::object& params) {
msg["params"] = params;
std::string body = json::serialize(msg);
g_lsp.proc.write(frame_message(body));
g_lsp.proc.write(lsp_frame_message(body));
return id;
}
@@ -380,7 +381,7 @@ static void send_notification(const std::string& method, const json::object& par
msg["params"] = params;
std::string body = json::serialize(msg);
g_lsp.proc.write(frame_message(body));
g_lsp.proc.write(lsp_frame_message(body));
}
// ============================================================================
@@ -457,11 +458,11 @@ static void reader_loop() {
}
// header 块以空行结束 / header block ends with empty line
auto sv = trim(std::string_view(line));
auto sv = lsp_trim(std::string_view(line));
if (sv.empty()) break;
// 累积 Content-Length遇到其他 header 不丢弃,继续读取下一行 / Accumulate Content-Length; don't discard other headers, continue reading next line
int len = parse_content_length(line);
int len = lsp_parse_content_length(line);
if (len >= 0) content_length = len;
}