Pure-D / serve-d

D LSP server (dlang language server protocol server)
MIT License
200 stars 48 forks source link

fixing missing params and proper end brackets to message registerCapability #299

Closed vushu closed 1 year ago

vushu commented 1 year ago

I have painstakingly debugged serve-d for quite some time, since coc didn't work after some major changes, and I have finally discovered why (see in the PR), It is quite error prone to manually build these messages, so I am guessing we need some tests to ensure the expected message.

I think why other lsp clients works is because they just ignore invalid messages, whereas coc is way more strict and just shutdowns the server when it receives something invalid.

WebFreak001 commented 1 year ago

I rewrote the code here to be more readable and not fail due to wrong string handling, can you try out this patch and see if it works instead of this PR?

diff --git a/lsp/source/served/lsp/jsonrpc.d b/lsp/source/served/lsp/jsonrpc.d
index 44bbad3..e10bf5d 100644
--- a/lsp/source/served/lsp/jsonrpc.d
+++ b/lsp/source/served/lsp/jsonrpc.d
@@ -224,16 +224,33 @@ class RPCProcessor : Fiber

    void registerCapability(T)(scope const(char)[] id, scope const(char)[] method, T options)
    {
-       const(char)[][7] parts = [
-           `{"jsonrpc":"2.0","method":"client/registerCapability","registrations":[{"id":"`,
-           id.escapeJsonStringContent,
-           `","method":"`,
-           method.escapeJsonStringContent,
-           `","registerOptions":`,
-           options.serializeJson,
-           `]}`
+       import mir.serde;
+
+       @serdeFallbackStruct
+       struct RegistrationT
+       {
+           const(char)[] id;
+           const(char)[] method;
+           T registerOptions;
+       }
+
+       @serdeFallbackStruct
+       struct RegistrationParamsT
+       {
+           RegistrationT[] registrations;
+       }
+
+       static assert(RegistrationParamsT.tupleof.stringof == RegistrationParams.tupleof.stringof,
+           "Fields of templated `RegistrationParams` differ from regular struct, please verify correct field names in LSP spec!");
+       static assert(RegistrationT.tupleof.stringof == Registration.tupleof.stringof,
+           "Fields of templated `Registration` differ from regular struct, please verify correct field names in LSP spec!");
+
+       scope RegistrationParamsT params;
+       params.registrations = [
+           RegistrationT(id, method, options)
        ];
-       sendRawPacket(parts[]);
+
+       sendMethod("client/registerCapability", params);
    }

    /// Sends a request with the given `method` name to the other RPC side without any parameters.

if it does, I could either commit it with you co-authoring it or you can just apply it to the PR here and I will merge it then.

This fixes that there was also no id parameter allocated for the request, so it never got a response. (although the response is void, it may throw an exception if the editor responds with an error)

vushu commented 1 year ago

@WebFreak001 I can confirm that your implementation works :) Just commit it with co-authoring

monkoose commented 1 year ago

Works for me too.

WebFreak001 commented 1 year ago

thanks, committed it there, nightly is building