# Sort diagnostics ascending based on line and character offset
def SortDiags(diags: list<dict<any>>): list<dict<any>>
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
})
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),
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
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
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
# Notification: textDocument/publishDiagnostics
# Param: PublishDiagnosticsParams
export def DiagNotification(lspserver: dict<any>, uri: string, diags_arg: list<dict<any>>): 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
var diagWithinRange: list<dict<any>> = []
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
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
# Display the message of "diag" in a popup window right below the position in
# the diagnostic message.
def ShowDiagInPopup(diag: dict<any>)
- 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
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
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))
# 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
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 =~ '\<line\>\|\<screenline\>\|\<both\>'
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
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()
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
# Visually (character-wise) select the text in a range
def SelectText(bnr: number, range: dict<dict<number>>)
- 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
# Returns true if the current visual selection matches a range in the
# selection reply from LSP.
def SelectionFromLSP(range: dict<any>, startpos: list<number>, endpos: list<number>): 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.
# 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,
}
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
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
var pos: list<number> = []
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!')
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
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<any> = r.start
+ var rend: dict<any> = 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],
var lines: list<string> = 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
#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
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