]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Move all the LSP diagnostic functions to diag.vim and add tests for LSP diagnostics
authorYegappan Lakshmanan <yegappan@yahoo.com>
Tue, 11 Jan 2022 05:21:00 +0000 (21:21 -0800)
committerYegappan Lakshmanan <yegappan@yahoo.com>
Tue, 11 Jan 2022 05:21:00 +0000 (21:21 -0800)
autoload/diag.vim
autoload/handlers.vim
autoload/lsp.vim
autoload/lspserver.vim
autoload/util.vim
test/test_lsp.vim

index 763645b45a5a7dd4912a3684e2a305f88d1745a0..d870422ee7740530832e1cea2926f1abb6979159 100644 (file)
@@ -1,15 +1,34 @@
 vim9script
 
 var opt = {}
+var util = {}
 
 if has('patch-8.2.4019')
   import './lspoptions.vim' as opt_import
+  import './util.vim' as util_import
+
   opt.lspOptions = opt_import.lspOptions
+  util.WarnMsg = util_import.WarnMsg
+  util.GetLineByteFromPos = util_import.GetLineByteFromPos
 else
   import lspOptions from './lspoptions.vim'
+  import {WarnMsg,
+       LspUriToFile,
+       GetLineByteFromPos} from './util.vim'
+
   opt.lspOptions = lspOptions
+  util.WarnMsg = WarnMsg
+  util.LspUriToFile = LspUriToFile
+  util.GetLineByteFromPos = GetLineByteFromPos
 endif
 
+# Remove the diagnostics stored for buffer 'bnr'
+export def DiagRemoveFile(lspserver: dict<any>, bnr: number)
+  if lspserver.diagsMap->has_key(bnr)
+    lspserver.diagsMap->remove(bnr)
+  endif
+enddef
+
 def s:lspDiagSevToSignName(severity: number): string
   var typeMap: list<string> = ['LspDiagError', 'LspDiagWarning',
                                                'LspDiagInfo', 'LspDiagHint']
@@ -21,7 +40,7 @@ enddef
 
 # New LSP diagnostic messages received from the server for a file.
 # Update the signs placed in the buffer for this file
-export def LspDiagsUpdated(lspserver: dict<any>, bnr: number)
+export def UpdateDiags(lspserver: dict<any>, bnr: number)
   if !opt.lspOptions.autoHighlightDiags
     return
   endif
@@ -55,4 +74,162 @@ export def LspDiagsUpdated(lspserver: dict<any>, bnr: number)
   signs->sign_placelist()
 enddef
 
