diff options
Diffstat (limited to 'runtime/lua/vim/lsp/util.lua')
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 106 |
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} } |