mirror of
https://github.com/neovim/neovim.git
synced 2024-12-25 05:35:10 -07:00
refactor(lsp): consolidate the different floating window methods into open_floating_preview
This commit is contained in:
parent
192f89ea1b
commit
64da499ac2
@ -1151,6 +1151,7 @@ function M.show_line_diagnostics(opts, bufnr, line_nr, client_id)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.focus_id = "line_diagnostics"
|
||||||
local popup_bufnr, winnr = util.open_floating_preview(lines, 'plaintext', opts)
|
local popup_bufnr, winnr = util.open_floating_preview(lines, 'plaintext', opts)
|
||||||
for i, hi in ipairs(highlights) do
|
for i, hi in ipairs(highlights) do
|
||||||
local prefixlen, hiname = unpack(hi)
|
local prefixlen, hiname = unpack(hi)
|
||||||
|
@ -260,7 +260,7 @@ end
|
|||||||
--- - See |vim.api.nvim_open_win()|
|
--- - See |vim.api.nvim_open_win()|
|
||||||
function M.hover(_, method, result, _, _, config)
|
function M.hover(_, method, result, _, _, config)
|
||||||
config = config or {}
|
config = config or {}
|
||||||
local bufnr, winnr = util.focusable_float(method, function()
|
config.focus_id = method
|
||||||
if not (result and result.contents) then
|
if not (result and result.contents) then
|
||||||
-- return { 'No information available' }
|
-- return { 'No information available' }
|
||||||
return
|
return
|
||||||
@ -271,11 +271,7 @@ function M.hover(_, method, result, _, _, config)
|
|||||||
-- return { 'No information available' }
|
-- return { 'No information available' }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local bufnr, winnr = util.fancy_floating_markdown(markdown_lines, config)
|
return util.open_floating_preview(markdown_lines, "markdown", config)
|
||||||
util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, winnr)
|
|
||||||
return bufnr, winnr
|
|
||||||
end)
|
|
||||||
return bufnr, winnr
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
|
||||||
@ -333,13 +329,13 @@ M['textDocument/implementation'] = location_handler
|
|||||||
--- - See |vim.api.nvim_open_win()|
|
--- - See |vim.api.nvim_open_win()|
|
||||||
function M.signature_help(_, method, result, _, bufnr, config)
|
function M.signature_help(_, method, result, _, bufnr, config)
|
||||||
config = config or {}
|
config = config or {}
|
||||||
|
config.focus_id = method
|
||||||
-- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler
|
-- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler
|
||||||
-- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
|
-- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
|
||||||
if not (result and result.signatures and result.signatures[1]) then
|
if not (result and result.signatures and result.signatures[1]) then
|
||||||
print('No signature help available')
|
print('No signature help available')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local p_bufnr, winnr = util.focusable_float(method, function()
|
|
||||||
local ft = api.nvim_buf_get_option(bufnr, 'filetype')
|
local ft = api.nvim_buf_get_option(bufnr, 'filetype')
|
||||||
local lines = util.convert_signature_help_to_markdown_lines(result, ft)
|
local lines = util.convert_signature_help_to_markdown_lines(result, ft)
|
||||||
lines = util.trim_empty_lines(lines)
|
lines = util.trim_empty_lines(lines)
|
||||||
@ -347,12 +343,7 @@ function M.signature_help(_, method, result, _, bufnr, config)
|
|||||||
print('No signature help available')
|
print('No signature help available')
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local p_bufnr, p_winnr = util.fancy_floating_markdown(lines, config)
|
return util.open_floating_preview(lines, "markdown", config)
|
||||||
util.close_preview_autocmd({"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"}, p_winnr)
|
|
||||||
|
|
||||||
return p_bufnr, p_winnr
|
|
||||||
end)
|
|
||||||
return p_bufnr, winnr
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
|
||||||
|
@ -975,6 +975,8 @@ function M.preview_location(location, opts)
|
|||||||
-- An empty syntax is more common now with TreeSitter, since TS disables syntax.
|
-- An empty syntax is more common now with TreeSitter, since TS disables syntax.
|
||||||
syntax = api.nvim_buf_get_option(bufnr, 'filetype')
|
syntax = api.nvim_buf_get_option(bufnr, 'filetype')
|
||||||
end
|
end
|
||||||
|
opts = opts or {}
|
||||||
|
opts.focus_id = "location"
|
||||||
return M.open_floating_preview(contents, syntax, opts)
|
return M.open_floating_preview(contents, syntax, opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -997,7 +999,9 @@ end
|
|||||||
---buffer id, the newly created window will be the new focus associated with
|
---buffer id, the newly created window will be the new focus associated with
|
||||||
---the current buffer via the tag `unique_name`.
|
---the current buffer via the tag `unique_name`.
|
||||||
--@returns (pbufnr, pwinnr) if `fn()` has created a new window; nil otherwise
|
--@returns (pbufnr, pwinnr) if `fn()` has created a new window; nil otherwise
|
||||||
|
---@deprecated please use open_floating_preview directly
|
||||||
function M.focusable_float(unique_name, fn)
|
function M.focusable_float(unique_name, fn)
|
||||||
|
vim.notify("focusable_float is deprecated. Please use open_floating_preview and pass focus_id = [unique_name] instead", vim.log.levels.WARN)
|
||||||
-- Go back to previous window if we are in a focusable one
|
-- Go back to previous window if we are in a focusable one
|
||||||
if npcall(api.nvim_win_get_var, 0, unique_name) then
|
if npcall(api.nvim_win_get_var, 0, unique_name) then
|
||||||
return api.nvim_command("wincmd p")
|
return api.nvim_command("wincmd p")
|
||||||
@ -1026,10 +1030,10 @@ end
|
|||||||
--@param fn (function) The return values of this function will be passed
|
--@param fn (function) The return values of this function will be passed
|
||||||
---directly to |vim.lsp.util.open_floating_preview()|, in the case that a new
|
---directly to |vim.lsp.util.open_floating_preview()|, in the case that a new
|
||||||
---floating window should be created
|
---floating window should be created
|
||||||
|
---@deprecated please use open_floating_preview directly
|
||||||
function M.focusable_preview(unique_name, fn)
|
function M.focusable_preview(unique_name, fn)
|
||||||
return M.focusable_float(unique_name, function()
|
vim.notify("focusable_preview is deprecated. Please use open_floating_preview and pass focus_id = [unique_name] instead", vim.log.levels.WARN)
|
||||||
return M.open_floating_preview(fn())
|
return M.open_floating_preview(fn(), {focus_id = unique_name})
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Trims empty lines from input and pad top and bottom with empty lines
|
--- Trims empty lines from input and pad top and bottom with empty lines
|
||||||
@ -1061,13 +1065,20 @@ end
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- TODO: refactor to separate stripping/converting and make use of open_floating_preview
|
--- @deprecated please use open_floating_preview directly
|
||||||
--
|
function M.fancy_floating_markdown(contents, opts)
|
||||||
|
vim.notify("fancy_floating_markdown is deprecated. Please use open_floating_preview and pass focus_id = [unique_name] instead", vim.log.levels.WARN)
|
||||||
|
return M.open_floating_preview(contents, "markdown", opts)
|
||||||
|
end
|
||||||
|
|
||||||
--- Converts markdown into syntax highlighted regions by stripping the code
|
--- Converts markdown into syntax highlighted regions by stripping the code
|
||||||
--- blocks and converting them into highlighted code.
|
--- blocks and converting them into highlighted code.
|
||||||
--- This will by default insert a blank line separator after those code block
|
--- This will by default insert a blank line separator after those code block
|
||||||
--- regions to improve readability.
|
--- regions to improve readability.
|
||||||
--- The result is shown in a floating preview.
|
---
|
||||||
|
--- This method configures the given buffer and returns the lines to set.
|
||||||
|
---
|
||||||
|
--- If you want to open a popup with fancy markdown, use `open_floating_preview` instead
|
||||||
---
|
---
|
||||||
---@param contents table of lines to show in window
|
---@param contents table of lines to show in window
|
||||||
---@param opts dictionary with optional fields
|
---@param opts dictionary with optional fields
|
||||||
@ -1082,7 +1093,7 @@ end
|
|||||||
--- - pad_bottom number of lines to pad contents at bottom
|
--- - pad_bottom number of lines to pad contents at bottom
|
||||||
--- - separator insert separator after code block
|
--- - separator insert separator after code block
|
||||||
---@returns width,height size of float
|
---@returns width,height size of float
|
||||||
function M.fancy_floating_markdown(contents, opts)
|
function M.stylize_markdown(bufnr, contents, opts)
|
||||||
validate {
|
validate {
|
||||||
contents = { contents, 't' };
|
contents = { contents, 't' };
|
||||||
opts = { opts, 't', true };
|
opts = { opts, 't', true };
|
||||||
@ -1154,24 +1165,13 @@ function M.fancy_floating_markdown(contents, opts)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Make the floating window.
|
|
||||||
local bufnr = api.nvim_create_buf(false, true)
|
|
||||||
local winnr = api.nvim_open_win(bufnr, false, M.make_floating_popup_options(width, height, opts))
|
|
||||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
|
||||||
api.nvim_buf_set_option(bufnr, 'modifiable', false)
|
|
||||||
api.nvim_buf_set_option(bufnr, 'bufhidden', 'wipe')
|
|
||||||
|
|
||||||
-- Switch to the floating window to apply the syntax highlighting.
|
|
||||||
-- This is because the syntax command doesn't accept a target.
|
|
||||||
local cwin = vim.api.nvim_get_current_win()
|
|
||||||
vim.api.nvim_set_current_win(winnr)
|
|
||||||
api.nvim_win_set_option(winnr, 'conceallevel', 2)
|
|
||||||
api.nvim_win_set_option(winnr, 'concealcursor', 'n')
|
|
||||||
|
|
||||||
vim.cmd("ownsyntax lsp_markdown")
|
|
||||||
|
|
||||||
local idx = 1
|
local idx = 1
|
||||||
--@private
|
--@private
|
||||||
|
-- keep track of syntaxes we already inlcuded.
|
||||||
|
-- no need to include the same syntax more than once
|
||||||
|
local langs = {}
|
||||||
local function apply_syntax_to_region(ft, start, finish)
|
local function apply_syntax_to_region(ft, start, finish)
|
||||||
if ft == "" then
|
if ft == "" then
|
||||||
vim.cmd(string.format("syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend", start, finish + 1))
|
vim.cmd(string.format("syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend", start, finish + 1))
|
||||||
@ -1180,21 +1180,37 @@ function M.fancy_floating_markdown(contents, opts)
|
|||||||
local name = ft..idx
|
local name = ft..idx
|
||||||
idx = idx + 1
|
idx = idx + 1
|
||||||
local lang = "@"..ft:upper()
|
local lang = "@"..ft:upper()
|
||||||
|
if not langs[lang] then
|
||||||
-- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
|
-- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
|
||||||
pcall(vim.api.nvim_buf_del_var, bufnr, "current_syntax")
|
pcall(vim.api.nvim_buf_del_var, bufnr, "current_syntax")
|
||||||
-- TODO(ashkan): better validation before this.
|
-- TODO(ashkan): better validation before this.
|
||||||
if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then
|
if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
langs[lang] = true
|
||||||
|
end
|
||||||
vim.cmd(string.format("syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend", name, start, finish + 1, lang))
|
vim.cmd(string.format("syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend", name, start, finish + 1, lang))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- needs to run in the buffer for the regions to work
|
||||||
|
api.nvim_buf_call(bufnr, function()
|
||||||
|
-- we need to apply lsp_markdown regions speperately, since otherwise
|
||||||
|
-- markdown regions can "bleed" through the other syntax regions
|
||||||
|
-- and mess up the formatting
|
||||||
|
local last = 1
|
||||||
for _, h in ipairs(highlights) do
|
for _, h in ipairs(highlights) do
|
||||||
apply_syntax_to_region(h.ft, h.start, h.finish)
|
if last < h.start then
|
||||||
|
apply_syntax_to_region("lsp_markdown", last, h.start - 1)
|
||||||
end
|
end
|
||||||
|
apply_syntax_to_region(h.ft, h.start, h.finish)
|
||||||
|
last = h.finish + 1
|
||||||
|
end
|
||||||
|
if last < #stripped then
|
||||||
|
apply_syntax_to_region("lsp_markdown", last, #stripped)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(cwin)
|
return stripped
|
||||||
return bufnr, winnr
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creates autocommands to close a preview window when events happen.
|
--- Creates autocommands to close a preview window when events happen.
|
||||||
@ -1203,7 +1219,9 @@ end
|
|||||||
--@param winnr (number) window id of preview window
|
--@param winnr (number) window id of preview window
|
||||||
--@see |autocmd-events|
|
--@see |autocmd-events|
|
||||||
function M.close_preview_autocmd(events, winnr)
|
function M.close_preview_autocmd(events, winnr)
|
||||||
|
if #events > 0 then
|
||||||
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
|
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--@internal
|
--@internal
|
||||||
@ -1288,13 +1306,16 @@ end
|
|||||||
--@param opts dictionary with optional fields
|
--@param opts dictionary with optional fields
|
||||||
-- - height of floating window
|
-- - height of floating window
|
||||||
-- - width of floating window
|
-- - width of floating window
|
||||||
-- - wrap_at character to wrap at for computing height
|
-- - wrap boolean enable wrapping of long lines (defaults to true)
|
||||||
|
-- - wrap_at character to wrap at for computing height when wrap is enabled
|
||||||
-- - max_width maximal width of floating window
|
-- - max_width maximal width of floating window
|
||||||
-- - max_height maximal height of floating window
|
-- - max_height maximal height of floating window
|
||||||
-- - pad_left number of columns to pad contents at left
|
-- - pad_left number of columns to pad contents at left
|
||||||
-- - pad_right number of columns to pad contents at right
|
-- - pad_right number of columns to pad contents at right
|
||||||
-- - pad_top number of lines to pad contents at top
|
-- - pad_top number of lines to pad contents at top
|
||||||
-- - pad_bottom number of lines to pad contents at bottom
|
-- - pad_bottom number of lines to pad contents at bottom
|
||||||
|
-- - focus_id if a popup with this id is opened, then focus it
|
||||||
|
-- - close_events list of events that closes the floating window
|
||||||
--@returns bufnr,winnr buffer and window number of the newly created floating
|
--@returns bufnr,winnr buffer and window number of the newly created floating
|
||||||
---preview window
|
---preview window
|
||||||
function M.open_floating_preview(contents, syntax, opts)
|
function M.open_floating_preview(contents, syntax, opts)
|
||||||
@ -1304,27 +1325,77 @@ function M.open_floating_preview(contents, syntax, opts)
|
|||||||
opts = { opts, 't', true };
|
opts = { opts, 't', true };
|
||||||
}
|
}
|
||||||
opts = opts or {}
|
opts = opts or {}
|
||||||
|
opts.wrap = opts.wrap ~= false -- wrapping by default
|
||||||
|
opts.stylize_markdown = opts.stylize_markdown ~= false
|
||||||
|
opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"}
|
||||||
|
|
||||||
|
local bufnr = api.nvim_get_current_buf()
|
||||||
|
|
||||||
|
-- check if this popup is focusable and we need to focus
|
||||||
|
if opts.focus_id then
|
||||||
|
-- Go back to previous window if we are in a focusable one
|
||||||
|
local current_winnr = api.nvim_get_current_win()
|
||||||
|
if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then
|
||||||
|
api.nvim_command("wincmd p")
|
||||||
|
return bufnr, current_winnr
|
||||||
|
end
|
||||||
|
do
|
||||||
|
local win = find_window_by_var(opts.focus_id, bufnr)
|
||||||
|
if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
|
||||||
|
-- focus and return the existing buf, win
|
||||||
|
api.nvim_set_current_win(win)
|
||||||
|
api.nvim_command("stopinsert")
|
||||||
|
return api.nvim_win_get_buf(win), win
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local floating_bufnr = api.nvim_create_buf(false, true)
|
||||||
|
local do_stylize = syntax == "markdown" and opts.stylize_markdown
|
||||||
|
|
||||||
|
|
||||||
-- Clean up input: trim empty lines from the end, pad
|
-- Clean up input: trim empty lines from the end, pad
|
||||||
contents = M._trim(contents, opts)
|
contents = M._trim(contents, opts)
|
||||||
|
|
||||||
-- Compute size of float needed to show (wrapped) lines
|
if do_stylize then
|
||||||
opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0))
|
-- applies the syntax and sets the lines to the buffer
|
||||||
local width, height = M._make_floating_popup_size(contents, opts)
|
contents = M.stylize_markdown(floating_bufnr, contents, opts)
|
||||||
|
else
|
||||||
local floating_bufnr = api.nvim_create_buf(false, true)
|
|
||||||
if syntax then
|
if syntax then
|
||||||
api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
|
api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
|
||||||
end
|
end
|
||||||
|
api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Compute size of float needed to show (wrapped) lines
|
||||||
|
if opts.wrap then
|
||||||
|
opts.wrap_at = opts.wrap_at or api.nvim_win_get_width(0)
|
||||||
|
else
|
||||||
|
opts.wrap_at = nil
|
||||||
|
end
|
||||||
|
local width, height = M._make_floating_popup_size(contents, opts)
|
||||||
|
|
||||||
local float_option = M.make_floating_popup_options(width, height, opts)
|
local float_option = M.make_floating_popup_options(width, height, opts)
|
||||||
local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
|
local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
|
||||||
if syntax == 'markdown' then
|
if do_stylize then
|
||||||
api.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
|
api.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
|
||||||
|
api.nvim_win_set_option(floating_winnr, 'concealcursor', 'n')
|
||||||
end
|
end
|
||||||
api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
|
-- disable folding
|
||||||
|
api.nvim_win_set_option(floating_winnr, 'foldenable', false)
|
||||||
|
-- soft wrapping
|
||||||
|
api.nvim_win_set_option(floating_winnr, 'wrap', opts.wrap)
|
||||||
|
|
||||||
api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
|
api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
|
||||||
api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
|
api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
|
||||||
M.close_preview_autocmd({"CursorMoved", "CursorMovedI", "BufHidden", "BufLeave"}, floating_winnr)
|
api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "<cmd>bdelete<cr>", {silent = true, noremap = true})
|
||||||
|
M.close_preview_autocmd(opts.close_events, floating_winnr)
|
||||||
|
|
||||||
|
-- save focus_id
|
||||||
|
if opts.focus_id then
|
||||||
|
api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
|
||||||
|
end
|
||||||
|
|
||||||
return floating_bufnr, floating_winnr
|
return floating_bufnr, floating_winnr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
" URL: http://neovim.io
|
" URL: http://neovim.io
|
||||||
" Remark: Uses markdown syntax file
|
" Remark: Uses markdown syntax file
|
||||||
|
|
||||||
runtime! syntax/markdown.vim
|
" always source the system included markdown instead of any other installed
|
||||||
|
" markdown.vim syntax files
|
||||||
|
execute 'source' expand('<sfile>:p:h') .. '/markdown.vim'
|
||||||
|
|
||||||
syn cluster mkdNonListItem add=mkdEscape,mkdNbsp
|
syn cluster mkdNonListItem add=mkdEscape,mkdNbsp
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user