]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Add support for storing and displaying the language server notification messages...
authorYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 10 Apr 2023 14:25:10 +0000 (07:25 -0700)
committerYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 10 Apr 2023 14:25:10 +0000 (07:25 -0700)
README.md
autoload/lsp/handlers.vim
autoload/lsp/lsp.vim
autoload/lsp/lspserver.vim
doc/lsp.txt
plugin/lsp.vim

index 73d382e3b53ef415c55e1a1052f153d7d77b41ef..9f66a9001af384db97cf327042fd8b345520eb54 100644 (file)
--- 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.
index 93c4312d9bc3488dc1f29f6c467837178661c774..42c0cbd6e4e5373c62a9e45f1de2e2734d6c1eb0 100644 (file)
@@ -20,11 +20,20 @@ def ProcessDiagNotif(lspserver: dict<any>, reply: dict<any>): 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<string> = ['', '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<any>, reply: dict<any>)
-  var msgType: list<string> = ['', '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<any>, reply: dict<any>)
     # 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<any>, reply: dict<any>)
-  var msgType: list<string> = ['', '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<any>, reply: dict<any>)
+  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<any>, reply: dict<any>)
   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<any>, reply: dict<any>)
-  :echomsg $'Log trace notification: {reply->string()}'
-enddef
-
 # per-filetype private map inside to record if ntf once or not
 var ftypeNtfOnceMap: dict<bool> = {}
 # process unsupported notification messages but only notify once
index 62e2f401a10cace9d9d2fec9b4286cbeaa52cae7..ca36ae451ca298110270ba26e886fe6fe34c4ccf 100644 (file)
@@ -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<any> = 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'
index e652d015fe53dd40fe3de92869e667109ea99818..20e00fd31b9d3facf8f27aace0a6706434607237 100644 (file)
@@ -1382,22 +1382,28 @@ def ExecuteCommand(lspserver: dict<any>, cmd: dict<any>)
   lspserver.rpc_a('workspace/executeCommand', params, WorkspaceExecuteReply)
 enddef
 
-# Display the LSP server capabilities (received during the initialization
-# stage).
-def ShowCapabilities(lspserver: dict<any>)
-  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<any>)
+  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<any>)
   :setlocal nomodifiable
 enddef
 
+# Display the log messages received from the LSP server (window/logMessage)
+def ShowMessages(lspserver: dict<any>)
+  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<string>,
     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<string>,
     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
index acd4cac959bb57463b1d825e0addcd376b3ed106..0cc668970517c1afc48f13b47ffc49a031e69c7f 100644 (file)
@@ -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
index 46ab79d18f3661ba363660837ab737f1d315b2bb..d70cc80c492fe2efdfc4c1c83cf1b07ffa50e48e 100644 (file)
@@ -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<string>
   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<string>
   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<string>
+  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('<abuf>')->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(<q-args>)
 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(<q-args>)
 command! -nargs=0 -bar LspShowAllServers lsp.ShowAllServers()
 command! -nargs=0 -bar LspShowSignature call LspShowSignature()
 command! -nargs=0 -bar LspSubTypeHierarchy lsp.TypeHierarchy(0)