+# process a diagnostic notification message from the LSP server
+# Notification: textDocument/publishDiagnostics
+# Param: PublishDiagnosticsParams
+export def DiagNotification(lspserver: dict<any>, uri: string, diags: list<dict<any>>): void
+  var fname: string = util.LspUriToFile(uri)
+  var bnr: number = fname->bufnr()
+  if bnr == -1
+    # Is this condition possible?
+    return
+  endif
+
+  # TODO: Is the buffer (bnr) always a loaded buffer? Should we load it here?
+  var lastlnum: number = bnr->getbufinfo()[0].linecount
+  var lnum: number
+
+  # store the diagnostic for each line separately
+  var diag_by_lnum: dict<dict<any>> = {}
+  for d in diags
+    lnum = d.range.start.line + 1
+    if lnum > lastlnum
+      # Make sure the line number is a valid buffer line number
+      lnum = lastlnum
+    endif
+    diag_by_lnum[lnum] = d
+  endfor
+
+  lspserver.diagsMap->extend({['' .. bnr]: diag_by_lnum})
+  UpdateDiags(lspserver, bnr)
+enddef
+
+# get the count of error in the current buffer
+export def DiagsGetErrorCount(lspserver: dict<any>): dict<number>
+  var res = {'Error': 0, 'Warn': 0, 'Info': 0, 'Hint': 0}
+
+  var bnr: number = bufnr()
+  if lspserver.diagsMap->has_key(bnr)
+      for item in lspserver.diagsMap[bnr]->values()
+          if item->has_key('severity')
+              if item.severity == 1
+                  res.Error = res.Error + 1
+              elseif item.severity == 2
+                  res.Warn = res.Warn + 1
+              elseif item.severity == 3
+                  res.Info = res.Info + 1
+              elseif item.severity == 4
+                  res.Hint = res.Hint + 1
+              endif
+          endif
+      endfor
+  endif
+
+  return res
+enddef
+
+# Map the LSP DiagnosticSeverity to a quickfix type character
+def s:lspDiagSevToQfType(severity: number): string
+  var typeMap: list<string> = ['E', 'W', 'I', 'N']
+
+  if severity > 4
+    return ''
+  endif
+
+  return typeMap[severity - 1]
+enddef
+
+# Display the diagnostic messages from the LSP server for the current buffer
+# in a location list
+export def ShowAllDiags(lspserver: dict<any>): void
+  var fname: string = expand('%:p')
+  if fname == ''
+    return
+  endif
+  var bnr: number = bufnr()
+
+  if !lspserver.diagsMap->has_key(bnr) || lspserver.diagsMap[bnr]->empty()
+    util.WarnMsg('No diagnostic messages found for ' .. fname)
+    return
+  endif
+
+  var qflist: list<dict<any>> = []
+  var text: string
+
+  for [lnum, diag] in lspserver.diagsMap[bnr]->items()
+    text = diag.message->substitute("\n\\+", "\n", 'g')
+    qflist->add({'filename': fname,
+                   'lnum': diag.range.start.line + 1,
+                   'col': util.GetLineByteFromPos(bnr, diag.range.start) + 1,
+                   'text': text,
+                   'type': s:lspDiagSevToQfType(diag.severity)})
+  endfor
+  setloclist(0, [], ' ', {'title': 'Language Server Diagnostics',
+                                                       'items': qflist})
+  :lopen
+enddef
+
+# Show the diagnostic message for the current line
+export def ShowCurrentDiag(lspserver: dict<any>)
+  var bnr: number = bufnr()
+  var lnum: number = line('.')
+  var diag: dict<any> = lspserver.getDiagByLine(bnr, lnum)
+  if diag->empty()
+    util.WarnMsg('No diagnostic messages found for current line')
+  else
+    echo diag.message
+  endif
+enddef
+
+# Get the diagnostic from the LSP server for a particular line in a file
+export def GetDiagByLine(lspserver: dict<any>, bnr: number, lnum: number): dict<any>
+  if lspserver.diagsMap->has_key(bnr) &&
+                               lspserver.diagsMap[bnr]->has_key(lnum)
+    return lspserver.diagsMap[bnr][lnum]
+  endif
+  return {}
+enddef
+
+# sort the diaganostics messages for a buffer by line number
+def s:getSortedDiagLines(lspsrv: dict<any>, bnr: number): list<number>
+  # create a list of line numbers from the diag map keys
+  var lnums: list<number> =
+               lspsrv.diagsMap[bnr]->keys()->mapnew((_, v) => v->str2nr())
+  return lnums->sort((a, b) => a - b)
+enddef
+
+# jump to the next/previous/first diagnostic message in the current buffer
+export def LspDiagsJump(lspserver: dict<any>, which: string): void
+  var fname: string = expand('%:p')
+  if fname == ''
+    return
+  endif
+  var bnr: number = bufnr()
+
+  if !lspserver.diagsMap->has_key(bnr) || lspserver.diagsMap[bnr]->empty()
+    util.WarnMsg('No diagnostic messages found for ' .. fname)
+    return
+  endif
+
+  # sort the diagnostics by line number
+  var sortedDiags: list<number> = s:getSortedDiagLines(lspserver, bnr)
+
+  if which == 'first'
+    cursor(sortedDiags[0], 1)
+    return
+  endif
+
+  # Find the entry just before the current line (binary search)
+  var curlnum: number = line('.')
+  for lnum in (which == 'next') ? sortedDiags : sortedDiags->reverse()
+    if (which == 'next' && lnum > curlnum)
+         || (which == 'prev' && lnum < curlnum)
+      cursor(lnum, 1)
+      return
+    endif
+  endfor
+
+  util.WarnMsg('Error: No more diagnostics found')
+enddef
+
 # vim: shiftwidth=2 softtabstop=2
