{
// JSON or JS or LSP mode: invoke the one-time callback with the
// matching nr
- for (cbitem = cbhead->cq_next; cbitem != NULL; cbitem = cbitem->cq_next)
- if (cbitem->cq_seq_nr == seq_nr)
+ int lsp_req_msg = FALSE;
+
+ // Don't use a LSP server request message with the same sequence number
+ // as the client request message as the response message.
+ if (ch_mode == CH_MODE_LSP && argv[1].v_type == VAR_DICT
+ && dict_has_key(argv[1].vval.v_dict, "method"))
+ lsp_req_msg = TRUE;
+
+ if (!lsp_req_msg)
+ {
+ for (cbitem = cbhead->cq_next; cbitem != NULL;
+ cbitem = cbitem->cq_next)
{
- invoke_one_time_callback(channel, cbhead, cbitem, argv);
- called_otc = TRUE;
- break;
+ if (cbitem->cq_seq_nr == seq_nr)
+ {
+ invoke_one_time_callback(channel, cbhead, cbitem, argv);
+ called_otc = TRUE;
+ break;
+ }
}
+ }
}
if (seq_nr > 0 && (ch_mode != CH_MODE_LSP || called_otc))
call assert_fails('call job_start([0zff])', 'E976:')
endfunc
-" Test for the 'lsp' channel mode
+" Process requests received from the LSP server
+func LspProcessServerRequests(chan, msg)
+ 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
+endfunc
+
+" LSP channel message callback function
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
+ call LspProcessServerRequests(a:chan, a:msg)
endif
endfunc
+" LSP one-time message callback function (used for ch_sendexpr())
func LspOtCb(chan, msg)
call add(g:lspOtMsgs, a:msg)
+ if a:msg->has_key('method')
+ call LspProcessServerRequests(a:chan, a:msg)
+ endif
endfunc
+" Test for the 'lsp' channel mode
func LspTests(port)
" call ch_logfile('Xlspclient.log', 'w')
let ch = ch_open(s:localhost .. a:port, #{mode: 'lsp', callback: 'LspCb'})
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.
+ " is waiting for a response with the same identifier (sync-rpc)
let g:lspNotif = []
let resp = ch_evalexpr(ch, #{method: 'server-req-in-middle',
\ params: #{text: 'client-req'}})
\ #{id: 28, jsonrpc: '2.0', method: 'server-req-in-middle',
\ params: #{text: 'server-req'}}], g:lspNotif)
+ " Test for processing a request message from the server while the client
+ " is waiting for a response with the same identifier (async-rpc using the
+ " channel callback function)
+ let g:lspNotif = []
+ call ch_sendexpr(ch, #{method: 'server-req-in-middle', id: 500,
+ \ params: #{text: 'client-req'}})
+ " Send three pings to wait for all the notification messages to arrive
+ for i in range(3)
+ call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
+ endfor
+ call assert_equal([
+ \ #{id: -1, jsonrpc: '2.0', method: 'server-req-in-middle',
+ \ params: #{text: 'server-notif'}},
+ \ #{id: 500, jsonrpc: '2.0', method: 'server-req-in-middle',
+ \ params: #{text: 'server-req'}},
+ \ #{id: 500, jsonrpc: '2.0', result: #{text: 'server-resp'}}
+ \ ], g:lspNotif)
+
+ " Test for processing a request message from the server while the client
+ " is waiting for a response with the same identifier (async-rpc using a
+ " one-time callback function)
+ let g:lspNotif = []
+ let g:lspOtMsgs = []
+ call ch_sendexpr(ch, #{method: 'server-req-in-middle',
+ \ params: #{text: 'client-req'}}, #{callback: 'LspOtCb'})
+ " Send a ping to wait for all the notification messages to arrive
+ for i in range(3)
+ call assert_equal('alive', ch_evalexpr(ch, #{method: 'ping'}).result)
+ endfor
+ call assert_equal([
+ \ #{id: 32, jsonrpc: '2.0', result: #{text: 'server-resp'}}],
+ \ g:lspOtMsgs)
+ call assert_equal([
+ \ #{id: -1, jsonrpc: '2.0', method: 'server-req-in-middle',
+ \ params: #{text: 'server-notif'}},
+ \ #{id: 32, 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)