Skip to content

Commit 9247a22

Browse files
yegappanbrammool
authored andcommitted
patch 8.2.4648: handling LSP messages is a bit slow
Problem: Handling LSP messages is a bit slow. Solution: Included support for LSP messages. (Yegappan Lakshmanan, closes #10025)
1 parent 2bdad61 commit 9247a22

File tree

9 files changed

+884
-49
lines changed

9 files changed

+884
-49
lines changed

runtime/doc/channel.txt

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ RAW nothing known, Vim cannot tell where a message ends
5353
NL every message ends in a NL (newline) character
5454
JSON JSON encoding |json_encode()|
5555
JS JavaScript style JSON-like encoding |js_encode()|
56+
LSP Language Server Protocol encoding |language-server-protocol|
5657

5758
Common combination are:
5859
- Using a job connected through pipes in NL mode. E.g., to run a style
@@ -130,6 +131,7 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
130131
"js" - Use JS (JavaScript) encoding, more efficient than JSON.
131132
"nl" - Use messages that end in a NL character
132133
"raw" - Use raw messages
134+
"lsp" - Use language server protocol encoding
133135
*channel-callback* *E921*
134136
"callback" A function that is called when a message is received that is
135137
not handled otherwise (e.g. a JSON message with ID zero). It
@@ -140,8 +142,8 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
140142
endfunc
141143
let channel = ch_open("localhost:8765", {"callback": "Handle"})
142144
<
143-
When "mode" is "json" or "js" the "msg" argument is the body
144-
of the received message, converted to Vim types.
145+
When "mode" is "json" or "js" or "lsp" the "msg" argument is
146+
the body of the received message, converted to Vim types.
145147
When "mode" is "nl" the "msg" argument is one message,
146148
excluding the NL.
147149
When "mode" is "raw" the "msg" argument is the whole message
@@ -165,7 +167,19 @@ When using an IPv6 address, enclose it within square brackets. E.g.,
165167
to check for messages, the close_cb may be invoked while still
166168
in the callback. The plugin must handle this somehow, it can
167169
be useful to know that no more data is coming.
168-
*channel-drop*
170+
If it is not known if there is a message to be read, use a
171+
try/catch block: >
172+
try
173+
let msg = ch_readraw(a:channel)
174+
catch
175+
let msg = 'no message'
176+
endtry
177+
try
178+
let err = ch_readraw(a:channel, #{part: 'err'})
179+
catch
180+
let err = 'no error'
181+
endtry
182+
< *channel-drop*
169183
"drop" Specifies when to drop messages:
170184
"auto" When there is no callback to handle a message.
171185
The "close_cb" is also considered for this.
@@ -443,7 +457,7 @@ to check if there is something to read.
443457
Note that when there is no callback, messages are dropped. To avoid that add
444458
a close callback to the channel.
445459

446-
To read all output from a RAW channel that is available: >
460+
To read all normal output from a RAW channel that is available: >
447461
let output = ch_readraw(channel)
448462
To read the error output: >
449463
let output = ch_readraw(channel, {"part": "err"})
@@ -503,6 +517,7 @@ ch_evalexpr({handle}, {expr} [, {options}]) *ch_evalexpr()*
503517
according to the type of channel. The function cannot be used
504518
with a raw channel. See |channel-use|.
505519
{handle} can be a Channel or a Job that has a Channel.
520+
When using the "lsp" channel mode, {expr} must be a |Dict|.
506521
*E917*
507522
{options} must be a Dictionary. It must not have a "callback"
508523
entry. It can have a "timeout" entry to specify the timeout
@@ -578,7 +593,7 @@ ch_info({handle}) *ch_info()*
578593
"err_io" "out", "null", "pipe", "file" or "buffer"
579594
"err_timeout" timeout in msec
580595
"in_status" "open" or "closed"
581-
"in_mode" "NL", "RAW", "JSON" or "JS"
596+
"in_mode" "NL", "RAW", "JSON", "JS" or "LSP"
582597
"in_io" "null", "pipe", "file" or "buffer"
583598
"in_timeout" timeout in msec
584599

@@ -674,6 +689,7 @@ ch_sendexpr({handle}, {expr} [, {options}]) *ch_sendexpr()*
674689
with a raw channel.
675690
See |channel-use|. *E912*
676691
{handle} can be a Channel or a Job that has a Channel.
692+
When using the "lsp" channel mode, {expr} must be a |Dict|.
677693

678694
Can also be used as a |method|: >
679695
GetChannel()->ch_sendexpr(expr)
@@ -1361,5 +1377,76 @@ The same in |Vim9| script: >
13611377
# start accepting shell commands
13621378
startinsert
13631379
1380+
==============================================================================
1381+
14. Language Server Protocol *language-server-protocol*
1382+
1383+
The language server protocol specification is available at:
1384+
1385+
https://microsoft.github.io/language-server-protocol/specification
1386+
1387+
Each LSP protocol message starts with a simple HTTP header followed by the
1388+
payload encoded in JSON-RPC format. This is described in:
1389+
1390+
https://www.jsonrpc.org/specification
1391+
1392+
For messages received on a channel with mode set to "lsp", Vim will process
1393+
the HTTP header and decode the payload into a Vim |Dict| type and call the
1394+
channel callback or the specified callback function. When sending messages on
1395+
a channel using |ch_evalexpr()| or |ch_sendexpr()|, Vim will add the HTTP
1396+
header and encode the Vim expression into JSON-RPC.
1397+
1398+
To open a channel using the 'lsp' mode, set the 'mode' item in the |ch_open()|
1399+
{options} argument to 'lsp'. Example: >
1400+
1401+
let ch = ch_open(..., #{mode: 'lsp'})
1402+
1403+
To open a channel using the 'lsp' mode with a job, set the 'in_mode' and
1404+
'out_mode' items in the |job_start()| {options} argument to 'lsp'. Example: >
1405+
1406+
let job = job_start(...., #{in_mode: 'lsp', out_mode: 'lsp'})
1407+
1408+
To synchronously send a JSON-RPC request to the server, use the |ch_evalexpr()|
1409+
function. This function will return the response from the server. You can use
1410+
the 'timeout' field in the {options} argument to control the response wait
1411+
time. Example: >
1412+
1413+
let req = {}
1414+
let req.method = 'textDocument/definition'
1415+
let req.params = {}
1416+
let req.params.textDocument = #{uri: 'a.c'}
1417+
let req.params.position = #{line: 10, character: 3}
1418+
let resp = ch_evalexpr(ch, req, #{timeout: 100})
1419+
1420+
Note that in the request message the 'id' field should not be specified. If it
1421+
is specified, then Vim will overwrite the value with an internally generated
1422+
identifier. Vim currently supports only a number type for the 'id' field.
1423+
1424+
To send a JSON-RPC request to the server and asynchronously process the
1425+
response, use the |ch_sendexpr()| function and supply a callback function.
1426+
Example: >
1427+
1428+
let req = {}
1429+
let req.method = 'textDocument/hover'
1430+
let req.params = {}
1431+
let req.params.textDocument = #{uri: 'a.c'}
1432+
let req.params.position = #{line: 10, character: 3}
1433+
let resp = ch_sendexpr(ch, req, #{callback: 'MyFn'})
1434+
1435+
To send a JSON-RPC notification message to the server, use the |ch_sendexpr()|
1436+
function. Example: >
1437+
1438+
call ch_sendexpr(ch, #{method: 'initialized'})
1439+
1440+
To respond to a JSON-RPC request message from the server, use the
1441+
|ch_sendexpr()| function. In the response message, copy the 'id' field value
1442+
from the server request message. Example: >
1443+
1444+
let resp = {}
1445+
let resp.id = req.id
1446+
let resp.result = 1
1447+
call ch_sendexpr(ch, resp)
1448+
1449+
The JSON-RPC notification messages from the server are delivered through the
1450+
|channel-callback| function.
13641451

13651452
vim:tw=78:ts=8:noet:ft=help:norl:

0 commit comments

Comments
 (0)