index 02479f6d7938e4e15d1c4579da1383e96bf2a6ce..db6b3e524a7e205e85b806a3676e6762fa45e289 100644 (file)
@@ -19,7 +19,7 @@ if has('patch-8.2.4019')
   util.TraceLog = util_import.TraceLog
   util.LspUriToFile = util_import.LspUriToFile
   util.GetLineByteFromPos = util_import.GetLineByteFromPos
-  diag.LspDiagsUpdated = diag_import.LspDiagsUpdated
+  diag.DiagNotification = diag_import.DiagNotification
 else
   import lspOptions from './lspoptions.vim'
   import {WarnMsg,
@@ -27,7 +27,7 @@ else
        TraceLog,
        LspUriToFile,
        GetLineByteFromPos} from './util.vim'
-  import {LspDiagsUpdated} from './diag.vim'
+  import {DiagNotification} from './diag.vim'
 
   opt.lspOptions = lspOptions
   util.WarnMsg = WarnMsg
@@ -35,7 +35,7 @@ else
   util.TraceLog = TraceLog
   util.LspUriToFile = LspUriToFile
   util.GetLineByteFromPos = GetLineByteFromPos
-  diag.LspDiagsUpdated = LspDiagsUpdated
+  diag.DiagNotification = DiagNotification
 endif
 
 # process the 'initialize' method reply from the LSP server
@@ -583,9 +583,13 @@ def s:set_lines(lines: list<string>, A: list<number>, B: list<number>,
   var i_n = [B[0], numlines - 1]->min()
 
   if i_0 < 0 || i_0 >= numlines || i_n < 0 || i_n >= numlines
-    util.WarnMsg("set_lines: Invalid range, A = " .. A->string()
-               .. ", B = " ..  B->string() .. ", numlines = " .. numlines
-               .. ", new lines = " .. new_lines->string())
+    #util.WarnMsg("set_lines: Invalid range, A = " .. A->string()
+    #          .. ", B = " ..  B->string() .. ", numlines = " .. numlines
+    #          .. ", new lines = " .. new_lines->string())
+    var msg = "set_lines: Invalid range, A = " .. A->string()
+    msg ..= ", B = " ..  B->string() .. ", numlines = " .. numlines
+    msg ..= ", new lines = " .. new_lines->string()
+    util.WarnMsg(msg)
     return lines
   endif
 
@@ -1022,30 +1026,7 @@ enddef
 # Notification: textDocument/publishDiagnostics
 # Param: PublishDiagnosticsParams
 def s:processDiagNotif(lspserver: dict<any>, reply: dict<any>): void
-  var fname: string = util.LspUriToFile(reply.params.uri)
-  var bnr: number = fname->bufnr()
-  if bnr == -1
-    # Is this condition possible?
-    return
-  endif
-
-  # TODO: Is the buffer (bnr) always a loaded buffer? Should we load it here?
-  var lastlnum: number = bnr->getbufinfo()[0].linecount
-  var lnum: number
-
-  # store the diagnostic for each line separately
-  var diag_by_lnum: dict<dict<any>> = {}
-  for diag in reply.params.diagnostics
-    lnum = diag.range.start.line + 1
-    if lnum > lastlnum
-      # Make sure the line number is a valid buffer line number
-      lnum = lastlnum
-    endif
-    diag_by_lnum[lnum] = diag
-  endfor
-
-  lspserver.diagsMap->extend({['' .. bnr]: diag_by_lnum})
-  diag.LspDiagsUpdated(lspserver, bnr)
+  diag.DiagNotification(lspserver, reply.params.uri, reply.params.diagnostics)
 enddef
 
 # process a show notification message from the LSP server
index 33487c4d2eae00a0403ede46ef88a5e1e5bec639..26793c97b598fd6e35c2bba3a6d649126faeb0b4 100644 (file)
@@ -22,7 +22,12 @@ if has('patch-8.2.4019')
   util.ClearTraceLogs = util_import.ClearTraceLogs
   util.GetLineByteFromPos = util_import.GetLineByteFromPos
   util.PushCursorToTagStack = util_import.PushCursorToTagStack
-  diag.LspDiagsUpdated = diag_import.LspDiagsUpdated
+  diag.UpdateDiags = diag_import.UpdateDiags
+  diag.DiagsGetErrorCount = diag_import.DiagsGetErrorCount
+  diag.ShowAllDiags = diag_import.ShowAllDiags
+  diag.ShowCurrentDiag = diag_import.ShowCurrentDiag
+  diag.LspDiagsJump = diag_import.LspDiagsJump
+  diag.DiagRemoveFile = diag_import.DiagRemoveFile
 else
   import {lspOptions, LspOptionsSet} from './lspoptions.vim'
   import NewLspServer from './lspserver.vim'
@@ -32,7 +37,12 @@ else
         ClearTraceLogs,
         GetLineByteFromPos,
         PushCursorToTagStack} from './util.vim'
