Josh Posted July 21 Posted July 21 This is an Ultra App Kit project. You can get the library for free on Steam. So far, our Process class does not seem to detect any output from the command-line program. LSPTest.zip Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 21 Author Posted July 21 Okay, it works if you call Process::GetStatus in the loop. I am going to change it so PIpeStream::Eof() will trigger a process::GetStatus() call internally, so it gets updated automatically. ChangeDir("lua-language-server/bin"); auto proc = CreateProcess("lua-language-server.exe"); if (not proc) { Print("Failed to create process"); return 1; } auto in = proc->readstream; auto out = proc->writestream; // This will run forever, so the project is set to act as a console app while (true) { proc->GetStatus(); // Read stream does not print anything... while (not in->Eof()) { Print(in->ReadLine()); } // Check error stream... while (not proc->errorstream->Eof()) { Print(proc->errorstream->ReadLine()); } Sleep(10); } Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 21 Author Posted July 21 This is the output. Looks like it tells you the length of the output, followed by one blank line, followed by the output in JSON format. Content-Length: 55 {"jsonrpc":"2.0","method":"$/hello","params":["world"]} Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 21 Author Posted July 21 Okay, this is interesting. It looks like I have two-way communication now. It only worked when I made the write operation a single string. I could not get Lock/Unlock/Flush to work correctly. // Example function to create a completion request std::string CreateCompletionRequest(int id, const std::string& uri, int line, int character) { std::stringstream ss; ss << "{" << "\"jsonrpc\": \"2.0\", " << "\"id\": " << id << ", " << "\"method\": \"textDocument/completion\", " << "\"params\": {" << "\"textDocument\": {\"uri\": \"" << uri << "\"}, " << "\"position\": {\"line\": " << line << ", \"character\": " << character << "}" << "}" << "}"; return ss.str(); } void SendLSPMessage(shared_ptr<PipeStream> out, const std::string& json) { std::stringstream header; header << "Content-Length: " << json.size() << "\r\n\r\n"; String s = header.str() + json + "\n"; out->WriteString(s, false); } int main(int argc, const char* argv[]) { { { ChangeDir("lua-language-server/bin"); auto proc = CreateProcess("lua-language-server.exe"); if (not proc) { Print("Failed to create process"); return 1; } auto in = proc->readstream; auto out = proc->writestream; bool start = false; bool a = false; while (true) { // This prints the following: // Content-Length: 55 // // { "jsonrpc":"2.0", "method" : "$/hello", "params" : ["world"] } while (not in->Eof()) { String s = in->ReadLine(); Print(s); a = true; } while (not proc->errorstream->Eof()) { String s = proc->errorstream->ReadLine(); Print(s); } Sleep(10); if (not start and a) { start = true; int id = 1; // Unique ID for this request std::string uri = "file:///test.lua"; auto completionRequest = CreateCompletionRequest(id, uri, 11, 5); SendLSPMessage(out, completionRequest); } } return 0; } } However, the results of the request seems to be null. Content-Length: 55 {"jsonrpc":"2.0","method":"$/hello","params":["world"]} Content-Length: 38 {"id":1,"jsonrpc":"2.0","result":null} Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 21 Author Posted July 21 Not working yet, but some progress: #include "Leadwerks.h" using namespace Leadwerks; void SendLSPMessage(shared_ptr<PipeStream> out, table& t) { std::string json = t.to_json(); std::stringstream header; header << "Content-Length: " << (json.size()) << "\r\n\r\n"; String s = header.str() + json; out->WriteString(s, false); } table GetLSPMessage(shared_ptr<Stream> in, const int id) { while (true) { while (not in->Eof()) { auto s = in->ReadLine(); Print(s); if (s.StartsWith("{")) { auto t = ParseTable(s); if (t["id"].is_integer() and int(t["id"]) == id) { return t; } } } Sleep(1); } } int main(int argc, const char* argv[]) { int rid = 0; ChangeDir("lua-language-server/bin"); auto proc = CreateProcess("lua-language-server.exe"); if (not proc) { Print("Failed to create process"); return 1; } auto in = proc->readstream; auto out = proc->writestream; // Send Initialize message ++rid; table t = {}; t["jsonrpc"] = "2.0"; t["id"] = rid; t["method"] = "initialize"; t["params"] = {}; t["params"]["processId"] = std::to_string(GetCurrentProcessId()); t["params"]["rootUri"] = CurrentDir().ToUtf8String(); t["params"]["capabilities"] = {}; SendLSPMessage(out, t); // Wait for response t = GetLSPMessage(in, rid); Print(t["id"]); // Send Initialized message (no response) t = {}; t["jsonrpc"] = "2.0"; t["method"] = "initialized"; t["params"] = {}; SendLSPMessage(out, t); // Open text document (no response) t = {}; t["jsonrpc"] = "2.0"; t["method"] = "textDocument/didOpen"; t["params"] = {}; t["params"]["uri"] = "file:///C:/test.lua"; t["params"]["languageId"] = "lua"; t["params"]["version"] = 1; String s = LoadString("C:/test.lua"); t["params"]["text"] = s; SendLSPMessage(out, t); Sleep(5000); // Completion request ++rid; t = {}; t["jsonrpc"] = "2.0"; t["id"] = rid; t["method"] = "textDocument/completion"; t["params"] = {}; t["params"]["textDocument"] = {}; t["params"]["textDocument"]["uri"] = "file:///C:/test2.lua"; t["params"]["position"] = {}; t["params"]["position"]["line"] = 3; t["params"]["position"]["character"] = 1; t["params"]["context"] = {}; t["params"]["context"]["triggerKind"] = 3; t["params"]["context"]["triggerCharacter"] = "."; SendLSPMessage(out, t); t = GetLSPMessage(in, rid); Print(t["id"]); return 0; } Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 22 Author Posted July 22 Kind of sort of working but not really #include "Leadwerks.h" using namespace Leadwerks; void SendLSPMessage(shared_ptr<PipeStream> out, table& t) { std::string json = t.to_json(); std::stringstream header; header << "Content-Length: " << (json.size()) << "\r\n\r\n"; String s = header.str() + json; out->WriteString(s, false); } table GetLSPMessage(shared_ptr<Stream> in, const int id) { while (true) { while (not in->Eof()) { auto s = in->ReadLine(); Print(s); if (s.StartsWith("{")) { auto t = ParseTable(s); if (t["id"].is_integer() and int(t["id"]) == id) { return t; } } } Sleep(1); } } int main(int argc, const char* argv[]) { int rid = 0; ChangeDir("lua-language-server/bin"); auto proc = CreateProcess("lua-language-server.exe"); if (not proc) { Print("Failed to create process"); return 1; } auto in = proc->readstream; auto out = proc->writestream; // Send Initialize message ++rid; table t = {}; t["jsonrpc"] = "2.0"; t["id"] = rid; t["method"] = "initialize"; t["params"] = {}; t["params"]["processId"] = std::to_string(GetCurrentProcessId()); t["params"]["rootUri"] = CurrentDir().ToUtf8String(); t["params"]["capabilities"] = {}; SendLSPMessage(out, t); // Wait for response t = GetLSPMessage(in, rid); Print(t["id"]); // Send Initialized message (no response) t = {}; t["jsonrpc"] = "2.0"; t["method"] = "initialized"; t["params"] = {}; SendLSPMessage(out, t); // Open text document (no response) t = {}; t["jsonrpc"] = "2.0"; t["method"] = "textDocument/didOpen"; t["params"] = {}; t["params"]["textDocument"] = {}; t["params"]["textDocument"]["uri"] = "file:///C:/test.lua"; t["params"]["textDocument"]["languageId"] = "lua"; t["params"]["textDocument"]["version"] = 1; t["params"]["textDocument"]["text"] = LoadString("C:/test.lua"); SendLSPMessage(out, t); Sleep(5000); // Completion request ++rid; t = {}; t["jsonrpc"] = "2.0"; t["id"] = rid; t["method"] = "textDocument/completion"; t["params"] = {}; t["params"]["textDocument"] = {}; t["params"]["textDocument"]["uri"] = "file:///C:/test.lua"; t["params"]["position"] = {}; t["params"]["position"]["line"] = 3; t["params"]["position"]["character"] = 1; t["params"]["context"] = {}; t["params"]["context"]["triggerKind"] = 3; t["params"]["context"]["triggerCharacter"] = "."; SendLSPMessage(out, t); t = GetLSPMessage(in, rid); Print(t["id"]); return 0; } Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted July 22 Author Posted July 22 Okay, it does work if I set the character value to 2, with this script: t = {} t.a = 1 t.b = 2 t. And here is the response, correctly showing that a and b are available values. { "id": 2, "jsonrpc": "2.0", "result": { "isIncomplete": false, "items": [ { "data": { "id": 1, "uri": "file:///c%3A/test.lua" }, "insertTextFormat": 1, "kind": 13, "label": "a", "sortText": "0001" }, { "data": { "id": 2, "uri": "file:///c%3A/test.lua" }, "insertTextFormat": 1, "kind": 13, "label": "b", "sortText": "0002" } ] } } 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.