From aef1c2879dc4997069980e6804e9047a3632b24f Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Mon, 10 Apr 2023 07:25:10 -0700 Subject: [PATCH] Add support for storing and displaying the language server notification messages. Add additional arguments to the LspShowServer command --- README.md | 3 +-- autoload/lsp/handlers.vim | 49 +++++++++++++++++++++++++------------- autoload/lsp/lsp.vim | 20 +++++++++++----- autoload/lsp/lspserver.vim | 32 ++++++++++++++++++++----- doc/lsp.txt | 32 +++++++++++++------------ plugin/lsp.vim | 18 +++++++++++--- 6 files changed, 105 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 73d382e..9f66a90 100644 --- a/README.md +++ b/README.md @@ -189,8 +189,7 @@ Command|Description :LspShowAllServers|Display information about all the registered language servers. :LspServerRestart|Restart the language server for the current buffer. :LspShowReferences|Display the list of references to the keyword under cursor in a new location list. -:LspShowServer|Display the language server status for the current buffer. -:LspShowServerCapabilities|Display the language server capabilities for the current buffer. +:LspShowServer|Display the capabilities or messages or status of the language server for the current buffer. :LspShowSignature|Display the signature of the keyword under cursor. :LspSubTypeHierarchy|Display the sub type hierarchy in a popup window. :LspSuperTypeHierarchy|Display the super type hierarchy in a popup window. diff --git a/autoload/lsp/handlers.vim b/autoload/lsp/handlers.vim index 93c4312..42c0cbd 100644 --- a/autoload/lsp/handlers.vim +++ b/autoload/lsp/handlers.vim @@ -20,11 +20,20 @@ def ProcessDiagNotif(lspserver: dict, reply: dict): void diag.DiagNotification(lspserver, reply.params.uri, reply.params.diagnostics) enddef +# Convert LSP message type to a string +def LspMsgTypeToString(lspMsgType: number): string + var msgStrMap: list = ['', 'Error', 'Warning', 'Info', 'Log'] + var mtype: string = 'Log' + if lspMsgType > 0 && lspMsgType < 5 + mtype = msgStrMap[lspMsgType] + endif + return mtype +enddef + # process a show notification message from the LSP server # Notification: window/showMessage # Param: ShowMessageParams def ProcessShowMsgNotif(lspserver: dict, reply: dict) - var msgType: list = ['', 'Error: ', 'Warning: ', 'Info: ', 'Log: '] if reply.params.type == 4 # ignore log messages from the LSP server (too chatty) # TODO: Add a configuration to control the message level that will be @@ -32,25 +41,36 @@ def ProcessShowMsgNotif(lspserver: dict, reply: dict) # them. return endif - var mtype: string = 'Log: ' - if reply.params.type > 0 && reply.params.type < 5 - mtype = msgType[reply.params.type] - endif - - :echomsg $'Lsp {mtype} {reply.params.message}' + var mtype = LspMsgTypeToString(reply.params.type) + :echomsg $'Lsp({lspserver.name}):[{mtype}]: {reply.params.message}' enddef # process a log notification message from the LSP server # Notification: window/logMessage # Param: LogMessageParams def ProcessLogMsgNotif(lspserver: dict, reply: dict) - var msgType: list = ['', 'Error', 'Warning', 'Info', 'Log'] - var mtype: string = 'Log' - if reply.params.type > 0 && reply.params.type < 5 - mtype = msgType[reply.params.type] + var mtype = LspMsgTypeToString(reply.params.type) + var msgs = reply.params.message->split("\n") + + lspserver.messages->add($'{strftime("%m/%d/%y %T")}: [{mtype}]: {msgs[0]}') + lspserver.messages->extend(msgs[1 : ]) + # Keep only the last 500 messages to reduce the memory usage + if lspserver.messages->len() > 500 + lspserver.messages = lspserver.messages[-500 : ] endif +enddef - lspserver.traceLog($'{strftime("%m/%d/%y %T")}: [{mtype}]: {reply.params.message}') +# process the log trace notification messages +# Notification: $/logTrace +# Param: LogTraceParams +def ProcessLogTraceNotif(lspserver: dict, reply: dict) + var msgs = reply.params.message->split("\n") + lspserver.messages->add($'{strftime("%m/%d/%y %T")}: [trace]: {msgs[0]}') + lspserver.messages->extend(msgs[1 : ]) + # Keep only the last 500 messages to reduce the memory usage + if lspserver.messages->len() > 500 + lspserver.messages = lspserver.messages[-500 : ] + endif enddef # process unsupported notification messages @@ -58,11 +78,6 @@ def ProcessUnsupportedNotif(lspserver: dict, reply: dict) util.ErrMsg($'Error: Unsupported notification message received from the LSP server ({lspserver.path}), message = {reply->string()}') enddef -# process log trace notification messages -def ProcessLogTraceNotif(lspserver: dict, reply: dict) - :echomsg $'Log trace notification: {reply->string()}' -enddef - # per-filetype private map inside to record if ntf once or not var ftypeNtfOnceMap: dict = {} # process unsupported notification messages but only notify once diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 62e2f40..ca36ae4 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -155,20 +155,28 @@ export def ShowAllServers() enddef # Show the status of the LSP server for the current buffer -export def ShowServer() +export def ShowServer(arg: string) var lspserver: dict = buf.CurbufGetServerChecked() if lspserver->empty() :echomsg "LSP Server not found" return endif - var msg = $"LSP server '{lspserver.name}' is " - if lspserver.running - msg ..= 'running' + if arg == '' || arg ==? 'status' + var msg = $"LSP server '{lspserver.name}' is " + if lspserver.running + msg ..= 'running' + else + msg ..= 'not running' + endif + :echomsg msg + elseif arg ==? 'capabilities' + lspserver.showCapabilities() + elseif arg ==? 'messages' + lspserver.showMessages() else - msg ..= 'not running' + util.ErrMsg($'Error: Unsupported argument "{arg}"') endif - :echomsg msg enddef # Get LSP server running status for filetype 'ftype' diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index e652d01..20e00fd 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -1382,22 +1382,28 @@ def ExecuteCommand(lspserver: dict, cmd: dict) lspserver.rpc_a('workspace/executeCommand', params, WorkspaceExecuteReply) enddef -# Display the LSP server capabilities (received during the initialization -# stage). -def ShowCapabilities(lspserver: dict) - var wid = bufwinid('Language-Server-Capabilities') +# Create a new window containing the buffer 'bname' or if the window is +# already present then jump to it. +def OpenScratchWindow(bname: string) + var wid = bufwinid(bname) if wid != -1 wid->win_gotoid() :setlocal modifiable :silent! :%d _ else - :new Language-Server-Capabilities + exe $':new {bname}' :setlocal buftype=nofile :setlocal bufhidden=wipe :setlocal noswapfile :setlocal nonumber nornu :setlocal fdc=0 signcolumn=no endif +enddef + +# Display the LSP server capabilities (received during the initialization +# stage). +def ShowCapabilities(lspserver: dict) + OpenScratchWindow($'LangServer-{lspserver.name}-Capabilities') var l = [] var heading = $"'{lspserver.path}' Language Server Capabilities" var underlines = repeat('=', heading->len()) @@ -1410,6 +1416,18 @@ def ShowCapabilities(lspserver: dict) :setlocal nomodifiable enddef +# Display the log messages received from the LSP server (window/logMessage) +def ShowMessages(lspserver: dict) + if lspserver.messages->empty() + util.WarnMsg($'No messages received from "{lspserver.name}" server') + return + endif + OpenScratchWindow($'LangServer-{lspserver.name}-Messages') + setline(1, lspserver.messages) + :setlocal nomodified + :setlocal nomodifiable +enddef + # Send a 'textDocument/definition' request to the LSP server to get the # location where the symbol under the cursor is defined and return a list of # Dicts in a format accepted by the 'tagfunc' option. @@ -1472,6 +1490,7 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list, callHierarchyType: '', selection: {}, workspaceConfig: workspaceConfig, + messages: [], debug: debug_arg } lspserver.logfile = $'lsp-{lspserver.name}.log' @@ -1542,7 +1561,8 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list, foldRange: function(FoldRange, [lspserver]), executeCommand: function(ExecuteCommand, [lspserver]), workspaceConfigGet: function(WorkspaceConfigGet, [lspserver]), - showCapabilities: function(ShowCapabilities, [lspserver]) + showCapabilities: function(ShowCapabilities, [lspserver]), + showMessages: function(ShowMessages, [lspserver]) }) return lspserver diff --git a/doc/lsp.txt b/doc/lsp.txt index acd4cac..0cc6689 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -128,11 +128,8 @@ The following commands are provided: servers. :LspShowReferences Display the list of references to the keyword under cursor in a new location list. -:LspShowServerCapabilities - Display the language server capabilities for the - current buffer. -:LspShowServer Display the status of the language server for the - current buffer. +:LspShowServer Display the capabilities, status and messages of the + language server for the current buffer. :LspShowSignature Display the signature of the symbol under cursor. :LspSubTypeHierarchy Display the sub type hierarchy in a popup window. :LspSuperTypeHierarchy Display the super type hierarchy in a popup window. @@ -790,17 +787,22 @@ can map these commands to keys and make it easier to invoke them. call LspOptionsSet({'useQuickfixForLocations': v:true}) < - -:LspShowServerCapabilities *:LspShowServerCapabilities* - Display the list of language server capabilities for - the current buffer. The server capabilities are - described in the LSP protocol specification under the - "ServerCapabilities" interface. - *:LspShowServer* -:LspShowServer Displays the language server status for the current - buffer. The output shows the path to the language - server executable and the server status. +:LspShowServer {capabilities | messages | status} + capabilities - Display the list of language server + capabilities for the current buffer. + The server capabilities are described + in the LSP protocol specification under + the "ServerCapabilities" interface. + messages - Display the log messages received from + the language server. This includes the + messages received using the + "window/logMessage" and "$/logTrace" + LSP notifications. + status - Display the language server status for + the current buffer. The output shows + the path to the language server + executable and the server status. *:LspShowSignature* :LspShowSignature Displays the signature of the symbol (e.g. a function diff --git a/plugin/lsp.vim b/plugin/lsp.vim index 46ab79d..d70cc80 100644 --- a/plugin/lsp.vim +++ b/plugin/lsp.vim @@ -44,7 +44,7 @@ def g:LspServerRunning(ftype: string): bool return lsp.ServerRunning(ftype) enddef -# Command line completion function for the LspSetTrace command. +# Command line completion function for the LspServerTrace command. def LspServerTraceComplete(arglead: string, cmdline: string, cursorpos: number): list var l = ['off', 'messages', 'verbose'] if arglead->empty() @@ -54,7 +54,7 @@ def LspServerTraceComplete(arglead: string, cmdline: string, cursorpos: number): endif enddef -# Command line completion function for the LspSetTrace command. +# Command line completion function for the LspServerDebug command. def LspServerDebugComplete(arglead: string, cmdline: string, cursorpos: number): list var l = ['errors', 'messages', 'off', 'on'] if arglead->empty() @@ -64,6 +64,16 @@ def LspServerDebugComplete(arglead: string, cmdline: string, cursorpos: number): endif enddef +# Command line completion function for the LspShowServer command. +def LspShowServerComplete(arglead: string, cmdline: string, cursorpos: number): list + var l = ['capabilities', 'messages', 'status'] + if arglead->empty() + return l + else + return filter(l, (_, val) => val =~ arglead) + endif +enddef + augroup LSPAutoCmds au! autocmd BufNewFile,BufReadPost * lsp.AddFile(expand('')->str2nr()) @@ -112,8 +122,10 @@ command! -nargs=1 -complete=customlist,LspServerDebugComplete -bar LspServerDebu command! -nargs=0 -bar LspServerRestart lsp.RestartServer() command! -nargs=1 -complete=customlist,LspServerTraceComplete -bar LspServerTrace lsp.ServerTraceSet() command! -nargs=0 -bar LspShowReferences lsp.ShowReferences(v:false) +# The :LspShowServerCapabilities command is retained for backward +# compatibility. Remove this in the future. command! -nargs=0 -bar LspShowServerCapabilities lsp.ShowServerCapabilities() -command! -nargs=0 -bar LspShowServer lsp.ShowServer() +command! -nargs=? -complete=customlist,LspShowServerComplete -bar LspShowServer lsp.ShowServer() command! -nargs=0 -bar LspShowAllServers lsp.ShowAllServers() command! -nargs=0 -bar LspShowSignature call LspShowSignature() command! -nargs=0 -bar LspSubTypeHierarchy lsp.TypeHierarchy(0) -- 2.48.1