-  import {LspDiagsUpdated} from './diag.vim'
+  import {DiagRemoveFile,
+       UpdateDiags,
+       DiagsGetErrorCount,
+       ShowAllDiags,
+       ShowCurrentDiag,
+       LspDiagsJump} from './diag.vim'
 
   opt.LspOptionsSet = LspOptionsSet
   opt.lspOptions = lspOptions
@@ -43,7 +53,12 @@ else
   util.ClearTraceLogs = ClearTraceLogs
   util.GetLineByteFromPos = GetLineByteFromPos
   util.PushCursorToTagStack = PushCursorToTagStack
-  diag.LspDiagsUpdated = LspDiagsUpdated
+  diag.DiagRemoveFile = DiagRemoveFile
+  diag.UpdateDiags = UpdateDiags
+  diag.DiagsGetErrorCount = DiagsGetErrorCount
+  diag.ShowAllDiags = ShowAllDiags
+  diag.ShowCurrentDiag = ShowCurrentDiag
+  diag.LspDiagsJump = LspDiagsJump
 endif
 
 # Needs Vim 8.2.2342 and higher
@@ -303,7 +318,7 @@ def lsp#leftInsertMode()
   if lspserver->empty() || !lspserver.running
     return
   endif
-  diag.LspDiagsUpdated(lspserver, bufnr())
+  diag.UpdateDiags(lspserver, bufnr())
 enddef
 
 # A new buffer is opened. If LSP is supported for this buffer, then add it
@@ -398,9 +413,7 @@ def lsp#removeFile(bnr: number): void
     return
   endif
   lspserver.textdocDidClose(bnr)
-  if lspserver.diagsMap->has_key(bnr)
-    lspserver.diagsMap->remove(bnr)
-  endif
+  diag.DiagRemoveFile(lspserver, bnr)
   bufnrToServer->remove(bnr)
 enddef
 
@@ -482,22 +495,11 @@ def lsp#setTraceServer(traceVal: string)
   lspserver.setTrace(traceVal)
 enddef
 
-# Map the LSP DiagnosticSeverity to a quickfix type character
-def s:lspDiagSevToQfType(severity: number): string
-  var typeMap: list<string> = ['E', 'W', 'I', 'N']
-
-  if severity > 4
-    return ''
-  endif
-
-  return typeMap[severity - 1]
-enddef
-
 # Display the diagnostic messages from the LSP server for the current buffer
 # in a quickfix list
 def lsp#showDiagnostics(): void
   var ftype = &filetype
-  if ftype == ''
+  if ftype == '' || @% == ''
     return
   endif
 
@@ -511,37 +513,13 @@ def lsp#showDiagnostics(): void
     return
   endif
 
-  var fname: string = expand('%:p')
-  if fname == ''
-    return
-  endif
-  var bnr: number = bufnr()
-
-  if !lspserver.diagsMap->has_key(bnr) || lspserver.diagsMap[bnr]->empty()
-    util.WarnMsg('No diagnostic messages found for ' .. fname)
-    return
-  endif
-
-  var qflist: list<dict<any>> = []
-  var text: string
-
-  for [lnum, diag] in lspserver.diagsMap[bnr]->items()
-    text = diag.message->substitute("\n\\+", "\n", 'g')
-    qflist->add({'filename': fname,
-                   'lnum': diag.range.start.line + 1,
-                   'col': util.GetLineByteFromPos(bnr, diag.range.start) + 1,
-                   'text': text,
-                   'type': s:lspDiagSevToQfType(diag.severity)})
-  endfor
-  setloclist(0, [], ' ', {'title': 'Language Server Diagnostics',
-                                                       'items': qflist})
-  :lopen
+  diag.ShowAllDiags(lspserver)
 enddef
 
 # Show the diagnostic message for the current line
 def lsp#showCurrentDiag()
   var ftype = &filetype
