feat(lsp): improve LSP doc hover rendering #30695

Problem:
- Some servers like LuaLS add unwanted blank lines after multiline
  `@param` description.
- List items do not wrap nicely.

Solution:
- When rendering the LSP doc hover, remove blank lines in each `@param`
  or `@return`.
  - But ensure exactly one empty line before each.
- Set 'breakindent'.
This commit is contained in:
Justin M. Keyes
2024-10-06 12:20:40 -07:00
committed by GitHub
parent 5da2a171f7
commit 27f3750817
2 changed files with 82 additions and 11 deletions

View File

@@ -99,9 +99,26 @@ local function get_border_size(opts)
return { height = height, width = width }
end
local function split_lines(value)
value = string.gsub(value, '\r\n?', '\n')
return split(value, '\n', { plain = true, trimempty = true })
--- Splits string at newlines, optionally removing unwanted blank lines.
---
--- @param s string Multiline string
--- @param no_blank boolean? Drop blank lines for each @param/@return (except one empty line
--- separating each). Workaround for https://github.com/LuaLS/lua-language-server/issues/2333
local function split_lines(s, no_blank)
s = string.gsub(s, '\r\n?', '\n')
local lines = {}
local in_desc = true -- Main description block, before seeing any @foo.
for line in vim.gsplit(s, '\n', { plain = true, trimempty = true }) do
local start_annotation = not not line:find('^ ?%@.?[pr]')
in_desc = (not start_annotation) and in_desc or false
if start_annotation and no_blank and not (lines[#lines] or ''):find('^%s*$') then
table.insert(lines, '') -- Separate each @foo with a blank line.
end
if in_desc or not no_blank or not line:find('^%s*$') then
table.insert(lines, line)
end
end
return lines
end
local function create_window_without_focus()
@@ -116,7 +133,7 @@ end
--- Convenience wrapper around vim.str_utfindex
---@param line string line to be indexed
---@param index integer|nil byte index (utf-8), or `nil` for length
---@param encoding string|nil utf-8|utf-16|utf-32|nil defaults to utf-16
---@param encoding 'utf-8'|'utf-16'|'utf-32'|nil defaults to utf-16
---@return integer `encoding` index of `index` in `line`
function M._str_utfindex_enc(line, index, encoding)
local len32, len16 = vim.str_utfindex(line)
@@ -735,13 +752,13 @@ function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
-- MarkedString variation 1
if type(input) == 'string' then
list_extend(contents, split_lines(input))
list_extend(contents, split_lines(input, true))
else
assert(type(input) == 'table', 'Expected a table for LSP input')
-- MarkupContent
if input.kind then
local value = input.value or ''
list_extend(contents, split_lines(value))
list_extend(contents, split_lines(value, true))
-- MarkupString variation 2
elseif input.language then
table.insert(contents, '```' .. input.language)
@@ -1633,10 +1650,9 @@ function M.open_floating_preview(contents, syntax, opts)
if do_stylize then
vim.wo[floating_winnr].conceallevel = 2
end
-- disable folding
vim.wo[floating_winnr].foldenable = false
-- soft wrapping
vim.wo[floating_winnr].wrap = opts.wrap
vim.wo[floating_winnr].foldenable = false -- Disable folding.
vim.wo[floating_winnr].wrap = opts.wrap -- Soft wrapping.
vim.wo[floating_winnr].breakindent = true -- Slightly better list presentation.
vim.bo[floating_bufnr].modifiable = false
vim.bo[floating_bufnr].bufhidden = 'wipe'