var msg: dict<any>
var req: dict<any>
- while lspserver.data->len() > 0
- idx = stridx(lspserver.data, 'Content-Length: ')
- if idx == -1
- return
- endif
-
- if stridx(lspserver.data, "\r\n", idx + 16) == -1
- # not enough data is received. Wait for more data to arrive
- return
- endif
-
- len = str2nr(lspserver.data[idx + 16 : ])
- if len == 0
- util.ErrMsg("Error(LSP): Invalid content length")
- # Discard the header
- lspserver.data = lspserver.data[idx + 16 :]
- return
- endif
-
- # Header and contents are separated by '\r\n\r\n'
- idx = stridx(lspserver.data, "\r\n\r\n", idx + 16)
- if idx == -1
- # content separator is not found. Wait for more data to arrive.
- return
- endif
-
- # skip the separator
- idx = idx + 4
-
- if lspserver.data->len() - idx < len
- # message is not fully received. Process the message after more data is
- # received
- return
- endif
-
- content = lspserver.data[idx : idx + len - 1]
- try
- msg = content->json_decode()
- catch
- util.ErrMsg($'Error(LSP): Malformed content ({content})')
- lspserver.data = lspserver.data[idx + len :]
- continue
- endtry
-
- if msg->has_key('result') || msg->has_key('error')
- # response message from the server
- req = lspserver.requests->get(msg.id->string(), {})
- if !req->empty()
- # Remove the corresponding stored request message
- lspserver.requests->remove(msg.id->string())
-
- if msg->has_key('result')
- lspserver.processReply(req, msg)
- else
- # request failed
- var emsg: string = msg.error.message
- emsg ..= $', code = {msg.error.code}'
- if msg.error->has_key('data')
- emsg = $'{emsg}, data = {msg.error.data->string()}'
- endif
- util.ErrMsg($'Error(LSP): request {req.method} failed ({emsg})')
+ msg = lspserver.data
+ if msg->has_key('result') || msg->has_key('error')
+ # response message from the server
+ req = lspserver.requests->get(msg.id->string(), {})
+ if !req->empty()
+ # Remove the corresponding stored request message
+ lspserver.requests->remove(msg.id->string())
+
+ if msg->has_key('result')
+ lspserver.processReply(req, msg)
+ else
+ # request failed
+ var emsg: string = msg.error.message
+ emsg ..= ', code = ' .. msg.error.code
+ if msg.error->has_key('data')
+ emsg = emsg .. ', data = ' .. msg.error.data->string()
endif
+ util.ErrMsg($'Error(LSP): request {req.method} failed ({emsg})')
endif
- elseif msg->has_key('id') && msg->has_key('method')
- # request message from the server
- lspserver.processRequest(msg)
- elseif msg->has_key('method')
- # notification message from the server
- lspserver.processNotif(msg)
- else
- util.ErrMsg($'Error(LSP): Unsupported message ({msg->string()})')
endif
-
- lspserver.data = lspserver.data[idx + len :]
- endwhile
+ elseif msg->has_key('id') && msg->has_key('method')
+ # request message from the server
+ lspserver.processRequest(msg)
+ elseif msg->has_key('method')
+ # notification message from the server
+ lspserver.processNotif(msg)
+ else
+ util.ErrMsg($'Error(LSP): Unsupported message ({msg->string()})')
+ endif
enddef
# vim: shiftwidth=2 softtabstop=2
import './selection.vim'
# LSP server standard output handler
-def Output_cb(lspserver: dict<any>, chan: channel, msg: string): void
- util.TraceLog(false, msg)
- lspserver.data = lspserver.data .. msg
+def Output_cb(lspserver: dict<any>, chan: channel, msg: any): void
+ util.TraceLog(false, msg->string())
+ lspserver.data = msg
lspserver.processMessages()
enddef
var cmd = [lspserver.path]
cmd->extend(lspserver.args)
- var opts = {in_mode: 'raw',
- out_mode: 'raw',
+ var opts = {in_mode: 'lsp',
+ out_mode: 'lsp',
err_mode: 'raw',
noblock: 1,
out_cb: function(Output_cb, [lspserver]),
# Send a request message to LSP server
def SendMessage(lspserver: dict<any>, content: dict<any>): void
- var payload_js: string = content->json_encode()
- var msg = $"Content-Length: {payload_js->len()}\r\n\r\n"
var ch = lspserver.job->job_getchannel()
if ch_status(ch) != 'open'
# LSP server has exited
return
endif
- ch->ch_sendraw(msg)
- ch->ch_sendraw(payload_js)
+ ch->ch_sendexpr(content)
+enddef
+
+# Send a RPC request message to LSP server
+def RpcCall(lspserver: dict<any>, method: string, params: any): dict<any>
+ var req = {}
+ req.method = method
+ req.params = {}
+ req.params->extend(params)
+
+ var ch = lspserver.job->job_getchannel()
+ if ch_status(ch) != 'open'
+ # LSP server has exited
+ return {}
+ endif
+ return ch->ch_evalexpr(req)
enddef
# Wait for a response message from the LSP server for the request "req"
createNotification: function(CreateNotification, [lspserver]),
sendResponse: function(SendResponse, [lspserver]),
sendMessage: function(SendMessage, [lspserver]),
+ rpc: function(RpcCall, [lspserver]),
waitForResponse: function(WaitForResponse, [lspserver]),
processReply: function(handlers.ProcessReply, [lspserver]),
processNotif: function(handlers.ProcessNotif, [lspserver]),