patch 9.0.1924: LSP server message still wrongly handled (after 9.0.1922)

Commit: 
https://github.com/vim/vim/commit/1926ae41845c3b6e2045b29225365c8a2e4eb1da
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Thu Sep 21 16:36:28 2023 +0200

    patch 9.0.1924: LSP server message still wrongly handled (after 9.0.1922)
    
    Problem:  LSP server message still wrongly handled (after 9.0.1922)
    Solution: Handle 'method' messages properly, don't discard them, add
              tests.
    
    closes: #13141
    
    Signed-off-by: Christian Brabandt <c...@256bit.org>
    Co-authored-by: Yegappan Lakshmanan <yegap...@yahoo.com>

diff --git a/src/channel.c b/src/channel.c
index 4326ca7c1..1de376884 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -2466,6 +2466,12 @@ channel_get_json(
                d = item->jq_value->vval.v_dict;
                if (d == NULL)
                    goto nextitem;
+               // When looking for a response message from the LSP server,
+               // ignore new LSP request and notification messages.  LSP
+               // request and notification messages have the "method" field in
+               // the header and the response messages do not have this field.
+               if (dict_has_key(d, "method"))
+                   goto nextitem;
                di = dict_find(d, (char_u *)"id", -1);
                if (di == NULL)
                    goto nextitem;
@@ -2927,16 +2933,9 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
            seq_nr = 0;
            if (d != NULL)
            {
-               // When looking for a response message from the LSP server,
-               // ignore new LSP request and notification messages.  LSP
-               // request and notification messages have the "method" field in
-               // the header and the response messages do not have this field.
-               if (!dict_has_key(d, "method"))
-               {
-                   di = dict_find(d, (char_u *)"id", -1);
-                   if (di != NULL && di->di_tv.v_type == VAR_NUMBER)
-                       seq_nr = di->di_tv.vval.v_number;
-               }
+               di = dict_find(d, (char_u *)"id", -1);
+               if (di != NULL && di->di_tv.v_type == VAR_NUMBER)
+                   seq_nr = di->di_tv.vval.v_number;
            }
 
            argv[1] = *listtv;
diff --git a/src/optionstr.c b/src/optionstr.c
index aeeab2789..5fceb8573 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -1858,7 +1858,7 @@ did_set_isopt(optset_T *args)
  * The 'jumpoptions' option is changed.
  */
     char *
-did_set_jumpoptions(optset_T *args)
+did_set_jumpoptions(optset_T *args UNUSED)
 {
     if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, TRUE) != OK)
        return e_invalid_argument;
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 5a3508324..edfd56e0b 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -2481,6 +2481,14 @@ endfunc
 " Test for the 'lsp' channel mode
 func LspCb(chan, msg)
   call add(g:lspNotif, a:msg)