-  if ftype == ''
+  if ftype == '' || @% == ''
     return
   endif
 
@@ -555,14 +533,7 @@ def lsp#showCurrentDiag()
     return
   endif
 
-  var bnr: number = bufnr()
-  var lnum: number = line('.')
-  var diag: dict<any> = lspserver.getDiagByLine(bnr, lnum)
-  if diag->empty()
-    util.WarnMsg('No diagnostic messages found for current line')
-  else
-    echo diag.message
-  endif
+  diag.ShowCurrentDiag(lspserver)
 enddef
 
 # get the count of error in the current buffer
@@ -578,38 +549,13 @@ def lsp#errorCount(): dict<number>
     return res
   endif
 
-  var bnr: number = bufnr()
-  if lspserver.diagsMap->has_key(bnr)
-      for item in lspserver.diagsMap[bnr]->values()
-          if item->has_key('severity')
-              if item.severity == 1
-                  res.Error = res.Error + 1
-              elseif item.severity == 2
-                  res.Warn = res.Warn + 1
-              elseif item.severity == 3
-                  res.Info = res.Info + 1
-              elseif item.severity == 4
-                  res.Hint = res.Hint + 1
-              endif
-          endif
-      endfor
-  endif
-
-  return res
-enddef
-
-# sort the diaganostics messages for a buffer by line number
-def s:getSortedDiagLines(lspsrv: dict<any>, bnr: number): list<number>
-  # create a list of line numbers from the diag map keys
-  var lnums: list<number> =
-               lspsrv.diagsMap[bnr]->keys()->mapnew((_, v) => v->str2nr())
-  return lnums->sort((a, b) => a - b)
+  return diag.DiagsGetErrorCount(lspserver)
 enddef
 
 # jump to the next/previous/first diagnostic message in the current buffer
 def lsp#jumpToDiag(which: string): void
   var ftype = &filetype
-  if ftype == ''
+  if ftype == '' || @% == ''
     return
   endif
 
@@ -623,36 +569,7 @@ def lsp#jumpToDiag(which: string): void
     return
   endif
 
-  var fname: string = expand('%:p')
-  if fname == ''
-    return
-  endif
-  var bnr: number = bufnr()
-
-  if !lspserver.diagsMap->has_key(bnr) || lspserver.diagsMap[bnr]->empty()
-    util.WarnMsg('No diagnostic messages found for ' .. fname)
-    return
-  endif
-
-  # sort the diagnostics by line number
-  var sortedDiags: list<number> = s:getSortedDiagLines(lspserver, bnr)
-
-  if which == 'first'
-    cursor(sortedDiags[0], 1)
-    return
-  endif
-
-  # Find the entry just before the current line (binary search)
-  var curlnum: number = line('.')
-  for lnum in (which == 'next') ? sortedDiags : sortedDiags->reverse()
-    if (which == 'next' && lnum > curlnum)
-         || (which == 'prev' && lnum < curlnum)
-      cursor(lnum, 1)
-      return
-    endif
-  endfor
-
-  util.WarnMsg('Error: No more diagnostics found')
+  diag.LspDiagsJump(lspserver, which)
 enddef
 
 # Insert mode completion handler. Used when 24x7 completion is enabled
index c91021acb3f2750cc050ac475767f464376284ab..cef6987638e96f6b152deb1d56b2580c33cd81b8 100644 (file)
@@ -5,11 +5,13 @@ vim9script
 # for the Language Server Protocol (LSP) specificaiton.
 
 var handlers = {}
+var diag = {}
 var util = {}
 
 if has('patch-8.2.4019')
   import './handlers.vim' as handlers_import
   import './util.vim' as util_import
+  import './diag.vim' as diag_import
   handlers.ProcessReply = handlers_import.ProcessReply
   handlers.ProcessNotif = handlers_import.ProcessNotif
   handlers.ProcessRequest = handlers_import.ProcessRequest
