From: Yegappan Lakshmanan Date: Fri, 28 Oct 2022 15:29:11 +0000 (-0700) Subject: Snipper support is set to true for completion matches (by mistake). Include plugin... X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=a54fa00a4e13ede6c19b03ecfe1a988f415ed094;p=vim-lsp.git Snipper support is set to true for completion matches (by mistake). Include plugin debug information in the help text. Add debug messages for async RPC calls. Cleanup async RPC APIs --- diff --git a/autoload/lsp/hover.vim b/autoload/lsp/hover.vim index ab6ab8d..7119aab 100644 --- a/autoload/lsp/hover.vim +++ b/autoload/lsp/hover.vim @@ -7,50 +7,50 @@ import './options.vim' as opt # process the 'textDocument/hover' reply from the LSP server # Result: Hover | null -export def HoverReply(lspserver: dict, _: any, reply: dict): void - if !util.SanitizeReply('textDocument/hover', reply) +export def HoverReply(lspserver: dict, hoverResult: any): void + if hoverResult->empty() return endif var hoverText: list var hoverKind: string - if reply.result.contents->type() == v:t_dict - if reply.result.contents->has_key('kind') + if hoverResult.contents->type() == v:t_dict + if hoverResult.contents->has_key('kind') # MarkupContent - if reply.result.contents.kind == 'plaintext' - hoverText = reply.result.contents.value->split("\n") + if hoverResult.contents.kind == 'plaintext' + hoverText = hoverResult.contents.value->split("\n") hoverKind = 'text' - elseif reply.result.contents.kind == 'markdown' - hoverText = reply.result.contents.value->split("\n") + elseif hoverResult.contents.kind == 'markdown' + hoverText = hoverResult.contents.value->split("\n") hoverKind = 'markdown' else - util.ErrMsg($'Error: Unsupported hover contents type ({reply.result.contents.kind})') + util.ErrMsg($'Error: Unsupported hover contents type ({hoverResult.contents.kind})') return endif - elseif reply.result.contents->has_key('value') + elseif hoverResult.contents->has_key('value') # MarkedString - hoverText = reply.result.contents.value->split("\n") + hoverText = hoverResult.contents.value->split("\n") else - util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})') + util.ErrMsg($'Error: Unsupported hover contents ({hoverResult.contents})') return endif - elseif reply.result.contents->type() == v:t_list + elseif hoverResult.contents->type() == v:t_list # interface MarkedString[] - for e in reply.result.contents + for e in hoverResult.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() + elseif hoverResult.contents->type() == v:t_string + if hoverResult.contents->empty() return endif - hoverText->extend(reply.result.contents->split("\n")) + hoverText->extend(hoverResult.contents->split("\n")) else - util.ErrMsg($'Error: Unsupported hover contents ({reply.result.contents})') + util.ErrMsg($'Error: Unsupported hover contents ({hoverResult.contents})') return endif diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 23ae46a..373ff05 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -92,9 +92,19 @@ def LspOmniComplSet(ftype: string, enabled: bool) ftypeOmniCtrlMap->extend({[ftype]: enabled}) enddef -export def EnableServerTrace() - util.ClearTraceLogs() - util.ServerTrace(true) +# Enable/disable the logging of the language server protocol messages +export def ServerDebug(arg: string) + if arg !=? 'on' && arg !=? 'off' + util.ErrMsg($'Error: Invalid argument ("{arg}") for LSP server debug') + return + endif + + if arg ==? 'on' + util.ClearTraceLogs() + util.ServerTrace(true) + else + util.ServerTrace(false) + endif enddef # Show information about all the LSP servers @@ -491,7 +501,7 @@ enddef # set the LSP server trace level for the current buffer # Params: SetTraceParams -export def SetTraceServer(traceVal: string) +export def ServerTraceSet(traceVal: string) if ['off', 'messages', 'verbose']->index(traceVal) == -1 util.ErrMsg($'Error: Unsupported LSP server trace value {traceVal}') return diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index 0f82878..6ef13f6 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -17,7 +17,7 @@ import './callhierarchy.vim' as callhier # LSP server standard output handler def Output_cb(lspserver: dict, chan: channel, msg: any): void - util.TraceLog(false, $'Received: {msg->string()}') + util.TraceLog(false, $'Received [{strftime("%m/%d/%y %T")}]: {msg->string()}') lspserver.data = msg lspserver.processMessages() enddef @@ -99,7 +99,7 @@ def InitServer(lspserver: dict) completionItem: { documentationFormat: ['plaintext', 'markdown'], resolveSupport: {properties: ['detail', 'documentation']}, - snippetSupport: true + snippetSupport: false }, completionItemKind: {valueSet: range(1, 25)} }, @@ -265,7 +265,7 @@ def SendMessage(lspserver: dict, content: dict): void endif ch->ch_sendexpr(content) if content->has_key('id') - util.TraceLog(false, $'Sent: {content->string()}') + util.TraceLog(false, $'Sent [{strftime("%m/%d/%y %T")}]: {content->string()}') endif enddef @@ -283,8 +283,13 @@ def Rpc(lspserver: dict, method: string, params: any): dict return {} endif + util.TraceLog(false, $'Sent [{strftime("%m/%d/%y %T")}]: {req->string()}') + + # Do the synchronous RPC call var reply = ch->ch_evalexpr(req) + util.TraceLog(false, $'Received [{strftime("%m/%d/%y %T")}]: {reply->string()}') + if reply->has_key('result') # successful reply return reply @@ -303,7 +308,31 @@ def Rpc(lspserver: dict, method: string, params: any): dict return {} enddef +# LSP server asynchronous RPC callback +def AsyncRpcCb(lspserver: dict, method: string, RpcCb: func, chan: channel, reply: dict) + util.TraceLog(false, $'Received [{strftime("%m/%d/%y %T")}]: {reply->string()}') + + if reply->empty() + return + 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 + util.ErrMsg($'Error(LSP): request {method} failed ({emsg})') + return + endif + + RpcCb(lspserver, reply.result) +enddef + # Send a async RPC request message to the LSP server with a callback function. +# Returns the LSP message id. This id can be used to cancel the RPC request +# (if needed). Returns -1 on error. def AsyncRpc(lspserver: dict, method: string, params: any, Cbfunc: func): number var req = {} req.method = method @@ -316,7 +345,20 @@ def AsyncRpc(lspserver: dict, method: string, params: any, Cbfunc: func): n return -1 endif - var reply = ch->ch_sendexpr(req, {callback: Cbfunc}) + util.TraceLog(false, $'Sent [{strftime("%m/%d/%y %T")}]: {req->string()}') + + # Do the asynchronous RPC call + var Fn = function('AsyncRpcCb', [lspserver, method, Cbfunc]) + + var reply: dict + if get(g:, 'LSPTest') + # When running LSP tests, make this a synchronous RPC call + reply = Rpc(lspserver, method, params) + Fn(test_null_channel(), reply) + else + # Otherwise, make an asynchronous RPC call + reply = ch->ch_sendexpr(req, {callback: Fn}) + endif if reply->empty() return -1 endif @@ -643,14 +685,8 @@ def ShowSignature(lspserver: dict): void # interface SignatureHelpParams # interface TextDocumentPositionParams var params = GetLspTextDocPosition() - if get(g:, 'LSPTest') - # When running LSP tests, make this a synchronous call - var reply = lspserver.rpc('textDocument/signatureHelp', params) - signature.SignatureHelp(lspserver, 0, reply) - else - lspserver.rpc_a('textDocument/signatureHelp', params, - function(signature.SignatureHelp, [lspserver])) - endif + lspserver.rpc_a('textDocument/signatureHelp', params, + signature.SignatureHelp) enddef def DidSaveFile(lspserver: dict, bnr: number): void @@ -682,14 +718,7 @@ def ShowHoverInfo(lspserver: dict): void # interface HoverParams # interface TextDocumentPositionParams var params = GetLspTextDocPosition() - if get(g:, 'LSPTest') - # When running LSP tests, make this a synchronous call - var reply = lspserver.rpc('textDocument/hover', params) - hover.HoverReply(lspserver, 0, reply) - else - lspserver.rpc_a('textDocument/hover', params, - function(hover.HoverReply, [lspserver])) - endif + lspserver.rpc_a('textDocument/hover', params, hover.HoverReply) enddef # Request: "textDocument/references" diff --git a/autoload/lsp/signature.vim b/autoload/lsp/signature.vim index 9acecb8..c5c0c84 100644 --- a/autoload/lsp/signature.vim +++ b/autoload/lsp/signature.vim @@ -41,12 +41,7 @@ enddef # process the 'textDocument/signatureHelp' reply from the LSP server and # display the symbol signature help. # Result: SignatureHelp | null -export def SignatureHelp(lspserver: dict, _: any, reply: dict): void - if !util.SanitizeReply('textDocument/signatureHelp', reply) - return - endif - - var sighelp: dict = reply.result +export def SignatureHelp(lspserver: dict, sighelp: any): void if sighelp->empty() CloseSignaturePopup(lspserver) return diff --git a/autoload/lsp/util.vim b/autoload/lsp/util.vim index a567cbc..25701e3 100644 --- a/autoload/lsp/util.vim +++ b/autoload/lsp/util.vim @@ -35,9 +35,9 @@ export def TraceLog(stderr: bool, msg: string) return endif if stderr - writefile(split(msg, "\n"), $'{lsp_log_dir}lsp_server.err', 'a') + writefile(msg->split("\n"), $'{lsp_log_dir}lsp_server.err', 'a') else - writefile(split(msg, "\n"), $'{lsp_log_dir}lsp_server.out', 'a') + writefile([msg], $'{lsp_log_dir}lsp_server.out', 'a') endif enddef @@ -151,27 +151,4 @@ export def PushCursorToTagStack() }]}, 't') enddef -export def SanitizeReply(reqmsg: string, reply: dict): 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 diff --git a/doc/lsp.txt b/doc/lsp.txt index c837964..71bbdc6 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -711,4 +711,36 @@ LspDiagsUpdated A |User| autocommand invoked when new server. This is invoked after the LSP client has processed the diagnostics. +============================================================================== +10. Debugging *lsp-debug* + +To debug this plugin, you can log the language server protocol messages sent +and received by the plugin from the language server. The following command +enables the logging of the messages: > + + :LspServerDebug on +< +This command also clears the log files. The following command disables the +logging of the messages: > + + :LspServerDebug off +< +By default, the messages are not logged. + +The messages printed by the LSP server in the stdout are logged to the +lsp_server.out file and the messages printed in the stderr are logged to the +lsp_server.err file. On a Unix-like system, these files are created in the +/tmp directory. On MS-Windows, these files are created in the %TEMP% +directory. + +The language servers typically support command line options to enable debug +messages and to increase the verbosity of the messages. You can refer to the +language server documentation for information about this. You can include +these options when registering the LSP server with this plugin. + +If a language server supports the "$/logTrace" LSP notification, then you can +use the :LspServerTrace command to set the trace value: > + + :LspServerTrace { off | messages | verbose } +< vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 635328c..c9a15a7 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -14,10 +14,6 @@ def g:LspOptionsSet(opts: dict) options.OptionsSet(opts) enddef -def g:LspServerTraceEnable() - lsp.EnableServerTrace() -enddef - def g:LspAddServer(serverList: list>) lsp.AddServer(serverList) enddef @@ -40,6 +36,16 @@ def LspServerTraceComplete(arglead: string, cmdline: string, cursorpos: number): endif enddef +# Command line completion function for the LspSetTrace command. +def LspServerDebugComplete(arglead: string, cmdline: string, cursorpos: number): list + var l = ['off', 'on'] + if arglead->empty() + return l + else + return filter(l, (_, val) => val =~ arglead) + endif +enddef + augroup LSPAutoCmds au! autocmd BufNewFile,BufReadPost * lsp.AddFile(expand('')->str2nr()) @@ -59,7 +65,8 @@ augroup END command! -nargs=0 -bar LspShowServers lsp.ShowServers() command! -nargs=0 -bar LspShowServerCapabilities lsp.ShowServerCapabilities() command! -nargs=0 -bar LspServerRestart lsp.RestartServer() -command! -nargs=1 -complete=customlist,LspServerTraceComplete -bar LspSetTrace lsp.SetTraceServer() +command! -nargs=1 -complete=customlist,LspServerTraceComplete -bar LspServerTrace lsp.ServerTraceSet() +command! -nargs=1 -complete=customlist,LspServerDebugComplete -bar LspServerDebug lsp.ServerDebug() command! -nargs=0 -bar LspGotoDefinition lsp.GotoDefinition(v:false) command! -nargs=0 -bar LspGotoDeclaration lsp.GotoDeclaration(v:false) command! -nargs=0 -bar LspGotoTypeDef lsp.GotoTypedef(v:false)