diff options
author | Maria José Solano <majosolano99@gmail.com> | 2024-10-15 02:36:04 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-15 02:36:04 -0700 |
commit | e0a5c3bb581752569df4490b48cb54e7c1ab0613 (patch) | |
tree | 97e6936d443d2cb7f4da14a04a285ac16034f1dd /runtime/lua/vim | |
parent | 74a161477266b3c131076ac572c5d4b577593ec4 (diff) | |
download | rneovim-e0a5c3bb581752569df4490b48cb54e7c1ab0613.tar.gz rneovim-e0a5c3bb581752569df4490b48cb54e7c1ab0613.tar.bz2 rneovim-e0a5c3bb581752569df4490b48cb54e7c1ab0613.zip |
fix(lsp): handle multiline signature help labels #30460
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r-- | runtime/lua/vim/lsp/handlers.lua | 15 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 93 |
2 files changed, 69 insertions, 39 deletions
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 44548fec92..8e538242d9 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -462,6 +462,8 @@ M[ms.textDocument_typeDefinition] = location_handler --- @see # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation M[ms.textDocument_implementation] = location_handler +local sig_help_ns = api.nvim_create_namespace('vim_lsp_signature_help') + --- |lsp-handler| for the method "textDocument/signatureHelp". --- --- The active parameter is highlighted with |hl-LspSignatureActiveParameter|. @@ -476,7 +478,7 @@ M[ms.textDocument_implementation] = location_handler --- ``` --- ---@param _ lsp.ResponseError? ----@param result lsp.SignatureHelp Response from the language server +---@param result lsp.SignatureHelp? Response from the language server ---@param ctx lsp.HandlerContext Client context ---@param config table Configuration table. --- - border: (default=nil) @@ -509,10 +511,15 @@ function M.signature_help(_, result, ctx, config) return end local fbuf, fwin = util.open_floating_preview(lines, 'markdown', config) + -- Highlight the active parameter. if hl then - -- Highlight the second line if the signature is wrapped in a Markdown code block. - local line = vim.startswith(lines[1], '```') and 1 or 0 - api.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', line, unpack(hl)) + vim.highlight.range( + fbuf, + sig_help_ns, + 'LspSignatureActiveParameter', + { hl[1], hl[2] }, + { hl[3], hl[4] } + ) end return fbuf, fwin end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ebc3f7c55e..fc822f1403 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -781,24 +781,37 @@ function M.convert_input_to_markdown_lines(input, contents) return contents end +--- Returns the line/column-based position in `contents` at the given offset. +--- +---@param offset integer +---@param contents string[] +---@return { [1]: integer, [2]: integer } +local function get_pos_from_offset(offset, contents) + local i = 0 + for l, line in ipairs(contents) do + if offset >= i and offset < i + #line then + return { l - 1, offset - i + 1 } + else + i = i + #line + 1 + end + end +end + --- Converts `textDocument/signatureHelp` response to markdown lines. --- ---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp` ---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block ---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets ---@return string[]|nil table list of lines of converted markdown. ----@return number[]|nil table of active hl +---@return Range4|nil table of active hl ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) - if not signature_help.signatures then - return - end --The active signature. If omitted or the value lies outside the range of --`signatures` the value defaults to zero or is ignored if `signatures.length == 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_offset ---@type [integer, integer]|nil local active_signature = signature_help.activeSignature or 0 -- If the activeSignature is not inside the valid range, then clip it. -- In 3.15 of the protocol, activeSignature was allowed to be negative @@ -806,9 +819,6 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers active_signature = 0 end local signature = signature_help.signatures[active_signature + 1] - if not signature then - return - end local label = signature.label if ft then -- wrap inside a code block for proper rendering @@ -825,6 +835,8 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers M.convert_input_to_markdown_lines(signature.documentation, contents) end if signature.parameters and #signature.parameters > 0 then + -- First check if the signature has an activeParameter. If it doesn't check if the response + -- had that property instead. Else just default to 0. local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0) if active_parameter < 0 then active_parameter = 0 @@ -837,8 +849,8 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers end local parameter = signature.parameters[active_parameter + 1] - if parameter then - --[=[ + local parameter_label = parameter.label + --[=[ --Represents a parameter of a callable-signature. A parameter can --have a label and a doc-comment. interface ParameterInformation { @@ -856,36 +868,47 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers documentation?: string | MarkupContent; } --]=] - 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 + if type(parameter_label) == 'table' then + active_offset = parameter_label + else + local offset = 1 ---@type integer|nil + -- 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 - if parameter.documentation then - M.convert_input_to_markdown_lines(parameter.documentation, contents) + 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_offset = { offset - 1, offset + #parameter_label - 1 } + break + end + offset = offset + #param.label + 1 end end + if parameter.documentation then + M.convert_input_to_markdown_lines(parameter.documentation, contents) + end + end + + local active_hl = nil + if active_offset then + active_hl = {} + -- Account for the start of the markdown block. + if ft then + active_offset[1], active_offset[2] = + active_offset[1] + #contents[1], active_offset[2] + #contents[1] + end + + list_extend(active_hl, get_pos_from_offset(active_offset[1], contents)) + list_extend(active_hl, get_pos_from_offset(active_offset[2], contents)) end + return contents, active_hl end |