From 870ca1de52b240926b88f01afa697cd9b119bdac Mon Sep 17 00:00:00 2001 From: Sebastian Lyng Johansen Date: Tue, 10 Jan 2023 11:22:41 +0100 Subject: feat(float): open float relative to mouse #21531 Problem: No easy way to position a LSP hover window relative to mouse. Solution: Introduce another option to the `relative` key in `nvim_open_win()`. With this PR it should be possible to override the handler and do something similar to this https://github.com/neovim/neovim/pull/19481#issuecomment-1193248674 to have hover information displayed from the mouse. Test case: ```lua local util = require('vim.lsp.util') local function make_position_param(window, offset_encoding) window = window or 0 local buf = vim.api.nvim_win_get_buf(window) local row, col local mouse = vim.fn.getmousepos() row = mouse.line col = mouse.column offset_encoding = offset_encoding or util._get_offset_encoding(buf) row = row - 1 local line = vim.api.nvim_buf_get_lines(buf, row, row + 1, true)[1] if not line then return { line = 0, character = 0 } end if #line < col then return { line = 0, character = 0 } end col = util._str_utfindex_enc(line, col, offset_encoding) return { line = row, character = col } end local make_params = function(window, offset_encoding) window = window or 0 local buf = vim.api.nvim_win_get_buf(window) offset_encoding = offset_encoding or util._get_offset_encoding(buf) return { textDocument = util.make_text_document_params(buf), position = make_position_param(window, offset_encoding), } end local hover_timer = nil vim.o.mousemoveevent = true vim.keymap.set({ '', 'i' }, '', function() if hover_timer then hover_timer:close() end hover_timer = vim.defer_fn(function() hover_timer = nil local params = make_params() vim.lsp.buf_request( 0, 'textDocument/hover', params, vim.lsp.with(vim.lsp.handlers.hover, { silent = true, focusable = false, relative = 'mouse', }) ) end, 500) return '' end, { expr = true }) ``` --- src/nvim/api/win_config.c | 3 +++ src/nvim/buffer_defs.h | 3 ++- src/nvim/window.c | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3fdd062ef0..f81d26b486 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -74,6 +74,7 @@ /// - "editor" The global editor grid /// - "win" Window given by the `win` field, or current window. /// - "cursor" Cursor position in current window. +/// - "mouse" Mouse position /// - win: |window-ID| for relative="win". /// - anchor: Decides which corner of the float to place at (row,col): /// - "NW" northwest (default) @@ -349,6 +350,8 @@ static bool parse_float_relative(String relative, FloatRelative *out) *out = kFloatRelativeWindow; } else if (striequal(str, "cursor")) { *out = kFloatRelativeCursor; + } else if (striequal(str, "mouse")) { + *out = kFloatRelativeMouse; } else { return false; } diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 7442e60024..40249c2f9d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1028,10 +1028,11 @@ typedef enum { kFloatRelativeEditor = 0, kFloatRelativeWindow = 1, kFloatRelativeCursor = 2, + kFloatRelativeMouse = 3, } FloatRelative; EXTERN const char *const float_relative_str[] INIT(= { "editor", "win", - "cursor" }); + "cursor", "mouse" }); typedef enum { kWinStyleUnused = 0, diff --git a/src/nvim/window.c b/src/nvim/window.c index 5c05417dd8..37f297909a 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -804,6 +804,15 @@ void win_config_float(win_T *wp, FloatConfig fconfig) fconfig.row += curwin->w_wrow; fconfig.col += curwin->w_wcol; fconfig.window = curwin->handle; + } else if (fconfig.relative == kFloatRelativeMouse) { + int row = mouse_row, col = mouse_col, grid = mouse_grid; + win_T *mouse_win = mouse_find_win(&grid, &row, &col); + if (mouse_win != NULL) { + fconfig.relative = kFloatRelativeWindow; + fconfig.row += row; + fconfig.col += col; + fconfig.window = mouse_win->handle; + } } bool change_external = fconfig.external != wp->w_float_config.external; -- cgit