From c0833c30c8d7c3bb00b6386d6e7ad36fb0dbe13f Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Fri, 30 Jun 2023 21:37:26 -0700 Subject: [PATCH] When applying text edits and restoring eol, ignore empty lines. Optimize use of range Dict by using local variables --- autoload/lsp/diag.vim | 68 ++++++++++++++++++++++--------------- autoload/lsp/inlayhints.vim | 6 ++-- autoload/lsp/lsp.vim | 8 +++-- autoload/lsp/lspserver.vim | 10 +++--- autoload/lsp/outline.vim | 11 +++--- autoload/lsp/selection.vim | 20 ++++++----- autoload/lsp/symbol.vim | 32 ++++++++++------- autoload/lsp/textedit.vim | 19 ++++++----- autoload/lsp/util.vim | 5 +-- 9 files changed, 106 insertions(+), 73 deletions(-) diff --git a/autoload/lsp/diag.vim b/autoload/lsp/diag.vim index 3238d74..a892b74 100644 --- a/autoload/lsp/diag.vim +++ b/autoload/lsp/diag.vim @@ -108,9 +108,11 @@ enddef # Sort diagnostics ascending based on line and character offset def SortDiags(diags: list>): list> return diags->sort((a, b) => { - var linediff = a.range.start.line - b.range.start.line + var a_start = a.range.start + var b_start = b.range.start + var linediff = a_start.line - b_start.line if linediff == 0 - return a.range.start.character - b.range.start.character + return a_start.character - b_start.character endif return linediff }) @@ -227,7 +229,9 @@ def DiagsRefresh(bnr: number) for diag in diags # TODO: prioritize most important severity if there are multiple diagnostics # from the same line - var lnum = diag.range.start.line + 1 + var d_start = diag.range.start + var d_end = diag.range.end + var lnum = d_start.line + 1 if opt.lspOptions.showDiagWithSign signs->add({id: 0, buffer: bnr, group: 'LSPDiag', lnum: lnum, name: DiagSevToSignName(diag.severity), @@ -236,12 +240,11 @@ def DiagsRefresh(bnr: number) try if opt.lspOptions.highlightDiagInline - prop_add(diag.range.start.line + 1, - util.GetLineByteFromPos(bnr, diag.range.start) + 1, - {end_lnum: diag.range.end.line + 1, - end_col: util.GetLineByteFromPos(bnr, diag.range.end) + 1, - bufnr: bnr, - type: DiagSevToInlineHLName(diag.severity)}) + prop_add(lnum, util.GetLineByteFromPos(bnr, d_start) + 1, + {end_lnum: d_end.line + 1, + end_col: util.GetLineByteFromPos(bnr, d_end) + 1, + bufnr: bnr, + type: DiagSevToInlineHLName(diag.severity)}) endif if opt.lspOptions.showDiagWithVirtualText @@ -253,10 +256,10 @@ def DiagsRefresh(bnr: number) padding = 3 symbol = DiagSevToSymbolText(diag.severity) else - var charIdx = util.GetCharIdxWithoutCompChar(bnr, diag.range.start) + var charIdx = util.GetCharIdxWithoutCompChar(bnr, d_start) padding = charIdx if padding > 0 - padding = strdisplaywidth(getline(diag.range.start.line + 1)[ : charIdx - 1]) + padding = strdisplaywidth(getline(lnum)[ : charIdx - 1]) endif endif @@ -285,14 +288,16 @@ def SendAleDiags(bnr: number, timerid: number) endif # Convert to Ale's diagnostics format (:h ale-loclist-format) - ale#other_source#ShowResults(bnr, 'lsp', diagsMap[bnr].sortedDiagnostics->mapnew((_, v) => { + ale#other_source#ShowResults(bnr, 'lsp', + diagsMap[bnr].sortedDiagnostics->mapnew((_, v) => { return {text: v.message, lnum: v.range.start.line + 1, col: util.GetLineByteFromPos(bnr, v.range.start) + 1, end_lnum: v.range.end.line + 1, end_col: util.GetLineByteFromPos(bnr, v.range.end) + 1, type: "EWIH"[v.severity - 1]} - })) + }) + ) enddef # Hook called when Ale wants to retrieve new diagnostics @@ -332,8 +337,9 @@ enddef # Notification: textDocument/publishDiagnostics # Param: PublishDiagnosticsParams export def DiagNotification(lspserver: dict, uri: string, diags_arg: list>): void - # Diagnostics are disabled for this server - if lspserver.features->has_key('diagnostics') && !lspserver.features.diagnostics + # Diagnostics are disabled for this server? + var diagSupported = lspserver.features->get('diagnostics', true) + if !diagSupported return endif @@ -366,12 +372,13 @@ export def DiagNotification(lspserver: dict, uri: string, diags_arg: list> = [] for diag in newDiags - if diag.range.start.line + 1 > lastlnum + var d_start = diag.range.start + if d_start.line + 1 > lastlnum # Make sure the line number is a valid buffer line number - diag.range.start.line = lastlnum - 1 + d_start.line = lastlnum - 1 endif - var lnum = diag.range.start.line + 1 + var lnum = d_start.line + 1 if !diagsByLnum->has_key(lnum) diagsByLnum[lnum] = [] endif @@ -485,12 +492,14 @@ def DiagsUpdateLocList(bnr: number, calledByCmd: bool = false): bool var diags = diagsMap[bnr].sortedDiagnostics for diag in diags + var d_start = diag.range.start + var d_end = diag.range.end 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, - end_lnum: diag.range.end.line + 1, - end_col: util.GetLineByteFromPos(bnr, diag.range.end) + 1, + lnum: d_start.line + 1, + col: util.GetLineByteFromPos(bnr, d_start) + 1, + end_lnum: d_end.line + 1, + end_col: util.GetLineByteFromPos(bnr, d_end) + 1, text: text, type: DiagSevToQfType(diag.severity)}) endfor @@ -531,9 +540,10 @@ enddef # Display the message of "diag" in a popup window right below the position in # the diagnostic message. def ShowDiagInPopup(diag: dict) - var dlnum = diag.range.start.line + 1 + var d_start = diag.range.start + var dlnum = d_start.line + 1 var ltext = dlnum->getline() - var dlcol = ltext->byteidxcomp(diag.range.start.character) + 1 + var dlcol = ltext->byteidxcomp(d_start.character) + 1 var lastline = line('$') if dlnum > lastline @@ -622,8 +632,9 @@ export def GetDiagByPos(bnr: number, lnum: number, col: number, var diags_in_line = GetDiagsByLine(bnr, lnum) for diag in diags_in_line - var startCharIdx = util.GetCharIdxWithoutCompChar(bnr, diag.range.start) - var endCharIdx = util.GetCharIdxWithoutCompChar(bnr, diag.range.end) + var r = diag.range + var startCharIdx = util.GetCharIdxWithoutCompChar(bnr, r.start) + var endCharIdx = util.GetCharIdxWithoutCompChar(bnr, r.end) if atPos if col >= startCharIdx + 1 && col < endCharIdx + 1 return diag @@ -715,8 +726,9 @@ export def LspDiagsJump(which: string, a_count: number = 0): void var curcol: number = charcol('.') for diag in (which == 'next' || which == 'here') ? diags : diags->copy()->reverse() - var lnum = diag.range.start.line + 1 - var col = util.GetCharIdxWithoutCompChar(bnr, diag.range.start) + 1 + var d_start = diag.range.start + var lnum = d_start.line + 1 + var col = util.GetCharIdxWithoutCompChar(bnr, d_start) + 1 if (which == 'next' && (lnum > curlnum || lnum == curlnum && col > curcol)) || (which == 'prev' && (lnum < curlnum || lnum == curlnum && col < curcol)) diff --git a/autoload/lsp/inlayhints.vim b/autoload/lsp/inlayhints.vim index a44e3fc..37efdc4 100644 --- a/autoload/lsp/inlayhints.vim +++ b/autoload/lsp/inlayhints.vim @@ -9,8 +9,10 @@ import './options.vim' as opt # Initialize the highlight group and the text property type used for # inlay hints. export def InitOnce() - hlset([{name: 'LspInlayHintsType', default: true, linksto: 'Label'}]) - hlset([{name: 'LspInlayHintsParam', default: true, linksto: 'Conceal'}]) + hlset([ + {name: 'LspInlayHintsType', default: true, linksto: 'Label'}, + {name: 'LspInlayHintsParam', default: true, linksto: 'Conceal'} + ]) prop_type_add('LspInlayHintsType', {highlight: 'LspInlayHintsType'}) prop_type_add('LspInlayHintsParam', {highlight: 'LspInlayHintsParam'}) enddef diff --git a/autoload/lsp/lsp.vim b/autoload/lsp/lsp.vim index 43f96c5..a949407 100644 --- a/autoload/lsp/lsp.vim +++ b/autoload/lsp/lsp.vim @@ -31,9 +31,11 @@ var ftypeServerMap: dict>> = {} var lspInitializedOnce = false def LspInitOnce() - hlset([{name: 'LspTextRef', default: true, linksto: 'Search'}]) - hlset([{name: 'LspReadRef', default: true, linksto: 'DiffChange'}]) - hlset([{name: 'LspWriteRef', default: true, linksto: 'DiffDelete'}]) + hlset([ + {name: 'LspTextRef', default: true, linksto: 'Search'}, + {name: 'LspReadRef', default: true, linksto: 'DiffChange'}, + {name: 'LspWriteRef', default: true, linksto: 'DiffDelete'} + ]) var override = &cursorline && &cursorlineopt =~ '\\|\\|\' diff --git a/autoload/lsp/lspserver.vim b/autoload/lsp/lspserver.vim index e5cb731..9d888c8 100644 --- a/autoload/lsp/lspserver.vim +++ b/autoload/lsp/lspserver.vim @@ -964,10 +964,12 @@ def DocHighlightReply(lspserver: dict, docHighlightReply: any, propName = 'LspTextRef' endif try - prop_add(docHL.range.start.line + 1, - util.GetLineByteFromPos(bnr, docHL.range.start) + 1, - {end_lnum: docHL.range.end.line + 1, - end_col: util.GetLineByteFromPos(bnr, docHL.range.end) + 1, + var docHL_start = docHL.range.start + var docHL_end = docHL.range.end + prop_add(docHL_start.line + 1, + util.GetLineByteFromPos(bnr, docHL_start) + 1, + {end_lnum: docHL_end.line + 1, + end_col: util.GetLineByteFromPos(bnr, docHL_end) + 1, bufnr: bnr, type: propName}) catch /E966\|E964/ # Invalid lnum | Invalid col diff --git a/autoload/lsp/outline.vim b/autoload/lsp/outline.vim index 2979d20..dd7a049 100644 --- a/autoload/lsp/outline.vim +++ b/autoload/lsp/outline.vim @@ -82,8 +82,9 @@ def AddSymbolText(bnr: number, for s in symbols text->add(prefix .. s.name) # remember the line number for the symbol - var start_col: number = util.GetLineByteFromPos(bnr, s.range.start) + 1 - lnumMap->add({name: s.name, lnum: s.range.start.line + 1, + var s_start = s.range.start + var start_col: number = util.GetLineByteFromPos(bnr, s_start) + 1 + lnumMap->add({name: s.name, lnum: s_start.line + 1, col: start_col}) s.outlineLine = lnumMap->len() if s->has_key('children') && !s.children->empty() @@ -172,11 +173,11 @@ def OutlineHighlightCurrentSymbol() var mid: number while left <= right mid = (left + right) / 2 - if lnum >= (symbolTable[mid].range.start.line + 1) && - lnum <= (symbolTable[mid].range.end.line + 1) + var r = symbolTable[mid].range + if lnum >= (r.start.line + 1) && lnum <= (r.end.line + 1) break endif - if lnum > (symbolTable[mid].range.start.line + 1) + if lnum > (r.start.line + 1) left = mid + 1 else right = mid - 1 diff --git a/autoload/lsp/selection.vim b/autoload/lsp/selection.vim index 51467f1..1ef289b 100644 --- a/autoload/lsp/selection.vim +++ b/autoload/lsp/selection.vim @@ -6,12 +6,14 @@ import './util.vim' # Visually (character-wise) select the text in a range def SelectText(bnr: number, range: dict>) - var start_col: number = util.GetLineByteFromPos(bnr, range.start) + 1 - var end_col: number = util.GetLineByteFromPos(bnr, range.end) + var rstart = range.start + var rend = range.end + var start_col: number = util.GetLineByteFromPos(bnr, rstart) + 1 + var end_col: number = util.GetLineByteFromPos(bnr, rend) :normal! v"_y - setcharpos("'<", [0, range.start.line + 1, start_col, 0]) - setcharpos("'>", [0, range.end.line + 1, end_col, 0]) + setcharpos("'<", [0, rstart.line + 1, start_col, 0]) + setcharpos("'>", [0, rend.line + 1, end_col, 0]) :normal! gv enddef @@ -48,10 +50,12 @@ enddef # Returns true if the current visual selection matches a range in the # selection reply from LSP. def SelectionFromLSP(range: dict, startpos: list, endpos: list): bool - return startpos[1] == range.start.line + 1 - && endpos[1] == range.end.line + 1 - && startpos[2] == range.start.character + 1 - && endpos[2] == range.end.character + var rstart = range.start + var rend = range.end + return startpos[1] == rstart.line + 1 + && endpos[1] == rend.line + 1 + && startpos[2] == rstart.character + 1 + && endpos[2] == rend.character enddef # Expand or Shrink the current selection or start a new one. diff --git a/autoload/lsp/symbol.vim b/autoload/lsp/symbol.vim index 0be5300..6b9ac09 100644 --- a/autoload/lsp/symbol.vim +++ b/autoload/lsp/symbol.vim @@ -14,12 +14,14 @@ import './outline.vim' # document symbol search export def InitOnce() # Use a high priority value to override other highlights in the line - hlset([{name: 'LspSymbolName', default: true, linksto: 'Search'}]) + hlset([ + {name: 'LspSymbolName', default: true, linksto: 'Search'}, + {name: 'LspSymbolRange', default: true, linksto: 'Visual'} + ]) prop_type_add('LspSymbolNameProp', {highlight: 'LspSymbolName', combine: false, override: true, priority: 201}) - hlset([{name: 'LspSymbolRange', default: true, linksto: 'Visual'}]) prop_type_add('LspSymbolRangeProp', {highlight: 'LspSymbolRange', combine: false, override: true, @@ -307,17 +309,18 @@ def UpdatePeekFilePopup(lspserver: dict, locations: list>) } lspserver.peekSymbolFilePopup = popup_create(bnr, popupAttrs) + var rstart = range.start var cmds =<< trim eval END :setlocal number - [{range.start.line + 1}, 1]->cursor() + [{rstart.line + 1}, 1]->cursor() :normal! z. END win_execute(lspserver.peekSymbolFilePopup, cmds) lspserver.peekSymbolFilePopup->clearmatches() - var start_col = util.GetLineByteFromPos(bnr, range.start) + 1 + var start_col = util.GetLineByteFromPos(bnr, rstart) + 1 var end_col = util.GetLineByteFromPos(bnr, range.end) - var pos = [[range.start.line + 1, + var pos = [[rstart.line + 1, start_col, end_col - start_col + 1]] matchaddpos('Search', pos, 10, -1, {window: lspserver.peekSymbolFilePopup}) enddef @@ -425,10 +428,11 @@ export def ShowLocations(lspserver: dict, locations: list>, bnr = fname->bufadd() endif :silent! bnr->bufload() - var text: string = bnr->getbufline(range.start.line + 1)->get(0, '')->trim("\t ", 1) + var rstart = range.start + var text: string = bnr->getbufline(rstart.line + 1)->get(0, '')->trim("\t ", 1) qflist->add({filename: fname, - lnum: range.start.line + 1, - col: util.GetLineByteFromPos(bnr, range.start) + 1, + lnum: rstart.line + 1, + col: util.GetLineByteFromPos(bnr, rstart) + 1, text: text}) endfor @@ -499,13 +503,14 @@ def PeekSymbolLocation(lspserver: dict, location: dict) var pos: list = [] var start_col: number var end_col: number - start_col = util.GetLineByteFromPos(pwbuf, range.start) + 1 + var rstart = range.start + start_col = util.GetLineByteFromPos(pwbuf, rstart) + 1 end_col = util.GetLineByteFromPos(pwbuf, range.end) + 1 - pos->add(range.start.line + 1) + pos->add(rstart.line + 1) pos->extend([start_col, end_col - start_col]) matchaddpos('Search', [pos], 10, 101, {window: pwid}) var cmds =<< trim eval END - [{range.start.line + 1}, 1]->cursor() + [{rstart.line + 1}, 1]->cursor() :normal! z. END win_execute(pwid, cmds, 'silent!') @@ -539,8 +544,9 @@ export def TagFunc(lspserver: dict, var [uri, range] = util.LspLocationParse(tagloc) tagitem.filename = util.LspUriToFile(uri) var bnr = util.LspUriToBufnr(uri) - var startByteIdx = util.GetLineByteFromPos(bnr, range.start) - tagitem.cmd = $"/\\%{range.start.line + 1}l\\%{startByteIdx + 1}c" + var rstart = range.start + var startByteIdx = util.GetLineByteFromPos(bnr, rstart) + tagitem.cmd = $"/\\%{rstart.line + 1}l\\%{startByteIdx + 1}c" retval->add(tagitem) endfor diff --git a/autoload/lsp/textedit.vim b/autoload/lsp/textedit.vim index 5c11408..0ea69fb 100644 --- a/autoload/lsp/textedit.vim +++ b/autoload/lsp/textedit.vim @@ -119,12 +119,15 @@ export def ApplyTextEdits(bnr: number, text_edits: list>): void var idx = 0 for e in text_edits # Adjust the start and end columns for multibyte characters - start_row = e.range.start.line - start_col = util.GetCharIdxWithoutCompChar(bnr, e.range.start) - end_row = e.range.end.line - end_col = util.GetCharIdxWithoutCompChar(bnr, e.range.end) - start_line = [e.range.start.line, start_line]->min() - finish_line = [e.range.end.line, finish_line]->max() + var r = e.range + var rstart: dict = r.start + var rend: dict = r.end + start_row = rstart.line + start_col = util.GetCharIdxWithoutCompChar(bnr, rstart) + end_row = rend.line + end_col = util.GetCharIdxWithoutCompChar(bnr, rend) + start_line = [rstart.line, start_line]->min() + finish_line = [rend.line, finish_line]->max() updated_edits->add({A: [start_row, start_col], B: [end_row, end_col], @@ -140,7 +143,7 @@ export def ApplyTextEdits(bnr: number, text_edits: list>): void var lines: list = bnr->getbufline(start_line + 1, finish_line + 1) var fix_eol: bool = bnr->getbufvar('&fixeol') var set_eol = fix_eol && bnr->getbufinfo()[0].linecount <= finish_line + 1 - if set_eol && lines[-1]->len() != 0 + if !lines->empty() && set_eol && lines[-1]->len() != 0 lines->add('') endif @@ -156,7 +159,7 @@ export def ApplyTextEdits(bnr: number, text_edits: list>): void #echomsg $'lines(2) = {string(lines)}' # If the last line is empty and we need to set EOL, then remove it. - if set_eol && lines[-1]->len() == 0 + if !lines->empty() && set_eol && lines[-1]->len() == 0 lines->remove(-1) endif diff --git a/autoload/lsp/util.vim b/autoload/lsp/util.vim index aefe766..34fc5a6 100644 --- a/autoload/lsp/util.vim +++ b/autoload/lsp/util.vim @@ -301,8 +301,9 @@ export def JumpToLspLocation(location: dict, cmdmods: string) exe $'{cmdmods} sbuffer {bnr}' endif endif - setcursorcharpos(range.start.line + 1, - GetCharIdxWithoutCompChar(bufnr(), range.start) + 1) + var rstart = range.start + setcursorcharpos(rstart.line + 1, + GetCharIdxWithoutCompChar(bufnr(), rstart) + 1) :normal! zv enddef -- 2.48.1