mirror of
https://github.com/neovim/neovim
synced 2025-07-16 17:21:49 +00:00
feat(lsp): improve control over placement of floating windows (#24494)
This commit is contained in:
@ -1580,7 +1580,8 @@ hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()*
|
|||||||
• {config} (table) Configuration table.
|
• {config} (table) Configuration table.
|
||||||
• border: (default=nil)
|
• border: (default=nil)
|
||||||
• Add borders to the floating window
|
• Add borders to the floating window
|
||||||
• See |nvim_open_win()|
|
• See |vim.lsp.util.open_floating_preview()| for more
|
||||||
|
options.
|
||||||
|
|
||||||
*vim.lsp.handlers.signature_help()*
|
*vim.lsp.handlers.signature_help()*
|
||||||
signature_help({_}, {result}, {ctx}, {config})
|
signature_help({_}, {result}, {ctx}, {config})
|
||||||
@ -1599,7 +1600,8 @@ signature_help({_}, {result}, {ctx}, {config})
|
|||||||
• {config} (table) Configuration table.
|
• {config} (table) Configuration table.
|
||||||
• border: (default=nil)
|
• border: (default=nil)
|
||||||
• Add borders to the floating window
|
• Add borders to the floating window
|
||||||
• See |nvim_open_win()|
|
• See |vim.lsp.util.open_floating_preview()| for more
|
||||||
|
options
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
@ -1791,6 +1793,13 @@ make_floating_popup_options({width}, {height}, {opts})
|
|||||||
• focusable (string or table) override `focusable`
|
• focusable (string or table) override `focusable`
|
||||||
• zindex (string or table) override `zindex`, defaults to 50
|
• zindex (string or table) override `zindex`, defaults to 50
|
||||||
• relative ("mouse"|"cursor") defaults to "cursor"
|
• relative ("mouse"|"cursor") defaults to "cursor"
|
||||||
|
• anchor_bias ("auto"|"above"|"below") defaults to "auto"
|
||||||
|
• "auto": place window based on which side of the cursor
|
||||||
|
has more lines
|
||||||
|
• "above": place the window above the cursor unless there
|
||||||
|
are not enough lines to display the full window height.
|
||||||
|
• "below": place the window below the cursor unless there
|
||||||
|
are not enough lines to display the full window height.
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
(table) Options
|
(table) Options
|
||||||
@ -1892,8 +1901,9 @@ open_floating_preview({contents}, {syntax}, {opts})
|
|||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {contents} (table) of lines to show in window
|
• {contents} (table) of lines to show in window
|
||||||
• {syntax} (string) of syntax to set for opened buffer
|
• {syntax} (string) of syntax to set for opened buffer
|
||||||
• {opts} (table) with optional fields (additional keys are passed
|
• {opts} (table) with optional fields (additional keys are filtered
|
||||||
on to |nvim_open_win()|)
|
with |vim.lsp.util.make_floating_popup_options()| before
|
||||||
|
they are passed on to |nvim_open_win()|)
|
||||||
• height: (integer) height of floating window
|
• height: (integer) height of floating window
|
||||||
• width: (integer) width of floating window
|
• width: (integer) width of floating window
|
||||||
• wrap: (boolean, default true) wrap long lines
|
• wrap: (boolean, default true) wrap long lines
|
||||||
|
@ -120,6 +120,8 @@ The following new APIs and features were added.
|
|||||||
indicator to see if a server supports a feature. Instead use
|
indicator to see if a server supports a feature. Instead use
|
||||||
`client.supports_method(<method>)`. It considers both the dynamic
|
`client.supports_method(<method>)`. It considers both the dynamic
|
||||||
capabilities and static `server_capabilities`.
|
capabilities and static `server_capabilities`.
|
||||||
|
• Added a new `anchor_bias` option to |lsp-handlers| to aid in positioning of
|
||||||
|
floating windows.
|
||||||
|
|
||||||
• Treesitter
|
• Treesitter
|
||||||
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
|
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
|
||||||
|
@ -355,7 +355,7 @@ end
|
|||||||
---@param config table Configuration table.
|
---@param config table Configuration table.
|
||||||
--- - border: (default=nil)
|
--- - border: (default=nil)
|
||||||
--- - Add borders to the floating window
|
--- - Add borders to the floating window
|
||||||
--- - See |nvim_open_win()|
|
--- - See |vim.lsp.util.open_floating_preview()| for more options.
|
||||||
function M.hover(_, result, ctx, config)
|
function M.hover(_, result, ctx, config)
|
||||||
config = config or {}
|
config = config or {}
|
||||||
config.focus_id = ctx.method
|
config.focus_id = ctx.method
|
||||||
@ -442,7 +442,7 @@ M[ms.textDocument_implementation] = location_handler
|
|||||||
---@param config table Configuration table.
|
---@param config table Configuration table.
|
||||||
--- - border: (default=nil)
|
--- - border: (default=nil)
|
||||||
--- - Add borders to the floating window
|
--- - Add borders to the floating window
|
||||||
--- - See |nvim_open_win()|
|
--- - See |vim.lsp.util.open_floating_preview()| for more options
|
||||||
function M.signature_help(_, result, ctx, config)
|
function M.signature_help(_, result, ctx, config)
|
||||||
config = config or {}
|
config = config or {}
|
||||||
config.focus_id = ctx.method
|
config.focus_id = ctx.method
|
||||||
|
@ -1087,6 +1087,12 @@ end
|
|||||||
--- - focusable (string or table) override `focusable`
|
--- - focusable (string or table) override `focusable`
|
||||||
--- - zindex (string or table) override `zindex`, defaults to 50
|
--- - zindex (string or table) override `zindex`, defaults to 50
|
||||||
--- - relative ("mouse"|"cursor") defaults to "cursor"
|
--- - relative ("mouse"|"cursor") defaults to "cursor"
|
||||||
|
--- - anchor_bias ("auto"|"above"|"below") defaults to "auto"
|
||||||
|
--- - "auto": place window based on which side of the cursor has more lines
|
||||||
|
--- - "above": place the window above the cursor unless there are not enough lines
|
||||||
|
--- to display the full window height.
|
||||||
|
--- - "below": place the window below the cursor unless there are not enough lines
|
||||||
|
--- to display the full window height.
|
||||||
---@return table Options
|
---@return table Options
|
||||||
function M.make_floating_popup_options(width, height, opts)
|
function M.make_floating_popup_options(width, height, opts)
|
||||||
validate({
|
validate({
|
||||||
@ -1105,7 +1111,20 @@ function M.make_floating_popup_options(width, height, opts)
|
|||||||
or vim.fn.winline() - 1
|
or vim.fn.winline() - 1
|
||||||
local lines_below = vim.fn.winheight(0) - lines_above
|
local lines_below = vim.fn.winheight(0) - lines_above
|
||||||
|
|
||||||
if lines_above < lines_below then
|
local anchor_bias = opts.anchor_bias or 'auto'
|
||||||
|
|
||||||
|
local anchor_below
|
||||||
|
|
||||||
|
if anchor_bias == 'below' then
|
||||||
|
anchor_below = (lines_below > lines_above) or (height <= lines_below)
|
||||||
|
elseif anchor_bias == 'above' then
|
||||||
|
local anchor_above = (lines_above > lines_below) or (height <= lines_above)
|
||||||
|
anchor_below = not anchor_above
|
||||||
|
else
|
||||||
|
anchor_below = lines_below > lines_above
|
||||||
|
end
|
||||||
|
|
||||||
|
if anchor_below then
|
||||||
anchor = anchor .. 'N'
|
anchor = anchor .. 'N'
|
||||||
height = math.min(lines_below, height)
|
height = math.min(lines_below, height)
|
||||||
row = 1
|
row = 1
|
||||||
@ -1635,7 +1654,8 @@ end
|
|||||||
---
|
---
|
||||||
---@param contents table of lines to show in window
|
---@param contents table of lines to show in window
|
||||||
---@param syntax string of syntax to set for opened buffer
|
---@param syntax string of syntax to set for opened buffer
|
||||||
---@param opts table with optional fields (additional keys are passed on to |nvim_open_win()|)
|
---@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()|
|
||||||
|
--- before they are passed on to |nvim_open_win()|)
|
||||||
--- - height: (integer) height of floating window
|
--- - height: (integer) height of floating window
|
||||||
--- - width: (integer) width of floating window
|
--- - width: (integer) width of floating window
|
||||||
--- - wrap: (boolean, default true) wrap long lines
|
--- - wrap: (boolean, default true) wrap long lines
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
local helpers = require('test.functional.helpers')(after_each)
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
local feed = helpers.feed
|
||||||
|
|
||||||
local eq = helpers.eq
|
local eq = helpers.eq
|
||||||
local exec_lua = helpers.exec_lua
|
local exec_lua = helpers.exec_lua
|
||||||
@ -85,4 +87,98 @@ describe('vim.lsp.util', function()
|
|||||||
eq(expected, stylize_markdown(lines, opts))
|
eq(expected, stylize_markdown(lines, opts))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe("make_floating_popup_options", function ()
|
||||||
|
|
||||||
|
local function assert_anchor(anchor_bias, expected_anchor)
|
||||||
|
local opts = exec_lua([[
|
||||||
|
local args = { ... }
|
||||||
|
local anchor_bias = args[1]
|
||||||
|
return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
|
||||||
|
]], anchor_bias)
|
||||||
|
|
||||||
|
eq(expected_anchor, string.sub(opts.anchor, 1, 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
local screen
|
||||||
|
before_each(function ()
|
||||||
|
helpers.clear()
|
||||||
|
screen = Screen.new(80, 80)
|
||||||
|
screen:attach()
|
||||||
|
feed("79i<CR><Esc>") -- fill screen with empty lines
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('when on the first line it places window below', function ()
|
||||||
|
before_each(function ()
|
||||||
|
feed('gg')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "auto"', function ()
|
||||||
|
assert_anchor('auto', 'N')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "above"', function ()
|
||||||
|
assert_anchor('above', 'N')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "below"', function ()
|
||||||
|
assert_anchor('below', 'N')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('when on the last line it places window above', function ()
|
||||||
|
before_each(function ()
|
||||||
|
feed('G')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "auto"', function ()
|
||||||
|
assert_anchor('auto', 'S')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "above"', function ()
|
||||||
|
assert_anchor('above', 'S')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('for anchor_bias = "below"', function ()
|
||||||
|
assert_anchor('below', 'S')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('with 20 lines above, 59 lines below', function ()
|
||||||
|
before_each(function ()
|
||||||
|
feed('gg20j')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window below for anchor_bias = "auto"', function ()
|
||||||
|
assert_anchor('auto', 'N')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window above for anchor_bias = "above"', function ()
|
||||||
|
assert_anchor('above', 'S')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window below for anchor_bias = "below"', function ()
|
||||||
|
assert_anchor('below', 'N')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('with 59 lines above, 20 lines below', function ()
|
||||||
|
before_each(function ()
|
||||||
|
feed('G20k')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window above for anchor_bias = "auto"', function ()
|
||||||
|
assert_anchor('auto', 'S')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window above for anchor_bias = "above"', function ()
|
||||||
|
assert_anchor('above', 'S')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('places window below for anchor_bias = "below"', function ()
|
||||||
|
assert_anchor('below', 'N')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user