@@ -17,19 +19,19 @@ if has('patch-8.2.4019')
   util.WarnMsg = util_import.WarnMsg
   util.ErrMsg = util_import.ErrMsg
   util.TraceLog = util_import.TraceLog
-  util.LspUriToFile = util_import.LspUriToFile
   util.LspBufnrToUri = util_import.LspBufnrToUri
   util.LspFileToUri = util_import.LspFileToUri
   util.PushCursorToTagStack = util_import.PushCursorToTagStack
+  diag.GetDiagByLine = diag_import.GetDiagByLine
 else
   import {ProcessReply,
        ProcessNotif,
        ProcessRequest,
        ProcessMessages} from './handlers.vim'
+  import {GetDiagByLine} from './diag.vim'
   import {WarnMsg,
        ErrMsg,
        TraceLog,
-       LspUriToFile,
        LspBufnrToUri,
        LspFileToUri,
        PushCursorToTagStack} from './util.vim'
@@ -40,10 +42,10 @@ else
   util.WarnMsg = WarnMsg
   util.ErrMsg = ErrMsg
   util.TraceLog = TraceLog
-  util.LspUriToFile = LspUriToFile
   util.LspBufnrToUri = LspBufnrToUri
   util.LspFileToUri = LspFileToUri
   util.PushCursorToTagStack = PushCursorToTagStack
+  diag.GetDiagByLine = GetDiagByLine
 endif
 
 # LSP server standard output handler
@@ -628,8 +630,9 @@ def s:textDocFormat(lspserver: dict<any>, fname: string, rangeFormat: bool,
     tabSize: tabsz,
     insertSpaces: &expandtab ? true : false,
   }
-  req.params->extend({textDocument: {uri: util.LspFileToUri(fname)},
-                                                       options: fmtopts})
+  #req.params->extend({textDocument: {uri: util.LspFileToUri(fname)},
+  #                                                    options: fmtopts})
+  req.params->extend({textDocument: {uri: util.LspFileToUri(fname)}, options: fmtopts})
   if rangeFormat
     var r: dict<dict<number>> = {
        start: {line: start_lnum - 1, character: 0},
@@ -677,15 +680,6 @@ def s:renameSymbol(lspserver: dict<any>, newName: string)
   lspserver.sendMessage(req)
 enddef
 
-# Get the diagnostic from the LSP server for a particular line in a file
-def s:getDiagByLine(lspserver: dict<any>, bnr: number, lnum: number): dict<any>
-  if lspserver.diagsMap->has_key(bnr) &&
-                               lspserver.diagsMap[bnr]->has_key(lnum)
-    return lspserver.diagsMap[bnr][lnum]
-  endif
-  return {}
-enddef
-
 # Request: "textDocument/codeAction"
 # Param: CodeActionParams
 def s:codeAction(lspserver: dict<any>, fname_arg: string)
@@ -705,13 +699,13 @@ def s:codeAction(lspserver: dict<any>, fname_arg: string)
                  start: {line: line('.') - 1, character: charcol('.') - 1},
                  end: {line: line('.') - 1, character: charcol('.') - 1}}
   req.params->extend({textDocument: {uri: util.LspFileToUri(fname)}, range: r})
-  var diag: list<dict<any>> = []
+  var d: list<dict<any>> = []
   var lnum = line('.')
-  var diagInfo: dict<any> = lspserver.getDiagByLine(bnr, lnum)
+  var diagInfo: dict<any> = diag.GetDiagByLine(lspserver, bnr, lnum)
   if !diagInfo->empty()
-    diag->add(diagInfo)
+    d->add(diagInfo)
   endif
-  req.params->extend({context: {diagnostics: diag}})
+  req.params->extend({context: {diagnostics: d}})
 
   lspserver.sendMessage(req)
 enddef
@@ -858,7 +852,7 @@ export def NewLspServer(path: string, args: list<string>): dict<any>
     processNotif: function(handlers.ProcessNotif, [lspserver]),
     processRequest: function(handlers.ProcessRequest, [lspserver]),
     processMessages: function(handlers.ProcessMessages, [lspserver]),
