Jump to content

Recommended Posts

Posted

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

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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);
           }

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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"]}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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;
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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;
}

 

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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"
      }
    ]
  }
}

 

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...