From b644830f94f6369b573d6bc42aa9f5169f01a780 Mon Sep 17 00:00:00 2001 From: Andreas Louv Date: Tue, 11 Apr 2023 16:40:02 +0200 Subject: [PATCH] Add support for diagnostics from multiple servers This will join diagnostics from all running language servers. --- autoload/lsp/diag.vim | 111 ++++++++++++++++++++++++------------- autoload/lsp/lspserver.vim | 1 - 2 files changed, 74 insertions(+), 38 deletions(-) diff --git a/autoload/lsp/diag.vim b/autoload/lsp/diag.vim index 293051c..12c699c 100644 --- a/autoload/lsp/diag.vim +++ b/autoload/lsp/diag.vim @@ -6,6 +6,19 @@ import './options.vim' as opt import './buffer.vim' as buf import './util.vim' +# [bnr] = { +# serverDiagnostics: { +# lspServer1Id: [diag, diag, diag] +# lspServer2Id: [diag, diag, diag] +# }, +# serverDiagnosticsByLnum: { +# lspServer1Id: { [lnum]: [diag, diag diag] }, +# lspServer2Id: { [lnum]: [diag, diag diag] }, +# }, +# sortedDiagnostics: [lspServer1.diags, ...lspServer2.diags]->sort() +# } +var diagsMap: dict> = {} + # Initialize the signs and the text property type used for diagnostics. export def InitOnce() # Signs used for LSP diagnostics @@ -75,9 +88,9 @@ def SortDiags(diags: list>): list> enddef # Remove the diagnostics stored for buffer 'bnr' -export def DiagRemoveFile(lspserver: dict, bnr: number) - if lspserver.diagsMap->has_key(bnr) - lspserver.diagsMap->remove(bnr) +export def DiagRemoveFile(bnr: number) + if diagsMap->has_key(bnr) + diagsMap->remove(bnr) endif enddef @@ -123,13 +136,13 @@ def DiagsRefresh(lspserver: dict, bnr: number) prop_remove({type: 'LspDiagInlineHint', bufnr: bnr, all: true}) endif - if !lspserver.diagsMap->has_key(bnr) || - lspserver.diagsMap[bnr].sortedDiagnostics->empty() + if !diagsMap->has_key(bnr) || + diagsMap[bnr].sortedDiagnostics->empty() return endif var signs: list> = [] - var diags = lspserver.diagsMap[bnr].sortedDiagnostics + var diags: list> = diagsMap[bnr].sortedDiagnostics for diag in diags # TODO: prioritize most important severity if there are multiple diagnostics # from the same line @@ -179,7 +192,7 @@ export def ProcessNewDiags(lspserver: dict, bnr: number) return endif - if bnr == -1 || !lspserver.diagsMap->has_key(bnr) + if bnr == -1 || !diagsMap->has_key(bnr) return endif @@ -197,7 +210,7 @@ enddef # process a diagnostic notification message from the LSP server # Notification: textDocument/publishDiagnostics # Param: PublishDiagnosticsParams -export def DiagNotification(lspserver: dict, uri: string, diags: list>): void +export def DiagNotification(lspserver: dict, uri: string, newDiags: list>): void var fname: string = util.LspUriToFile(uri) var bnr: number = fname->bufnr() if bnr == -1 @@ -207,33 +220,49 @@ export def DiagNotification(lspserver: dict, uri: string, diags: listgetbufinfo()[0].linecount + # store the diagnostic for each line separately - var diagByLnum: dict>> = {} + var diagsByLnum: dict>> = {} + var diagWithinRange: list> = [] - for diag in diags + for diag in newDiags if diag.range.start.line + 1 > lastlnum # Make sure the line number is a valid buffer line number diag.range.start.line = lastlnum - 1 endif var lnum = diag.range.start.line + 1 - if !diagByLnum->has_key(lnum) - diagByLnum[lnum] = [] + if !diagsByLnum->has_key(lnum) + diagsByLnum[lnum] = [] endif - diagByLnum[lnum]->add(diag) + diagsByLnum[lnum]->add(diag) diagWithinRange->add(diag) endfor - # sort the diagnostics by line number and column number - var sortedDiags = SortDiags(diagWithinRange) + var serverDiags: dict> = diagsMap->has_key(bnr) ? + diagsMap[bnr].serverDiagnostics : {} + serverDiags[lspserver.id] = diagWithinRange - lspserver.diagsMap->extend({ - [$'{bnr}']: { - sortedDiagnostics: sortedDiags, - diagnosticsByLnum: diagByLnum - } - }) + var serverDiagsByLnum: dict>> = diagsMap->has_key(bnr) ? + diagsMap[bnr].serverDiagnosticsByLnum : {} + serverDiagsByLnum[lspserver.id] = diagsByLnum + + # store the diagnostic for each line separately + var joinedServerDiags: list> = [] + for diags in serverDiags->values() + for diag in diags + joinedServerDiags->add(diag) + endfor + endfor + + var sortedDiags = SortDiags(joinedServerDiags) + + diagsMap[bnr] = { + sortedDiagnostics: sortedDiags, + serverDiagnosticsByLnum: serverDiagsByLnum, + serverDiagnostics: serverDiags + } ProcessNewDiags(lspserver, bnr) @@ -251,8 +280,8 @@ export def DiagsGetErrorCount(lspserver: dict): dict var hintCount = 0 var bnr: number = bufnr() - if lspserver.diagsMap->has_key(bnr) - var diags = lspserver.diagsMap[bnr].sortedDiagnostics + if diagsMap->has_key(bnr) + var diags = diagsMap[bnr].sortedDiagnostics for diag in diags var severity = diag->get('severity', -1) if severity == 1 @@ -295,8 +324,8 @@ def DiagsUpdateLocList(lspserver: dict, bnr: number): bool LspQfId = 0 endif - if !lspserver.diagsMap->has_key(bnr) || - lspserver.diagsMap[bnr].sortedDiagnostics->empty() + if !diagsMap->has_key(bnr) || + diagsMap[bnr].sortedDiagnostics->empty() if LspQfId != 0 setloclist(0, [], 'r', {id: LspQfId, items: []}) endif @@ -306,7 +335,7 @@ def DiagsUpdateLocList(lspserver: dict, bnr: number): bool var qflist: list> = [] var text: string - var diags = lspserver.diagsMap[bnr].sortedDiagnostics + var diags = diagsMap[bnr].sortedDiagnostics for diag in diags text = diag.message->substitute("\n\\+", "\n", 'g') qflist->add({filename: fname, @@ -457,15 +486,23 @@ enddef # Get all diagnostics from the LSP server for a particular line in a file export def GetDiagsByLine(lspserver: dict, bnr: number, lnum: number): list> - if lspserver.diagsMap->has_key(bnr) - var diagsbyLnum = lspserver.diagsMap[bnr].diagnosticsByLnum - if diagsbyLnum->has_key(lnum) - return diagsbyLnum[lnum]->sort((a, b) => { - return a.range.start.character - b.range.start.character - }) - endif + if !diagsMap->has_key(bnr) + return [] endif - return [] + + var diags: list> = [] + + var serverDiagsByLnum = diagsMap[bnr].serverDiagnosticsByLnum + + for diagsByLnum in serverDiagsByLnum->values() + if diagsByLnum->has_key(lnum) + diags->extend(diagsByLnum[lnum]) + endif + endfor + + return diags->sort((a, b) => { + return a.range.start.character - b.range.start.character + }) enddef # Utility function to do the actual jump @@ -485,13 +522,13 @@ export def LspDiagsJump(lspserver: dict, which: string, a_count: number = 0 endif var bnr: number = bufnr() - if !lspserver.diagsMap->has_key(bnr) || - lspserver.diagsMap[bnr].sortedDiagnostics->empty() + if !diagsMap->has_key(bnr) || + diagsMap[bnr].sortedDiagnostics->empty() util.WarnMsg($'No diagnostic messages found for {fname}') return endif - var diags = lspserver.diagsMap[bnr].sortedDiagnostics + var diags = diagsMap[bnr].sortedDiagnostics if which == 'first' JumpDiag(diags[0]) diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index 74e0914..5c50b23 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -1498,7 +1498,6 @@ export def NewLspServer(name_arg: string, path_arg: string, args: list, signaturePopup: -1, typeHierPopup: -1, typeHierFilePopup: -1, - diagsMap: {}, workspaceSymbolPopup: -1, workspaceSymbolQuery: '', peekSymbolPopup: -1, -- 2.50.0