aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFolke Lemaitre <folke.lemaitre@gmail.com>2021-05-26 23:47:53 +0200
committerFolke Lemaitre <folke.lemaitre@gmail.com>2021-05-29 13:42:15 +0200
commit64da499ac25bd833c57e0850e31affd22294049e (patch)
treeec999ccf318043a0301ac8b5cc67880a55ff4aeb
parent192f89ea1bdb86e8d12a9940872f92f0fc88b300 (diff)
downloadrneovim-64da499ac25bd833c57e0850e31affd22294049e.tar.gz
rneovim-64da499ac25bd833c57e0850e31affd22294049e.tar.bz2
rneovim-64da499ac25bd833c57e0850e31affd22294049e.zip
refactor(lsp): consolidate the different floating window methods into open_floating_preview
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua1
-rw-r--r--runtime/lua/vim/lsp/handlers.lua51
-rw-r--r--runtime/lua/vim/lsp/util.lua153
-rw-r--r--runtime/syntax/lsp_markdown.vim4
4 files changed, 137 insertions, 72 deletions
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 6f2f846a3b..6a7dc1bbb0 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -1151,6 +1151,7 @@ function M.show_line_diagnostics(opts, bufnr, line_nr, client_id)
end
end
+ opts.focus_id = "line_diagnostics"
local popup_bufnr, winnr = util.open_floating_preview(lines, 'plaintext', opts)
for i, hi in ipairs(highlights) do
local prefixlen, hiname = unpack(hi)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 18155ceb7e..6ae54ea253 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -260,22 +260,18 @@ end
--- - See |vim.api.nvim_open_win()|
function M.hover(_, method, result, _, _, config)
config = config or {}
- local bufnr, winnr = util.focusable_float(method, function()
- if not (result and result.contents) then
- -- return { 'No information available' }
- return
- end
- local markdown_lines = util.convert_input_to_markdown_lines(result.contents)
- markdown_lines = util.trim_empty_lines(markdown_lines)
- if vim.tbl_isempty(markdown_lines) then
- -- return { 'No information available' }
- return
- end
- local bufnr, winnr = util.fancy_floating_markdown(markdown_lines, config)
- util.close_preview_autocmd({"CursorMoved", "BufHidden", "InsertCharPre"}, winnr)
- return bufnr, winnr
- end)
- return bufnr, winnr
+ config.focus_id = method
+ if not (result and result.contents) then
+ -- return { 'No information available' }
+ return
+ end
+ local markdown_lines = util.convert_input_to_markdown_lines(result.contents)
+ markdown_lines = util.trim_empty_lines(markdown_lines)
+ if vim.tbl_isempty(markdown_lines) then
+ -- return { 'No information available' }
+ return
+ end
+ return util.open_floating_preview(markdown_lines, "markdown", config)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
@@ -333,26 +329,21 @@ M['textDocument/implementation'] = location_handler
--- - See |vim.api.nvim_open_win()|
function M.signature_help(_, method, result, _, bufnr, config)
config = config or {}
+ config.focus_id = method
-- 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 not (result and result.signatures and result.signatures[1]) then
print('No signature help available')
return
end
- local p_bufnr, winnr = util.focusable_float(method, function()
- local ft = api.nvim_buf_get_option(bufnr, 'filetype')
- local lines = util.convert_signature_help_to_markdown_lines(result, ft)
- lines = util.trim_empty_lines(lines)
- if vim.tbl_isempty(lines) then
- print('No signature help available')
- return
- end
- local p_bufnr, p_winnr = util.fancy_floating_markdown(lines, config)
- util.close_preview_autocmd({"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"}, p_winnr)
-
- return p_bufnr, p_winnr
- end)
- return p_bufnr, winnr
+ local ft = api.nvim_buf_get_option(bufnr, 'filetype')
+ local lines = util.convert_signature_help_to_markdown_lines(result, ft)
+ lines = util.trim_empty_lines(lines)
+ if vim.tbl_isempty(lines) then
+ print('No signature help available')
+ return
+ end
+ return util.open_floating_preview(lines, "markdown", config)
end
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index ad60d1bb03..e2cd01b698 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -975,6 +975,8 @@ function M.preview_location(location, opts)
-- An empty syntax is more common now with TreeSitter, since TS disables syntax.
syntax = api.nvim_buf_get_option(bufnr, 'filetype')
end
+ opts = opts or {}
+ opts.focus_id = "location"
return M.open_floating_preview(contents, syntax, opts)
end
@@ -997,7 +999,9 @@ end
---buffer id, the newly created window will be the new focus associated with
---the current buffer via the tag `unique_name`.
--@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)
+ 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
if npcall(api.nvim_win_get_var, 0, unique_name) then
return api.nvim_command("wincmd p")
@@ -1026,10 +1030,10 @@ end
--@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
---floating window should be created
+---@deprecated please use open_floating_preview directly
function M.focusable_preview(unique_name, fn)
- return M.focusable_float(unique_name, function()
- return M.open_floating_preview(fn())
- end)
+ 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(), {focus_id = unique_name})
end
--- 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
--- blocks and converting them into highlighted code.
--- This will by default insert a blank line separator after those code block
--- 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 opts dictionary with optional fields
@@ -1082,7 +1093,7 @@ end
--- - pad_bottom number of lines to pad contents at bottom
--- - separator insert separator after code block
---@returns width,height size of float
-function M.fancy_floating_markdown(contents, opts)
+function M.stylize_markdown(bufnr, contents, opts)
validate {
contents = { contents, 't' };
opts = { opts, 't', true };
@@ -1154,24 +1165,13 @@ function M.fancy_floating_markdown(contents, opts)
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)
- 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
--@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)
if ft == "" then
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
idx = idx + 1
local lang = "@"..ft:upper()
- -- 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")
- -- TODO(ashkan): better validation before this.
- if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then
- return
+ if not langs[lang] then
+ -- 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")
+ -- TODO(ashkan): better validation before this.
+ if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then
+ return
+ end
+ langs[lang] = true
end
vim.cmd(string.format("syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend", name, start, finish + 1, lang))
end
- for _, h in ipairs(highlights) do
- apply_syntax_to_region(h.ft, h.start, h.finish)
- 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
+ if last < h.start then
+ apply_syntax_to_region("lsp_markdown", last, h.start - 1)
+ 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 bufnr, winnr
+ return stripped
end
--- Creates autocommands to close a preview window when events happen.
@@ -1203,7 +1219,9 @@ end
--@param winnr (number) window id of preview window
--@see |autocmd-events|
function M.close_preview_autocmd(events, winnr)
- api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
+ if #events > 0 then
+ api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
+ end
end
--@internal
@@ -1288,13 +1306,16 @@ end
--@param opts dictionary with optional fields
-- - height 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_height maximal height of floating window
-- - pad_left number of columns to pad contents at left
-- - pad_right number of columns to pad contents at right
-- - pad_top number of lines to pad contents at top
-- - 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
---preview window
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 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
contents = M._trim(contents, opts)
+ if do_stylize then
+ -- applies the syntax and sets the lines to the buffer
+ contents = M.stylize_markdown(floating_bufnr, contents, opts)
+ else
+ if syntax then
+ api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
+ end
+ api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
+ end
+
-- 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))
+ 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 floating_bufnr = api.nvim_create_buf(false, true)
- if syntax then
- api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
- end
local float_option = M.make_floating_popup_options(width, height, opts)
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, 'concealcursor', 'n')
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, '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
end
diff --git a/runtime/syntax/lsp_markdown.vim b/runtime/syntax/lsp_markdown.vim
index d5c1414f01..d9b50be54c 100644
--- a/runtime/syntax/lsp_markdown.vim
+++ b/runtime/syntax/lsp_markdown.vim
@@ -4,7 +4,9 @@
" URL: http://neovim.io
" 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