3 # Functions related to handling LSP diagnostics.
5 import './options.vim' as opt
6 import './buffer.vim' as buf
10 # serverDiagnostics: {
11 # lspServer1Id: [diag, diag, diag]
12 # lspServer2Id: [diag, diag, diag]
14 # serverDiagnosticsByLnum: {
15 # lspServer1Id: { [lnum]: [diag, diag diag] },
16 # lspServer2Id: { [lnum]: [diag, diag diag] },
18 # sortedDiagnostics: [lspServer1.diags, ...lspServer2.diags]->sort()
20 var diagsMap: dict<dict<any>> = {}
22 # Initialize the signs and the text property type used for diagnostics.
24 # Signs and their highlight groups used for LSP diagnostics
26 {name: 'LspDiagLine', default: true, linksto: 'NONE'},
27 {name: 'LspDiagSignErrorText', default: true, linksto: 'ErrorMsg'},
28 {name: 'LspDiagSignWarningText', default: true, linksto: 'Search'},
29 {name: 'LspDiagSignInfoText', default: true, linksto: 'Pmenu'},
30 {name: 'LspDiagSignHintText', default: true, linksto: 'Question'}
35 text: opt.lspOptions.diagSignErrorText,
36 texthl: 'LspDiagSignErrorText',
40 name: 'LspDiagWarning',
41 text: opt.lspOptions.diagSignWarningText,
42 texthl: 'LspDiagSignWarningText',
47 text: opt.lspOptions.diagSignInfoText,
48 texthl: 'LspDiagSignInfoText',
53 text: opt.lspOptions.diagSignHintText,
54 texthl: 'LspDiagSignHintText',
59 # Diag inline highlight groups and text property types
61 {name: 'LspDiagInlineError', default: true, linksto: 'SpellBad'},
62 {name: 'LspDiagInlineWarning', default: true, linksto: 'SpellCap'},
63 {name: 'LspDiagInlineInfo', default: true, linksto: 'SpellRare'},
64 {name: 'LspDiagInlineHint', default: true, linksto: 'SpellLocal'}
67 var override = &cursorline
68 && &cursorlineopt =~ '\<line\>\|\<screenline\>\|\<both\>'
70 prop_type_add('LspDiagInlineError',
71 {highlight: 'LspDiagInlineError',
74 prop_type_add('LspDiagInlineWarning',
75 {highlight: 'LspDiagInlineWarning',
78 prop_type_add('LspDiagInlineInfo',
79 {highlight: 'LspDiagInlineInfo',
82 prop_type_add('LspDiagInlineHint',
83 {highlight: 'LspDiagInlineHint',
87 # Diag virtual text highlight groups and text property types
89 {name: 'LspDiagVirtualTextError', default: true, linksto: 'SpellBad'},
90 {name: 'LspDiagVirtualTextWarning', default: true, linksto: 'SpellCap'},
91 {name: 'LspDiagVirtualTextInfo', default: true, linksto: 'SpellRare'},
92 {name: 'LspDiagVirtualTextHint', default: true, linksto: 'SpellLocal'},
94 prop_type_add('LspDiagVirtualTextError',
95 {highlight: 'LspDiagVirtualTextError', override: true})
96 prop_type_add('LspDiagVirtualTextWarning',
97 {highlight: 'LspDiagVirtualTextWarning', override: true})
98 prop_type_add('LspDiagVirtualTextInfo',
99 {highlight: 'LspDiagVirtualTextInfo', override: true})
100 prop_type_add('LspDiagVirtualTextHint',
101 {highlight: 'LspDiagVirtualTextHint', override: true})
103 autocmd_add([{group: 'LspOptionsChanged',
106 cmd: 'LspDiagsOptionsChanged()'}])
109 if opt.lspOptions.aleSupport
110 opt.lspOptions.autoHighlightDiags = false
115 pattern: 'ALEWantResults',
116 cmd: 'AleHook(g:ale_want_results_buffer)'
122 # Initialize the diagnostics features for the buffer 'bnr'
123 export def BufferInit(lspserver: dict<any>, bnr: number)
124 if opt.lspOptions.showDiagInBalloon
125 :set ballooneval balloonevalterm
126 setbufvar(bnr, '&balloonexpr', 'g:LspDiagExpr()')
129 var acmds: list<dict<any>> = []
130 # Show diagnostics on the status line
131 if opt.lspOptions.showDiagOnStatusLine
132 acmds->add({bufnr: bnr,
133 event: 'CursorMoved',
134 group: 'LSPBufferAutocmds',
135 cmd: 'ShowCurrentDiagInStatusLine()'})
140 # Function to sort the diagnostics in ascending order based on the line and
142 def DiagsSortFunc(a: dict<any>, b: dict<any>): number
143 var a_start: dict<number> = a.range.start
144 var b_start: dict<number> = b.range.start
145 var linediff: number = a_start.line - b_start.line
147 return a_start.character - b_start.character
152 # Sort diagnostics ascending based on line and character offset
153 def SortDiags(diags: list<dict<any>>): list<dict<any>>
154 return diags->sort(DiagsSortFunc)
157 # Remove the diagnostics stored for buffer "bnr"
158 export def DiagRemoveFile(bnr: number)
159 if diagsMap->has_key(bnr)
160 diagsMap->remove(bnr)
164 def DiagSevToSignName(severity: number): string
165 var typeMap: list<string> = ['LspDiagError', 'LspDiagWarning',
166 'LspDiagInfo', 'LspDiagHint']
170 return typeMap[severity - 1]
173 def DiagSevToInlineHLName(severity: number): string
174 var typeMap: list<string> = [
175 'LspDiagInlineError',
176 'LspDiagInlineWarning',
181 return 'LspDiagInlineHint'
183 return typeMap[severity - 1]
186 def DiagSevToVirtualTextHLName(severity: number): string
187 var typeMap: list<string> = [
188 'LspDiagVirtualTextError',
189 'LspDiagVirtualTextWarning',
190 'LspDiagVirtualTextInfo',
191 'LspDiagVirtualTextHint'
194 return 'LspDiagVirtualTextHint'
196 return typeMap[severity - 1]
199 def DiagSevToSymbolText(severity: number): string
200 var lspOpts = opt.lspOptions
201 var typeMap: list<string> = [
202 lspOpts.diagSignErrorText,
203 lspOpts.diagSignWarningText,
204 lspOpts.diagSignInfoText,
205 lspOpts.diagSignHintText
208 return lspOpts.diagSignHintText
210 return typeMap[severity - 1]
213 # Remove signs and text properties for diagnostics in buffer
214 def RemoveDiagVisualsForBuffer(bnr: number, all: bool = false)
215 var lspOpts = opt.lspOptions
216 if lspOpts.showDiagWithSign || all
217 # Remove all the existing diagnostic signs
218 sign_unplace('LSPDiag', {buffer: bnr})
221 if lspOpts.showDiagWithVirtualText || all
222 # Remove all the existing virtual text
223 prop_remove({type: 'LspDiagVirtualTextError', bufnr: bnr, all: true})
224 prop_remove({type: 'LspDiagVirtualTextWarning', bufnr: bnr, all: true})
225 prop_remove({type: 'LspDiagVirtualTextInfo', bufnr: bnr, all: true})
226 prop_remove({type: 'LspDiagVirtualTextHint', bufnr: bnr, all: true})
229 if lspOpts.highlightDiagInline || all
230 # Remove all the existing virtual text
231 prop_remove({type: 'LspDiagInlineError', bufnr: bnr, all: true})
232 prop_remove({type: 'LspDiagInlineWarning', bufnr: bnr, all: true})
233 prop_remove({type: 'LspDiagInlineInfo', bufnr: bnr, all: true})
234 prop_remove({type: 'LspDiagInlineHint', bufnr: bnr, all: true})
238 # Refresh the placed diagnostics in buffer "bnr"
239 # This inline signs, inline props, and virtual text diagnostics
240 export def DiagsRefresh(bnr: number, all: bool = false)
241 var lspOpts = opt.lspOptions
242 if !lspOpts.autoHighlightDiags
246 :silent! bnr->bufload()
248 RemoveDiagVisualsForBuffer(bnr, all)
250 if !diagsMap->has_key(bnr) ||
251 diagsMap[bnr].sortedDiagnostics->empty()
255 # Initialize default/fallback properties for diagnostic virtual text:
256 var diag_align: string = 'above'
257 var diag_wrap: string = 'truncate'
258 var diag_symbol: string = '┌─'
260 if lspOpts.diagVirtualTextAlign == 'below'
262 diag_wrap = 'truncate'
263 diag_symbol = '└─'
264 elseif lspOpts.diagVirtualTextAlign == 'after'
270 var signs: list<dict<any>> = []
271 var diags: list<dict<any>> = diagsMap[bnr].sortedDiagnostics
272 var inlineHLprops: list<list<list<number>>> = [[], [], [], [], []]
274 # TODO: prioritize most important severity if there are multiple
275 # diagnostics from the same line
276 var d_range = diag.range
277 var d_start = d_range.start
278 var d_end = d_range.end
279 var lnum = d_start.line + 1
280 if lspOpts.showDiagWithSign
281 signs->add({id: 0, buffer: bnr, group: 'LSPDiag',
282 lnum: lnum, name: DiagSevToSignName(diag.severity),
283 priority: 10 - diag.severity})
287 if lspOpts.highlightDiagInline
288 var propLocation: list<number> = [
289 lnum, util.GetLineByteFromPos(bnr, d_start) + 1,
290 d_end.line + 1, util.GetLineByteFromPos(bnr, d_end) + 1
292 inlineHLprops[diag.severity]->add(propLocation)
295 if lspOpts.showDiagWithVirtualText
297 var symbol: string = diag_symbol
299 if diag_align == 'after'
301 symbol = DiagSevToSymbolText(diag.severity)
303 var charIdx = util.GetCharIdxWithoutCompChar(bnr, d_start)
306 padding = strdisplaywidth(getline(lnum)[ : charIdx - 1])
310 prop_add(lnum, 0, {bufnr: bnr,
311 type: DiagSevToVirtualTextHLName(diag.severity),
312 text: $'{symbol} {diag.message}',
313 text_align: diag_align,
314 text_wrap: diag_wrap,
315 text_padding_left: padding})
317 catch /E966\|E964/ # Invalid lnum | Invalid col
318 # Diagnostics arrive asynchronously and the document changed while they
319 # were in transit. Ignore this as new once will arrive shortly.
323 if lspOpts.highlightDiagInline
325 if !inlineHLprops[i]->empty()
327 prop_add_list({bufnr: bnr, type: DiagSevToInlineHLName(i)},
329 catch /E966\|E964/ # Invalid lnum | Invalid col
335 if lspOpts.showDiagWithSign
336 signs->sign_placelist()
340 # Sends diagnostics to Ale
341 def SendAleDiags(bnr: number, timerid: number)
342 if !diagsMap->has_key(bnr)
346 # Convert to Ale's diagnostics format (:h ale-loclist-format)
347 ale#other_source#ShowResults(bnr, 'lsp',
348 diagsMap[bnr].sortedDiagnostics->mapnew((_, v) => {
349 return {text: v.message,
350 lnum: v.range.start.line + 1,
351 col: util.GetLineByteFromPos(bnr, v.range.start) + 1,
352 end_lnum: v.range.end.line + 1,
353 end_col: util.GetLineByteFromPos(bnr, v.range.end) + 1,
354 type: "EWIH"[v.severity - 1]}
359 # Hook called when Ale wants to retrieve new diagnostics
360 def AleHook(bnr: number)
361 ale#other_source#StartChecking(bnr, 'lsp')
362 timer_start(0, function('SendAleDiags', [bnr]))
365 # New LSP diagnostic messages received from the server for a file.
366 # Update the signs placed in the buffer for this file
367 export def ProcessNewDiags(bnr: number)
368 DiagsUpdateLocList(bnr)
370 var lspOpts = opt.lspOptions
371 if lspOpts.aleSupport
372 SendAleDiags(bnr, -1)
375 if bnr == -1 || !diagsMap->has_key(bnr)
379 var curmode: string = mode()
380 if curmode == 'i' || curmode == 'R' || curmode == 'Rv'
381 # postpone placing signs in insert mode and replace mode. These will be
382 # placed after the user returns to Normal mode.
383 setbufvar(bnr, 'LspDiagsUpdatePending', true)
390 # process a diagnostic notification message from the LSP server
391 # Notification: textDocument/publishDiagnostics
392 # Param: PublishDiagnosticsParams
393 export def DiagNotification(lspserver: dict<any>, uri: string, diags_arg: list<dict<any>>): void
394 # Diagnostics are disabled for this server?
395 if !lspserver.featureEnabled('diagnostics')
399 var fname: string = util.LspUriToFile(uri)
400 var bnr: number = fname->bufnr()
402 # Is this condition possible?
406 var newDiags: list<dict<any>> = diags_arg
408 if lspserver.needOffsetEncoding
409 # Decode the position encoding in all the diags
410 newDiags->map((_, dval) => {
411 lspserver.decodeRange(bnr, dval.range)
416 if lspserver.processDiagHandler != null_function
417 newDiags = lspserver.processDiagHandler(diags_arg)
420 # TODO: Is the buffer (bnr) always a loaded buffer? Should we load it here?
421 var lastlnum: number = bnr->getbufinfo()[0].linecount
423 # store the diagnostic for each line separately
424 var diagsByLnum: dict<list<dict<any>>> = {}
426 var diagWithinRange: list<dict<any>> = []
428 var d_start = diag.range.start
429 if d_start.line + 1 > lastlnum
430 # Make sure the line number is a valid buffer line number
431 d_start.line = lastlnum - 1
434 var lnum = d_start.line + 1
435 if !diagsByLnum->has_key(lnum)
436 diagsByLnum[lnum] = []
438 diagsByLnum[lnum]->add(diag)
440 diagWithinRange->add(diag)
443 var serverDiags: dict<list<any>> = diagsMap->has_key(bnr) ?
444 diagsMap[bnr].serverDiagnostics : {}
445 serverDiags[lspserver.id] = diagWithinRange
447 var serverDiagsByLnum: dict<dict<list<any>>> = diagsMap->has_key(bnr) ?
448 diagsMap[bnr].serverDiagnosticsByLnum : {}
449 serverDiagsByLnum[lspserver.id] = diagsByLnum
451 # store the diagnostic for each line separately
452 var joinedServerDiags: list<dict<any>> = []
453 for diags in serverDiags->values()
454 joinedServerDiags->extend(diags)
457 var sortedDiags = SortDiags(joinedServerDiags)
460 sortedDiagnostics: sortedDiags,
461 serverDiagnosticsByLnum: serverDiagsByLnum,
462 serverDiagnostics: serverDiags
467 # Notify user scripts that diags has been updated
468 if exists('#User#LspDiagsUpdated')
469 :doautocmd <nomodeline> User LspDiagsUpdated
473 # get the count of error in the current buffer
474 export def DiagsGetErrorCount(bnr: number): dict<number>
475 var diagSevCount: list<number> = [0, 0, 0, 0, 0]
476 if diagsMap->has_key(bnr)
477 var diags = diagsMap[bnr].sortedDiagnostics
479 var severity = diag->get('severity', 0)
480 diagSevCount[severity] += 1
485 Error: diagSevCount[1],
486 Warn: diagSevCount[2],
487 Info: diagSevCount[3],
488 Hint: diagSevCount[4]
492 # Map the LSP DiagnosticSeverity to a quickfix type character
493 def DiagSevToQfType(severity: number): string
494 var typeMap: list<string> = ['E', 'W', 'I', 'N']
500 return typeMap[severity - 1]
503 # Update the location list window for the current window with the diagnostic
505 # Returns true if diagnostics is not empty and false if it is empty.
506 def DiagsUpdateLocList(bnr: number, calledByCmd: bool = false): bool
507 var fname: string = bnr->bufname()->fnamemodify(':p')
512 var LspQfId: number = bnr->getbufvar('LspQfId', 0)
513 if LspQfId == 0 && !opt.lspOptions.autoPopulateDiags && !calledByCmd
514 # Diags location list is not present. Create the location list only if
515 # the 'autoPopulateDiags' option is set or the ":LspDiag show" command is
520 if LspQfId != 0 && getloclist(0, {id: LspQfId}).id != LspQfId
521 # Previously used location list for the diagnostics is gone
525 if !diagsMap->has_key(bnr) ||
526 diagsMap[bnr].sortedDiagnostics->empty()
528 setloclist(0, [], 'r', {id: LspQfId, items: []})
533 var qflist: list<dict<any>> = []
536 var diags = diagsMap[bnr].sortedDiagnostics
538 var d_range = diag.range
539 var d_start = d_range.start
540 var d_end = d_range.end
541 text = diag.message->substitute("\n\\+", "\n", 'g')
542 qflist->add({filename: fname,
543 lnum: d_start.line + 1,
544 col: util.GetLineByteFromPos(bnr, d_start) + 1,
545 end_lnum: d_end.line + 1,
546 end_col: util.GetLineByteFromPos(bnr, d_end) + 1,
548 type: DiagSevToQfType(diag.severity)})
552 var props = {title: 'Language Server Diagnostics', items: qflist}
557 setloclist(0, [], op, props)
559 setbufvar(bnr, 'LspQfId', getloclist(0, {id: 0}).id)
565 # Display the diagnostic messages from the LSP server for the current buffer
567 export def ShowAllDiags(): void
568 var bnr: number = bufnr()
569 if !DiagsUpdateLocList(bnr, true)
570 util.WarnMsg($'No diagnostic messages found for {@%}')
574 var save_winid = win_getid()
575 # make the diagnostics error list the active one and open it
576 var LspQfId: number = bnr->getbufvar('LspQfId', 0)
577 var LspQfNr: number = getloclist(0, {id: LspQfId, nr: 0}).nr
578 exe $':{LspQfNr} lhistory'
580 if !opt.lspOptions.keepFocusInDiags
581 save_winid->win_gotoid()
585 # Display the message of "diag" in a popup window right below the position in
586 # the diagnostic message.
587 def ShowDiagInPopup(diag: dict<any>)
588 var d_start = diag.range.start
589 var dlnum = d_start.line + 1
590 var ltext = dlnum->getline()
591 var dlcol = ltext->byteidxcomp(d_start.character) + 1
593 var lastline = line('$')
595 # The line number is outside the last line in the file.
599 # The column is outside the last character in line.
600 dlcol = ltext->len() + 1
602 var d = screenpos(0, dlnum, dlcol)
604 # If the diag position cannot be converted to Vim lnum/col, then use
605 # the current cursor position
606 d = {row: line('.'), col: col('.')}
609 # Display a popup right below the diagnostics position
610 var msg = diag.message->split("\n")
611 var msglen = msg->reduce((acc, val) => max([acc, val->strcharlen()]), 0)
614 ppopts.pos = 'topleft'
615 ppopts.line = d.row + 1
626 popup_create(msg, ppopts)
629 # Display the "diag" message in a popup or in the status message area
630 def DisplayDiag(diag: dict<any>)
631 if opt.lspOptions.showDiagInPopup
632 # Display the diagnostic message in a popup window.
633 ShowDiagInPopup(diag)
635 # Display the diagnostic message in the status message area
640 # Show the diagnostic message for the current line
641 export def ShowCurrentDiag(atPos: bool)
642 var bnr: number = bufnr()
643 var lnum: number = line('.')
644 var col: number = charcol('.')
645 var diag: dict<any> = GetDiagByPos(bnr, lnum, col, atPos)
647 util.WarnMsg($'No diagnostic messages found for current {atPos ? "position" : "line"}')
653 # Show the diagnostic message for the current line without linebreak
654 def ShowCurrentDiagInStatusLine()
655 var bnr: number = bufnr()
656 var lnum: number = line('.')
657 var col: number = charcol('.')
658 var diag: dict<any> = GetDiagByPos(bnr, lnum, col)
660 # 15 is a enough length not to cause line break
661 var max_width = &columns - 15
663 if diag->has_key('code')
664 code = $'[{diag.code}] '
666 var msgNoLineBreak = code ..
667 diag.message->substitute("\n", ' ', '')->substitute("\\n", ' ', '')
668 :echo msgNoLineBreak[ : max_width]
670 # clear the previous message
675 # Get the diagnostic from the LSP server for a particular line and character
677 export def GetDiagByPos(bnr: number, lnum: number, col: number,
678 atPos: bool = false): dict<any>
679 var diags_in_line = GetDiagsByLine(bnr, lnum)
681 for diag in diags_in_line
683 var startCharIdx = util.GetCharIdxWithoutCompChar(bnr, r.start)
684 var endCharIdx = util.GetCharIdxWithoutCompChar(bnr, r.end)
686 if col >= startCharIdx + 1 && col < endCharIdx + 1
689 elseif col <= startCharIdx + 1
694 # No diagnostic to the right of the position, return the last one instead
695 if !atPos && diags_in_line->len() > 0
696 return diags_in_line[-1]
702 # Get all diagnostics from the LSP server for a particular line in a file
703 export def GetDiagsByLine(bnr: number, lnum: number, lspserver: dict<any> = null_dict): list<dict<any>>
704 if !diagsMap->has_key(bnr)
708 var diags: list<dict<any>> = []
710 var serverDiagsByLnum = diagsMap[bnr].serverDiagnosticsByLnum
712 if lspserver == null_dict
713 for diagsByLnum in serverDiagsByLnum->values()
714 if diagsByLnum->has_key(lnum)
715 diags->extend(diagsByLnum[lnum])
719 if !serverDiagsByLnum->has_key(lspserver.id)
722 if serverDiagsByLnum[lspserver.id]->has_key(lnum)
723 diags = serverDiagsByLnum[lspserver.id][lnum]
727 return diags->sort((a, b) => {
728 return a.range.start.character - b.range.start.character
732 # Utility function to do the actual jump
733 def JumpDiag(diag: dict<any>)
734 var startPos: dict<number> = diag.range.start
735 setcursorcharpos(startPos.line + 1,
736 util.GetCharIdxWithoutCompChar(bufnr(), startPos) + 1)
738 if !opt.lspOptions.showDiagWithVirtualText
744 # jump to the next/previous/first diagnostic message in the current buffer
745 export def LspDiagsJump(which: string, a_count: number = 0): void
746 var fname: string = expand('%:p')
750 var bnr: number = bufnr()
752 if !diagsMap->has_key(bnr) ||
753 diagsMap[bnr].sortedDiagnostics->empty()
754 util.WarnMsg($'No diagnostic messages found for {fname}')
758 var diags = diagsMap[bnr].sortedDiagnostics
770 # Find the entry just before the current line (binary search)
771 var count = a_count > 1 ? a_count : 1
772 var curlnum: number = line('.')
773 var curcol: number = charcol('.')
774 for diag in (which == 'next' || which == 'here') ?
775 diags : diags->copy()->reverse()
776 var d_start = diag.range.start
777 var lnum = d_start.line + 1
778 var col = util.GetCharIdxWithoutCompChar(bnr, d_start) + 1
779 if (which == 'next' && (lnum > curlnum || lnum == curlnum && col > curcol))
780 || (which == 'prev' && (lnum < curlnum || lnum == curlnum
782 || (which == 'here' && (lnum == curlnum && col >= curcol))
784 # Skip over as many diags as "count" dictates
795 # If [count] exceeded the remaining diags
796 if which == 'next' && a_count > 1 && a_count != count
801 # If [count] exceeded the previous diags
802 if which == 'prev' && a_count > 1 && a_count != count
808 util.WarnMsg('No more diagnostics found on this line')
810 util.WarnMsg('No more diagnostics found')
814 # Return the sorted diagnostics for buffer "bnr". Default is the current
815 # buffer. A copy of the diagnostics is returned so that the caller can modify
817 export def GetDiagsForBuf(bnr: number = bufnr()): list<dict<any>>
818 if !diagsMap->has_key(bnr) ||
819 diagsMap[bnr].sortedDiagnostics->empty()
823 return diagsMap[bnr].sortedDiagnostics->deepcopy()
826 # Return the diagnostic text from the LSP server for the current mouse line to
827 # display in a balloon
828 def g:LspDiagExpr(): any
829 if !opt.lspOptions.showDiagInBalloon
833 var diagsInfo: list<dict<any>> =
834 GetDiagsByLine(v:beval_bufnr, v:beval_lnum)
835 if diagsInfo->empty()
836 # No diagnostic for the current cursor location
839 var diagFound: dict<any> = {}
840 for diag in diagsInfo
842 var startcol = util.GetLineByteFromPos(v:beval_bufnr, r.start) + 1
843 var endcol = util.GetLineByteFromPos(v:beval_bufnr, r.end) + 1
844 if v:beval_col >= startcol && v:beval_col < endcol
849 if diagFound->empty()
850 # mouse is outside of the diagnostics range
854 # return the found diagnostic
855 return diagFound.message->split("\n")
858 # Track the current diagnostics auto highlight enabled/disabled state. Used
859 # when the "autoHighlightDiags" option value is changed.
860 var save_autoHighlightDiags = opt.lspOptions.autoHighlightDiags
861 var save_highlightDiagInline = opt.lspOptions.highlightDiagInline
862 var save_showDiagWithSign = opt.lspOptions.showDiagWithSign
863 var save_showDiagWithVirtualText = opt.lspOptions.showDiagWithVirtualText
865 # Enable the LSP diagnostics highlighting
866 export def DiagsHighlightEnable()
867 opt.lspOptions.autoHighlightDiags = true
868 save_autoHighlightDiags = true
869 for binfo in getbufinfo({bufloaded: true})
870 if diagsMap->has_key(binfo.bufnr)
871 DiagsRefresh(binfo.bufnr)
876 # Disable the LSP diagnostics highlighting in all the buffers
877 export def DiagsHighlightDisable()
878 # turn off all diags highlight
879 opt.lspOptions.autoHighlightDiags = false
880 save_autoHighlightDiags = false
881 for binfo in getbufinfo()
882 if diagsMap->has_key(binfo.bufnr)
883 RemoveDiagVisualsForBuffer(binfo.bufnr)
888 # Some options are changed. If 'autoHighlightDiags' option is changed, then
889 # either enable or disable diags auto highlight.
890 export def LspDiagsOptionsChanged()
891 if save_autoHighlightDiags && !opt.lspOptions.autoHighlightDiags
892 DiagsHighlightDisable()
893 elseif !save_autoHighlightDiags && opt.lspOptions.autoHighlightDiags
894 DiagsHighlightEnable()
897 if save_highlightDiagInline != opt.lspOptions.highlightDiagInline
898 || save_showDiagWithSign != opt.lspOptions.showDiagWithSign
899 || save_showDiagWithVirtualText != opt.lspOptions.showDiagWithVirtualText
900 save_highlightDiagInline = opt.lspOptions.highlightDiagInline
901 save_showDiagWithSign = opt.lspOptions.showDiagWithSign
902 save_showDiagWithVirtualText = opt.lspOptions.showDiagWithVirtualText
903 for binfo in getbufinfo({bufloaded: true})
904 if diagsMap->has_key(binfo.bufnr)
905 DiagsRefresh(binfo.bufnr, true)
911 # vim: tabstop=8 shiftwidth=2 softtabstop=2