-    getDiagByLine: function('s:getDiagByLine', [lspserver]),
+    getDiagByLine: function(diag.GetDiagByLine, [lspserver]),
     textdocDidOpen: function('s:textdocDidOpen', [lspserver]),
     textdocDidClose: function('s:textdocDidClose', [lspserver]),
     textdocDidChange: function('s:textdocDidChange', [lspserver]),
index 735febccf23a98ce054a6554730851ab5f94e2dc..bed2f381a65a5f1ef5ca1c7c68aec027b1657519 100644 (file)
@@ -69,7 +69,7 @@ export def LspUriToFile(uri: string): string
   return uri_decoded
 enddef
 
-# Convert a Vim filenmae to an LSP URI (file://<absolute_path>)
+# Convert a Vim filename to an LSP URI (file://<absolute_path>)
 export def LspFileToUri(fname: string): string
   var uri: string = fnamemodify(fname, ':p')
 
index 40367128751c8403b1329cceba86a9131cbba428..b71abb9b69a722347130dd483e22c25112101704 100644 (file)
@@ -138,6 +138,58 @@ def Test_lsp_show_references()
   :%bw!
 enddef
 
+def Test_lsp_diags()
+  :silent! edit Xtest.c
+  var lines: list<string> =<< trim END
+    void blueFunc()
+    {
+       int count, j:
+       count = 20;
+       j <= count;
+       j = 10;
+       MyFunc();
+    }
+  END
+  setline(1, lines)
+  :sleep 1
+  var bnr: number = bufnr()
+  :redraw!
+  :LspDiagShow
+  var qfl: list<dict<any>> = getloclist(0)
+  assert_equal('quickfix', getwinvar(winnr('$'), '&buftype'))
+  assert_equal(bnr, qfl[0].bufnr)
+  assert_equal(3, qfl->len())
+  assert_equal([3, 14, 'E'], [qfl[0].lnum, qfl[0].col, qfl[0].type])
+  assert_equal([5, 2, 'W'], [qfl[1].lnum, qfl[1].col, qfl[1].type])
+  assert_equal([7, 2, 'W'], [qfl[2].lnum, qfl[2].col, qfl[2].type])
+  close
+  normal gg
+  var output = execute('LspDiagCurrent')->split("\n")
+  assert_equal('No diagnostic messages found for current line', output[0])
+  :LspDiagFirst
+  assert_equal([3, 1], [line('.'), col('.')])
+  output = execute('LspDiagCurrent')->split("\n")
+  assert_equal("Expected ';' at end of declaration (fix available)", output[0])
+  :LspDiagNext
+  assert_equal([5, 1], [line('.'), col('.')])
+  :LspDiagNext
+  assert_equal([7, 1], [line('.'), col('.')])
+  output = execute('LspDiagNext')->split("\n")
+  assert_equal('Error: No more diagnostics found', output[0])
+  :LspDiagPrev
+  :LspDiagPrev
+  :LspDiagPrev
+  output = execute('LspDiagPrev')->split("\n")
+  assert_equal('Error: No more diagnostics found', output[0])
+  :%d
+  setline(1, ['void blueFunc()', '{', '}'])
+  sleep 1
+  output = execute('LspDiagShow')->split("\n")
+  assert_match('No diagnostic messages found for', output[0])
+
+  :%bw!
+enddef
+
 def LspRunTests()
   # Edit a dummy C file to start the LSP server
   :edit Xtest.c
@@ -150,11 +202,15 @@ def LspRunTests()
                    ->map("v:val->substitute('^def <SNR>\\d\\+_', '', '')")
   for f in fns
     v:errors = []
+    v:errmsg = ''
     try
       exe f
     catch
-      echomsg "Error: Test " .. f .. " failed with exception " .. v:exception
+      call add(v:errors, "Error: Test " .. f .. " failed with exception " .. v:exception)
     endtry
+    if v:errmsg != ''
+      call add(v:errors, "Error: Test " .. f .. " generated error " .. v:errmsg)
+    endif
     if v:errors->len() != 0
       new Lsp-Test-Results
       setline(1, ["Error: Test " .. f .. " failed"]->extend(v:errors))