代码之家  ›  专栏  ›  技术社区  ›  Leon0402

与语言服务器通信(语言服务器协议)

  •  1
  • Leon0402  · 技术社区  · 6 年前

    我想在一个简单的自编文本编辑器中测试语言服务器协议。但我不太确定我是否正确理解了如何向服务器写入和从服务器读取数据。我想用C++做这件事。

    为了测试目的,我在这个例子中使用qt。但如果你用另一个图书馆,这也没关系。作为一个服务器,我安装了CCL(它在我用Atom测试它时工作)。

    这就是我的基因观念: 1。将服务器作为进程启动 2。根据规范定义用于初始化的JSON文件 三。将其转换为字符串并发送到客户端 三。等待响应(应为初始值设定项结果)

    #include <QCoreApplication>
    #include <QProcess>
    #include <iostream>
    #include <QFile>
    
    int main(int argc, char* argv[]) {
      QCoreApplication app(argc, argv);
    
      QFile file {"src/initializeRequest.json"};
      file.open(QIODevice::ReadOnly);
    
      QProcess* myProcess = new QProcess(&app);
      myProcess->start("ccls", QStringList {});
    
      std::cout << myProcess->write(file.readAll()) << '\n';
      std::cout << myProcess->readAll().toStdString();
      file.close();
      return app.exec();
    }
    

    但实际上,我甚至不确定这些消息(didopen、initialzerequest等)是否真的作为文件发送。根据语言服务器协议网站,它们是描述JSON文件的接口…但是我没有发现他们是怎么被派来的

    因此,如果有人能告诉我我是否在正确的轨道上(我尝试发送实际的文件),如果有人能向我展示与服务器的最简单的通信,我会很感激,所以我得到了一个响应(看看它是否有效)。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Leon0402    6 年前

    我做了很多实验,并创建了一个最小的工作示例。在这个例子中,我将初始化请求发送到CCL(它是C++语言服务器)并读取响应。 我使用qprocess来启动服务器(当然可以使用不同的方法)和rapidjson( https://github.com/Tencent/rapidjson )用于构建JSON文件。

    #include <QCoreApplication>
    #include <QProcess>
    #include <iostream>
    #include <sstream>
    
    #include "rapidjson/stringbuffer.h"
    #include "rapidjson/writer.h"
    
    int main(int argc, char* argv[]) {
      QCoreApplication app {argc, argv};
    
      //Start server as a QProcess
      QProcess* server = new QProcess {&app};
      server->start("ccls", QStringList {"-log-file=/tmp/ccls2.log", "-init={}"});
      server->waitForStarted(-1);
      std::cout << "Server started" << '\n';
    
      //Construct json Request
      rapidjson::StringBuffer output {};
      rapidjson::Writer<rapidjson::StringBuffer> writer {output};
    
      writer.StartObject();
      writer.Key("jsonrpc");
      writer.String("2.0");
      writer.Key("id");
      writer.Int(0);
      writer.Key("method");
      writer.String("initialize");
      writer.Key("params");
      writer.StartObject();
      writer.Key("processId");
      writer.Int(0);
      writer.Key("rootUri");
      writer.String("home");
      writer.Key("capabilities");
      writer.StartObject();
      writer.EndObject();
      writer.EndObject();
      writer.EndObject();
    
      std::string content = output.GetString();
      std::ostringstream oss;
      oss << "Content-Length: " << content.length() << "\r\n" << "\r\n";
      std::string header = oss.str();
    
      std::cout << header << content << '\n';
    
      //Send request to server
      server->write(header.c_str());
      server->write(content.c_str());
    
      //Wait for response and read it
      server->waitForReadyRead(-1);
      std::cout << "Server has sent response" << '\n';
      std::cout << server->readAll().toStdString() << '\n';
    
      return app.exec();
    }
    

    输出:

    Server started
    Content-Length: 106
    
    {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":0,"rootUri":"home","capabilities":{}}}
    Server has sent response
    Content-Length: 1046
    
    {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"textDocumentSync":{"openClose":true,"change":2,"willSave":false,"willSaveWaitUntil":false,"
    save":{"includeText":false}},"hoverProvider":true,"completionProvider":{"resolveProvider":false,"triggerCharacters":[".",":",">","#","<","\"",
    "/"]},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"implementationProvider":true,"typeDefinitionProvider"
    :true,"referencesProvider":true,"documentHighlightProvider":true,"documentSymbolProvider":true,"workspaceSymbolProvider":true,"codeActionProvi
    der":{"codeActionKinds":["quickfix"]},"codeLensProvider":{"resolveProvider":false},"documentFormattingProvider":true,"documentRangeFormattingP
    rovider":true,"documentOnTypeFormattingProvider":{"firstTriggerCharacter":"}","moreTriggerCharacter":[]},"renameProvider":true,"documentLinkPr
    ovider":{"resolveProvider":true},"foldingRangeProvider":true,"executeCommandProvider":{"commands":["ccls.xref"]},"workspace":{"workspaceFolder
    s":{"supported":true,"changeNotifications":true}}}}}
    

    正如我所说,我想向所有有相同问题的人展示一个最小的工作示例。当然,为请求等创建结构是有意义的。