该项目从 "lsp-cpp项目(An easy language-server-protocol client)"Fork而来,源项目[https://github.com/alextsao1999/lsp-cpp]。 但由于源项目不更新,故本项目独立了出来。
源项目是一个十分简单的Lsp语言客户端,通俗易懂,但是不太完善,而且停止了维护。而官方的LspCpp有点庞大又不太用的来。
所以,本项目的目的是基于lsp-cpp项目进行完善和扩展,包括跨平台支持、模块化改造、协议扩充等。
可以运行的平台
- windows
- linux(未完成)
与其他框架的集成使用
- Qt6.x,编译通过,正常使用。示例项目: 代码编辑器[https://github.com/firemeatman/CodeEditor]
cmake
#include <iostream> #include <thread> #include <fstream> #include <lsp/client.h> using namespace nlohmann; using namespace LspCore; bool readFile(std::string& path, std::string* data) { // 这里就不实现了 return true; } void copyCompileCommandsFiles() { // 这里就不实现了 } auto debugFunc = [](value& j) { //value method = j.at("method"); std::cout << "========================================\n"; std::cout << j << std::endl; }; int main() { std::string file1_uri = "file:///yourTestCodeFilePath"; std::string file1_path = "yourTestCodeFilePath"; std::string root_uri = "file:///yourTestCodeFileRootPath"; // 1. 创建Lsp客户端 PipJsonIO jsonIO(R"(clangd.exe)"); // Lsp服务器路径, 这里我用的是Clangd. MapMessageHandler msgHandler; LanguageClient client(msgHandler, jsonIO); // 2. 复制compile_commands.json到工作区, clangd需要这个文件;通过命令应该也能指定该文件路径和clangd工作文件夹 copyCompileCommandsFiles(); // 3. 绑定一些通知消息的回调函数 { MapMessageHandler::Accessor accessor = msgHandler.access(); // 访问者模式访问MapMessageHandler的接口,线程安全 accessor.bindNotify(METHOD_PublishDiagnostics.c_str(), debugFunc); accessor.bindNotify(METHOD_DidOpen.c_str(), debugFunc); accessor.bindNotify(METHOD_DidClose.c_str(), debugFunc); } // 4. 线程中运行Lsp客户端 std::thread thread([&] { client.safeLoop(); }); // 5. 测试与本地Lsp服务器的通信 int res; while (scanf("%d", &res)) { switch (res) { case 0: // 退出 { client.Exit(); client.requestStopLoop(); thread.join(); return 0; break; } case 1: // 初始化 { MapMessageHandler::Accessor accessor = msgHandler.access();// 访问者模式访问MapMessageHandler的接口,线程安全 accessor.bindResponse(client.Initialize(string_ref(root_uri)), debugFunc);// 发出初始化请求消息,并绑定回调函数 break; } case 2: // 打开文件 { std::string text; readFile(file1_path, &text); client.DidOpen(file1_uri, text); break; } case 3: // 关闭文件 { client.DidClose(string_ref(file1_uri)); break; } case 4: // 获取词语列表 { MapMessageHandler::Accessor accessor = msgHandler.access(); accessor.bindResponse(client.SemanticTokensALL(string_ref(file1_uri)), debugFunc); break; } case 5: // 悬停信息 { MapMessageHandler::Accessor accessor = msgHandler.access(); Position pos{8, 13}; accessor.bindResponse(client.Hover(string_ref(file1_uri), pos), debugFunc); break; } default: break; } } return 0; }