import './symbol.vim'
import './codeaction.vim'
import './callhierarchy.vim' as callhier
-import './signature.vim'
# process the 'initialize' method reply from the LSP server
# Result: InitializeResult
endif
enddef
-# process the 'textDocument/signatureHelp' reply from the LSP server
-# Result: SignatureHelp | null
-def ProcessSignaturehelpReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
- if reply.result->empty()
- return
- endif
- signature.SignatureDisplay(lspserver, reply.result)
-enddef
-
# Map LSP complete item kind to a character
def LspCompleteItemKindChar(kind: number): string
var kindMap: list<string> = ['',
endif
enddef
-# process the 'textDocument/hover' reply from the LSP server
-# Result: Hover | null
-def ProcessHoverReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
- if reply.result->empty()
- return
- endif
-
- var hoverText: list<string>
- var hoverKind: string
-
- if reply.result.contents->type() == v:t_dict
- if reply.result.contents->has_key('kind')
- # MarkupContent
- if reply.result.contents.kind == 'plaintext'
- hoverText = reply.result.contents.value->split("\n")
- hoverKind = 'text'
- elseif reply.result.contents.kind == 'markdown'
- hoverText = reply.result.contents.value->split("\n")
- hoverKind = 'markdown'
- else
- util.ErrMsg($'Error: Unsupported hover contents type ({reply.result.contents.kind})')
- return
- endif
- elseif reply.result.contents->has_key('value')
- # MarkedString
- hoverText = reply.result.contents.value->split("\n")
- else
- util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})')
- return
- endif
- elseif reply.result.contents->type() == v:t_list
- # interface MarkedString[]
- for e in reply.result.contents
- if e->type() == v:t_string
- hoverText->extend(e->split("\n"))
- else
- hoverText->extend(e.value->split("\n"))
- endif
- endfor
- elseif reply.result.contents->type() == v:t_string
- if reply.result.contents->empty()
- return
- endif
- hoverText->extend(reply.result.contents->split("\n"))
- else
- util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})')
- return
- endif
- if opt.lspOptions.hoverInPreview
- silent! pedit HoverReply
- wincmd P
- setlocal buftype=nofile
- setlocal bufhidden=delete
- exe $'setlocal ft={hoverKind}'
- bufnr()->deletebufline(1, '$')
- append(0, hoverText)
- cursor(1, 1)
- wincmd p
- else
- hoverText->popup_atcursor({moved: 'word'})
- endif
-enddef
-
# process the 'textDocument/documentHighlight' reply from the LSP server
# Result: DocumentHighlight[] | null
def ProcessDocHighlightReply(lspserver: dict<any>, req: dict<any>, reply: dict<any>): void
var lsp_reply_handlers: dict<func> =
{
'initialize': ProcessInitializeReply,
- 'textDocument/signatureHelp': ProcessSignaturehelpReply,
'textDocument/completion': ProcessCompletionReply,
'completionItem/resolve': ProcessResolveReply,
- 'textDocument/hover': ProcessHoverReply,
'textDocument/documentHighlight': ProcessDocHighlightReply,
'textDocument/documentSymbol': ProcessDocSymbolReply,
'textDocument/codeAction': ProcessCodeActionReply,
--- /dev/null
+vim9script
+
+# Functions related to displaying hover symbol information.
+
+import './util.vim'
+import './options.vim' as opt
+
+# process the 'textDocument/hover' reply from the LSP server
+# Result: Hover | null
+export def HoverReply(lspserver: dict<any>, _: any, reply: dict<any>): void
+ if !util.SanitizeReply('textDocument/hover', reply)
+ return
+ endif
+
+ var hoverText: list<string>
+ var hoverKind: string
+
+ if reply.result.contents->type() == v:t_dict
+ if reply.result.contents->has_key('kind')
+ # MarkupContent
+ if reply.result.contents.kind == 'plaintext'
+ hoverText = reply.result.contents.value->split("\n")
+ hoverKind = 'text'
+ elseif reply.result.contents.kind == 'markdown'
+ hoverText = reply.result.contents.value->split("\n")
+ hoverKind = 'markdown'
+ else
+ util.ErrMsg($'Error: Unsupported hover contents type ({reply.result.contents.kind})')
+ return
+ endif
+ elseif reply.result.contents->has_key('value')
+ # MarkedString
+ hoverText = reply.result.contents.value->split("\n")
+ else
+ util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})')
+ return
+ endif
+ elseif reply.result.contents->type() == v:t_list
+ # interface MarkedString[]
+ for e in reply.result.contents
+ if e->type() == v:t_string
+ hoverText->extend(e->split("\n"))
+ else
+ hoverText->extend(e.value->split("\n"))
+ endif
+ endfor
+ elseif reply.result.contents->type() == v:t_string
+ if reply.result.contents->empty()
+ return
+ endif
+ hoverText->extend(reply.result.contents->split("\n"))
+ else
+ util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})')
+ return
+ endif
+
+ if opt.lspOptions.hoverInPreview
+ silent! pedit LspHoverReply
+ wincmd P
+ setlocal buftype=nofile
+ setlocal bufhidden=delete
+ exe $'setlocal ft={hoverKind}'
+ bufnr()->deletebufline(1, '$')
+ append(0, hoverText)
+ cursor(1, 1)
+ wincmd p
+ else
+ hoverText->popup_atcursor({moved: 'word'})
+ endif
+enddef
+
+# vim: tabstop=8 shiftwidth=2 softtabstop=2
# Refer to https://microsoft.github.io/language-server-protocol/specification
# for the Language Server Protocol (LSP) specificaiton.
+import './options.vim' as opt
import './handlers.vim'
import './util.vim'
import './diag.vim'
import './selection.vim'
import './symbol.vim'
import './textedit.vim'
+import './hover.vim'
+import './signature.vim'
import './callhierarchy.vim' as callhier
# LSP server standard output handler
completionItem: {
documentationFormat: ['plaintext', 'markdown'],
resolveSupport: {properties: ['detail', 'documentation']},
- snippetSupport: false
+ snippetSupport: true
},
completionItemKind: {valueSet: range(1, 25)}
},
# Send a sync RPC request message to the LSP server and return the received
# reply. In case of an error, an empty Dict is returned.
-def RpcCall(lspserver: dict<any>, method: string, params: any): dict<any>
+def Rpc(lspserver: dict<any>, method: string, params: any): dict<any>
var req = {}
req.method = method
req.params = {}
return {}
enddef
+# Send a async RPC request message to the LSP server with a callback function.
+def AsyncRpc(lspserver: dict<any>, method: string, params: any, Cbfunc: func): number
+ 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 -1
+ endif
+
+ var reply = ch->ch_sendexpr(req, {callback: Cbfunc})
+ if reply->empty()
+ return -1
+ endif
+
+ return reply.id
+enddef
+
# Wait for a response message from the LSP server for the request "req"
# Waits for a maximum of 5 seconds
def WaitForResponse(lspserver: dict<any>, req: dict<any>)
req.params.context = {triggerKind: triggerKind_arg, triggerCharacter: triggerChar}
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
req.params = item
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
return
endif
- var req = lspserver.createRequest('textDocument/signatureHelp')
# interface SignatureHelpParams
# interface TextDocumentPositionParams
- req.params->extend(GetLspTextDocPosition())
-
- lspserver.sendMessage(req)
-
- if exists('g:LSPTest') && g:LSPTest
+ var params = GetLspTextDocPosition()
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
- lspserver.waitForResponse(req)
+ var reply = lspserver.rpc('textDocument/signatureHelp', params)
+ signature.SignatureHelp(lspserver, 0, reply)
+ else
+ lspserver.rpc_a('textDocument/signatureHelp', params,
+ function(signature.SignatureHelp, [lspserver]))
endif
enddef
return
endif
- var req = lspserver.createRequest('textDocument/hover')
# interface HoverParams
# interface TextDocumentPositionParams
- req.params->extend(GetLspTextDocPosition())
- lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ var params = GetLspTextDocPosition()
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
- lspserver.waitForResponse(req)
+ var reply = lspserver.rpc('textDocument/hover', params)
+ hover.HoverReply(lspserver, 0, reply)
+ else
+ lspserver.rpc_a('textDocument/hover', params,
+ function(hover.HoverReply, [lspserver]))
endif
enddef
# interface TextDocumentPositionParams
req.params->extend(GetLspTextDocPosition())
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
# interface TextDocumentIdentifier
req.params->extend({textDocument: {uri: util.LspFileToUri(fname)}})
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
req.params->extend({context: {diagnostics: d}})
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
# interface TextDocumentIdentifier
req.params->extend({textDocument: {uri: util.LspFileToUri(fname)}})
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
var req = lspserver.createRequest('workspace/executeCommand')
req.params->extend(cmd)
lspserver.sendMessage(req)
- if exists('g:LSPTest') && g:LSPTest
+ if get(g:, 'LSPTest')
# When running LSP tests, make this a synchronous call
lspserver.waitForResponse(req)
endif
createNotification: function(CreateNotification, [lspserver]),
sendResponse: function(SendResponse, [lspserver]),
sendMessage: function(SendMessage, [lspserver]),
- rpc: function(RpcCall, [lspserver]),
+ rpc: function(Rpc, [lspserver]),
+ rpc_a: function(AsyncRpc, [lspserver]),
waitForResponse: function(WaitForResponse, [lspserver]),
processReply: function(handlers.ProcessReply, [lspserver]),
processNotif: function(handlers.ProcessNotif, [lspserver]),
autocmd InsertLeave <buffer> call CloseCurBufSignaturePopup()
enddef
-# Display the symbol signature help
-export def SignatureDisplay(lspserver: dict<any>, sighelp: dict<any>): void
+# process the 'textDocument/signatureHelp' reply from the LSP server and
+# display the symbol signature help.
+# Result: SignatureHelp | null
+export def SignatureHelp(lspserver: dict<any>, _: any, reply: dict<any>): void
+ if !util.SanitizeReply('textDocument/signatureHelp', reply)
+ return
+ endif
+
+ var sighelp: dict<any> = reply.result
if sighelp->empty()
CloseSignaturePopup(lspserver)
return
}]}, 't')
enddef
+export def SanitizeReply(reqmsg: string, reply: dict<any>): bool
+ if reply->empty()
+ return false
+ endif
+
+ if reply->has_key('error')
+ # request failed
+ var emsg: string
+ emsg = $'{reply.error.message}, code = {reply.error.code}'
+ if reply.error->has_key('data')
+ emsg ..= $', data = {reply.error.data->string()}'
+ endif
+ ErrMsg($'Error(LSP): request {reqmsg} failed ({emsg})')
+ return false
+ endif
+
+ if reply.result->empty()
+ return false
+ endif
+
+ return true
+enddef
+
# vim: tabstop=8 shiftwidth=2 softtabstop=2