aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/util.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/lsp/util.lua')
-rw-r--r--runtime/lua/vim/lsp/util.lua106
1 files changed, 68 insertions, 38 deletions
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 195e3a0e65..d682fdc17e 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -240,6 +240,7 @@ end
--- Applies a list of text edits to a buffer.
--@param text_edits (table) list of `TextEdit` objects
--@param buf_nr (number) Buffer id
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
function M.apply_text_edits(text_edits, bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
@@ -810,16 +811,16 @@ function M.convert_input_to_markdown_lines(input, contents)
-- If it's plaintext, then wrap it in a <text></text> block
-- Some servers send input.value as empty, so let's ignore this :(
- input.value = input.value or ''
+ local value = input.value or ''
if input.kind == "plaintext" then
-- wrap this in a <text></text> block so that stylize_markdown
-- can properly process it as plaintext
- input.value = string.format("<text>\n%s\n</text>", input.value or "")
+ value = string.format("<text>\n%s\n</text>", value)
end
- -- assert(type(input.value) == 'string')
- list_extend(contents, split_lines(input.value))
+ -- assert(type(value) == 'string')
+ list_extend(contents, split_lines(value))
-- MarkupString variation 2
elseif input.language then
-- Some servers send input.value as empty, so let's ignore this :(
@@ -845,9 +846,10 @@ end
---
--@param signature_help Response of `textDocument/SignatureHelp`
--@param ft optional filetype that will be use as the `lang` for the label markdown code block
+--@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets
--@returns list of lines of converted markdown.
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
-function M.convert_signature_help_to_markdown_lines(signature_help, ft)
+function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
if not signature_help.signatures then
return
end
@@ -856,6 +858,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
--=== 0`. Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value.
local contents = {}
+ local active_hl
local active_signature = signature_help.activeSignature or 0
-- If the activeSignature is not inside the valid range, then clip it.
if active_signature >= #signature_help.signatures then
@@ -875,11 +878,17 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
if signature.parameters and #signature.parameters > 0 then
- local active_parameter = signature_help.activeParameter or 0
- -- If the activeParameter is not inside the valid range, then clip it.
+ local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0)
+ if active_parameter < 0
+ then active_parameter = 0
+ end
+
+ -- If the activeParameter is > #parameters, then set it to the last
+ -- NOTE: this is not fully according to the spec, but a client-side interpretation
if active_parameter >= #signature.parameters then
- active_parameter = 0
+ active_parameter = #signature.parameters - 1
end
+
local parameter = signature.parameters[active_parameter + 1]
if parameter then
--[=[
@@ -900,13 +909,35 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
documentation?: string | MarkupContent;
}
--]=]
- -- TODO highlight parameter
+ if parameter.label then
+ if type(parameter.label) == "table" then
+ active_hl = parameter.label
+ else
+ local offset = 1
+ -- try to set the initial offset to the first found trigger character
+ for _, t in ipairs(triggers or {}) do
+ local trigger_offset = signature.label:find(t, 1, true)
+ if trigger_offset and (offset == 1 or trigger_offset < offset) then
+ offset = trigger_offset
+ end
+ end
+ for p, param in pairs(signature.parameters) do
+ offset = signature.label:find(param.label, offset, true)
+ if not offset then break end
+ if p == active_parameter + 1 then
+ active_hl = {offset - 1, offset + #parameter.label - 1}
+ break
+ end
+ offset = offset + #param.label + 1
+ end
+ end
+ end
if parameter.documentation then
M.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
end
- return contents
+ return contents, active_hl
end
--- Creates a table with sensible default options for a floating window. The
@@ -942,7 +973,7 @@ function M.make_floating_popup_options(width, height, opts)
row = -get_border_size(opts).height
end
- if vim.fn.wincol() + width <= api.nvim_get_option('columns') then
+ if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then
anchor = anchor..'W'
col = 0
else
@@ -960,6 +991,7 @@ function M.make_floating_popup_options(width, height, opts)
style = 'minimal',
width = width,
border = opts.border or default_border,
+ zindex = opts.zindex or 50,
}
end
@@ -1129,6 +1161,8 @@ function M.stylize_markdown(bufnr, contents, opts)
-- Clean up
contents = M._trim(contents, opts)
+ -- Insert blank line separator after code block?
+ local add_sep = opts.separator == nil and true or opts.separator
local stripped = {}
local highlights = {}
-- keep track of lnums that contain markdown
@@ -1155,9 +1189,24 @@ function M.stylize_markdown(bufnr, contents, opts)
start = start + 1;
finish = #stripped;
})
+ -- add a separator, but not on the last line
+ if add_sep and i < #contents then
+ table.insert(stripped, "---")
+ markdown_lines[#stripped] = true
+ end
else
- table.insert(stripped, line)
- markdown_lines[#stripped] = true
+ -- strip any emty lines or separators prior to this separator in actual markdown
+ if line:match("^---+$") then
+ while markdown_lines[#stripped] and (stripped[#stripped]:match("^%s*$") or stripped[#stripped]:match("^---+$")) do
+ markdown_lines[#stripped] = false
+ table.remove(stripped, #stripped)
+ end
+ end
+ -- add the line if its not an empty line following a separator
+ if not (line:match("^%s*$") and markdown_lines[#stripped] and stripped[#stripped]:match("^---+$")) then
+ table.insert(stripped, line)
+ markdown_lines[#stripped] = true
+ end
i = i + 1
end
end
@@ -1165,7 +1214,7 @@ function M.stylize_markdown(bufnr, contents, opts)
-- Compute size of float needed to show (wrapped) lines
opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0))
- local width, height = M._make_floating_popup_size(stripped, opts)
+ local width = M._make_floating_popup_size(stripped, opts)
local sep_line = string.rep("─", math.min(width, opts.wrap_at or width))
@@ -1175,26 +1224,6 @@ function M.stylize_markdown(bufnr, contents, opts)
end
end
- -- Insert blank line separator after code block
- local insert_separator = opts.separator
- if insert_separator == nil then insert_separator = true end
- if insert_separator then
- local offset = 0
- for _, h in ipairs(highlights) do
- h.start = h.start + offset
- h.finish = h.finish + offset
- -- check if a seperator already exists and use that one instead of creating a new one
- if h.finish + 1 <= #stripped then
- if stripped[h.finish + 1] ~= sep_line then
- table.insert(stripped, h.finish + 1, sep_line)
- offset = offset + 1
- height = height + 1
- end
- end
- end
- end
-
-
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
local idx = 1
@@ -1455,6 +1484,7 @@ do --[[ References ]]
---
--@param bufnr buffer id
--@param references List of `DocumentHighlight` objects to highlight
+ ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
function M.buf_highlight_references(bufnr, references)
validate { bufnr = {bufnr, 'n', true} }
for _, reference in ipairs(references) do
@@ -1689,14 +1719,14 @@ end
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
- if #lines[i] > 0 then
+ if lines[i] ~= nil and #lines[i] > 0 then
start = i
break
end
end
local finish = 1
for i = #lines, 1, -1 do
- if #lines[i] > 0 then
+ if lines[i] ~= nil and #lines[i] > 0 then
finish = i
break
end
@@ -1838,10 +1868,10 @@ function M.get_effective_tabstop(bufnr)
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
end
---- Creates a `FormattingOptions` object for the current buffer and cursor position.
+--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
--@param options Table with valid `FormattingOptions` entries
---@returns `FormattingOptions object
+--@returns `DocumentFormattingParams` object
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
validate { options = {options, 't', true} }