+  if a:msg->has_key('method')
+    " Requests received from the LSP server
+    if a:msg['method'] == 'server-req-in-middle'
+          \ && a:msg['params']['text'] == 'server-req'
+      call ch_sendexpr(a:chan, #{method: 'server-req-in-middle-resp',
+            \ id: a:msg['id'], params: #{text: 'client-resp'}})
+    endif
+  endif
 endfunc
 
 func LspOtCb(chan, msg)
@@ -2652,6 +2660,19 @@ func LspTests(port)
   " send a ping to make sure communication still works
   call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
 
+  " Test for processing a request message from the server while the client
+  " is waiting for a response with the same identifier.
+  let g:lspNotif = []
+  let resp = ch_evalexpr(ch, #{method: 'server-req-in-middle',
+        \ params: #{text: 'client-req'}})
+  call assert_equal(#{jsonrpc: '2.0', id: 28,
+        \ result: #{text: 'server-resp'}}, resp)
+  call assert_equal([
+        \ #{id: -1, jsonrpc: '2.0', method: 'server-req-in-middle',
+        \   params: #{text: 'server-notif'}},
+        \ #{id: 28, jsonrpc: '2.0', method: 'server-req-in-middle',
+        \   params: #{text: 'server-req'}}], g:lspNotif)
+
   " Test for invoking an unsupported method
   let resp = ch_evalexpr(ch, #{method: 'xyz', params: {}}, #{timeout: 200})
   call assert_equal({}, resp)
diff --git a/src/testdir/test_channel_lsp.py b/src/testdir/test_channel_lsp.py
index eccb8937f..887f6974e 100644
--- a/src/testdir/test_channel_lsp.py
+++ b/src/testdir/test_channel_lsp.py
@@ -29,7 +29,20 @@ class 
ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
             with open("Xlspserver.log", "a") as myfile:
                 myfile.write(msg)
 
-    def send_lsp_msg(self, msgid, resp_dict):
+    def send_lsp_req(self, msgid, method, params):
+        v = {'jsonrpc': '2.0', 'id': msgid, 'method': method}
+        if len(params) != 0:
+            v['params'] = params
+        s = json.dumps(v)
+        req = "Content-Length: " + str(len(s)) + "
"
+        req += "Content-Type: application/vscode-jsonrpc; charset=utf-8
"
+        req += "
"
+        req += s
+        if self.debug:
+            self.debuglog("SEND: ({0} bytes) '{1}'
".format(len(req), req))
+        self.request.sendall(req.encode('utf-8'))
+
+    def send_lsp_resp(self, msgid, resp_dict):
         v = {'jsonrpc': '2.0', 'result': resp_dict}
         if msgid != -1:
             v['id'] = msgid
@@ -118,56 +131,56 @@ class 
ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
 
     def do_ping(self, payload):
         time.sleep(0.2)
-        self.send_lsp_msg(payload['id'], 'alive')
+        self.send_lsp_resp(payload['id'], 'alive')
 
     def do_echo(self, payload):
-        self.send_lsp_msg(-1, payload)
+        self.send_lsp_resp(-1, payload)
 
     def do_simple_rpc(self, payload):
         # test for a simple RPC request
-        self.send_lsp_msg(payload['id'], 'simple-rpc')
+        self.send_lsp_resp(payload['id'], 'simple-rpc')
 
     def do_rpc_with_notif(self, payload):
         # test for sending a notification before replying to a request message
-        self.send_lsp_msg(-1, 'rpc-with-notif-notif')
+        self.send_lsp_resp(-1, 'rpc-with-notif-notif')
         # sleep for some time to make sure the notification is delivered
         time.sleep(0.2)
-        self.send_lsp_msg(payload['id'], 'rpc-with-notif-resp')
+        self.send_lsp_resp(payload['id'], 'rpc-with-notif-resp')
 
     def do_wrong_payload(self, payload):
         # test for sending a non dict payload
         self.send_wrong_payload()
         time.sleep(0.2)
-        self.send_lsp_msg(-1, 'wrong-payload')
+        self.send_lsp_resp(-1, 'wrong-payload')
 
     def do_large_payload(self, payload):
         # test for sending a large (> 64K) payload
-        self.send_lsp_msg(payload['id'], payload)
+        self.send_lsp_resp(payload['id'], payload)
 
     def do_rpc_resp_incorrect_id(self, payload):
-        self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-1')
-        self.send_lsp_msg(-1, 'rpc-resp-incorrect-id-2')
-        self.send_lsp_msg(1, 'rpc-resp-incorrect-id-3')
+        self.send_lsp_resp(-1, 'rpc-resp-incorrect-id-1')
+        self.send_lsp_resp(-1, 'rpc-resp-incorrect-id-2')
+        self.send_lsp_resp(1, 'rpc-resp-incorrect-id-3')
         time.sleep(0.2)
-        self.send_lsp_msg(payload['id'], 'rpc-resp-incorrect-id-4')
+        self.send_lsp_resp(payload['id'], 'rpc-resp-incorrect-id-4')
 
     def do_simple_notif(self, payload):
         # notification message test
-        self.send_lsp_msg(-1, 'simple-notif')
+        self.send_lsp_resp(-1, 'simple-notif')
 
     def do_multi_notif(self, payload):
         # send multiple notifications
-        self.send_lsp_msg(-1, 'multi-notif1')
-        self.send_lsp_msg(-1, 'multi-notif2')
+        self.send_lsp_resp(-1, 'multi-notif1')
+        self.send_lsp_resp(-1, 'multi-notif2')
 
     def do_msg_with_id(self, payload):
-        self.send_lsp_msg(payload['id'], 'msg-with-id')
+        self.send_lsp_resp(payload['id'], 'msg-with-id')
 
     def do_msg_specific_cb(self, payload):
-        self.send_lsp_msg(payload['id'], 'msg-specific-cb')
+        self.send_lsp_resp(payload['id'], 'msg-specific-cb')
 
     def do_server_req(self, payload):
-        self.send_lsp_msg(201, {'method': 'checkhealth', 'params': {'a': 20}})
+        self.send_lsp_resp(201, {'method': 'checkhealth', 'params': {'a': 20}})
 
     def do_extra_hdr_fields(self, payload):
         self.send_extra_hdr_fields(payload['id'], 'extra-hdr-fields')
@@ -190,6 +203,19 @@ class 
ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
     def do_empty_payload(self, payload):
         self.send_empty_payload()
 
+    def do_server_req_in_middle(self, payload):
+        # Send a notification message to the client in the middle of processing
+        # a request message from the client
+        self.send_lsp_req(-1, 'server-req-in-middle', {'text': 'server-notif'})
+        # Send a request message to the client in the middle of processing a
+        # request message from the client.
+        self.send_lsp_req(payload['id'], 'server-req-in-middle', {'text': 
'server-req'})
+
+    def do_server_req_in_middle_resp(self, payload):
+        # After receiving a response from the client send the response to the
+        # client request.
+        self.send_lsp_resp(payload['id'], {'text': 'server-resp'})
+
     def process_msg(self, msg):
         try:
             decoded = json.loads(msg)
@@ -213,7 +239,9 @@ class 
ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
                         'hdr-with-wrong-len': self.do_hdr_with_wrong_len,
                         'hdr-with-negative-len': self.do_hdr_with_negative_len,
                         'empty-header': self.do_empty_header,
-                        'empty-payload': self.do_empty_payload
+                        'empty-payload': self.do_empty_payload,
+                        'server-req-in-middle': self.do_server_req_in_middle,
+                        'server-req-in-middle-resp': 
self.do_server_req_in_middle_resp,
                         }
                 if decoded['method'] in test_map:
                     test_map[decoded['method']](decoded)
diff --git a/src/version.c b/src/version.c
index c08894288..b5a44982b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1924,
 /**/
     1923,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qjKvS-0055bK-DA%40256bit.org.

Raspunde prin e-mail lui