mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
feat(float): support callback for mouse event
This commit is contained in:
parent
9b8907d905
commit
ae4d5b83f4
@ -3198,10 +3198,15 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
|
||||
entered by |nvim_set_current_win()|, or, when the `mouse`
|
||||
field is set to true, by mouse events.
|
||||
• mouse: Specify how this window interacts with mouse
|
||||
events. Defaults to `focusable` value.
|
||||
events. May be a boolean or a Lua callback. Defaults to
|
||||
`focusable` value.
|
||||
• If false, mouse events pass through this window.
|
||||
• If true, mouse events interact with this window
|
||||
normally.
|
||||
• If a Lua callback, mouse events interact with this
|
||||
window, but the callback is called in place of the
|
||||
default handling. The default handling will be used
|
||||
again if callback returns `true`.
|
||||
• external: GUI should display the window as an external
|
||||
top-level window. Currently accepts no other positioning
|
||||
configuration together with this.
|
||||
|
5
runtime/lua/vim/_meta/api.lua
generated
5
runtime/lua/vim/_meta/api.lua
generated
@ -1770,9 +1770,12 @@ function vim.api.nvim_open_term(buffer, opts) end
|
||||
--- `nvim_set_current_win()`, or, when the `mouse` field is set to true,
|
||||
--- by mouse events.
|
||||
--- - mouse: Specify how this window interacts with mouse events.
|
||||
--- Defaults to `focusable` value.
|
||||
--- May be a boolean or a Lua callback. Defaults to `focusable` value.
|
||||
--- - If false, mouse events pass through this window.
|
||||
--- - If true, mouse events interact with this window normally.
|
||||
--- - If a Lua callback, mouse events interact with this window,
|
||||
--- but the callback is called in place of the default handling.
|
||||
--- The default handling will be used again if callback returns `true`.
|
||||
--- - external: GUI should display the window as an external
|
||||
--- top-level window. Currently accepts no other positioning
|
||||
--- configuration together with this.
|
||||
|
2
runtime/lua/vim/_meta/api_keysets.lua
generated
2
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -295,7 +295,7 @@ error('Cannot require a meta file')
|
||||
--- @field bufpos? any[]
|
||||
--- @field external? boolean
|
||||
--- @field focusable? boolean
|
||||
--- @field mouse? boolean
|
||||
--- @field mouse? any
|
||||
--- @field vertical? boolean
|
||||
--- @field zindex? integer
|
||||
--- @field border? any
|
||||
|
@ -119,7 +119,7 @@ typedef struct {
|
||||
Array bufpos;
|
||||
Boolean external;
|
||||
Boolean focusable;
|
||||
Boolean mouse;
|
||||
Object mouse;
|
||||
Boolean vertical;
|
||||
Integer zindex;
|
||||
Object border;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <lauxlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -23,6 +24,7 @@
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/grid_defs.h"
|
||||
#include "nvim/highlight_group.h"
|
||||
#include "nvim/lua/executor.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/memory.h"
|
||||
@ -132,9 +134,12 @@
|
||||
/// |nvim_set_current_win()|, or, when the `mouse` field is set to true,
|
||||
/// by mouse events.
|
||||
/// - mouse: Specify how this window interacts with mouse events.
|
||||
/// Defaults to `focusable` value.
|
||||
/// May be a boolean or a Lua callback. Defaults to `focusable` value.
|
||||
/// - If false, mouse events pass through this window.
|
||||
/// - If true, mouse events interact with this window normally.
|
||||
/// - If a Lua callback, mouse events interact with this window,
|
||||
/// but the callback is called in place of the default handling.
|
||||
/// The default handling will be used again if callback returns `true`.
|
||||
/// - external: GUI should display the window as an external
|
||||
/// top-level window. Currently accepts no other positioning
|
||||
/// configuration together with this.
|
||||
@ -719,7 +724,18 @@ Dict(win_config) nvim_win_get_config(Window window, Arena *arena, Error *err)
|
||||
PUT_KEY_X(rv, focusable, config->focusable);
|
||||
PUT_KEY_X(rv, external, config->external);
|
||||
PUT_KEY_X(rv, hide, config->hide);
|
||||
PUT_KEY_X(rv, mouse, config->mouse);
|
||||
|
||||
switch (config->mouse) {
|
||||
case kWinMouseIgnore:
|
||||
PUT_KEY_X(rv, mouse, BOOLEAN_OBJ(false));
|
||||
break;
|
||||
case kWinMouseDefault:
|
||||
PUT_KEY_X(rv, mouse, BOOLEAN_OBJ(true));
|
||||
break;
|
||||
case kWinMouseCallback:
|
||||
PUT_KEY_X(rv, mouse, LUAREF_OBJ(api_new_luaref(config->mouse_cb)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (wp->w_floating) {
|
||||
PUT_KEY_X(rv, width, config->width);
|
||||
@ -1208,11 +1224,22 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
|
||||
if (HAS_KEY_X(config, focusable)) {
|
||||
fconfig->focusable = config->focusable;
|
||||
fconfig->mouse = config->focusable;
|
||||
if (fconfig->mouse != kWinMouseCallback) {
|
||||
fconfig->mouse = config->focusable ? kWinMouseDefault : kWinMouseIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, mouse)) {
|
||||
fconfig->mouse = config->mouse;
|
||||
if (config->mouse.type == kObjectTypeLuaRef) {
|
||||
fconfig->mouse = kWinMouseCallback;
|
||||
fconfig->mouse_cb = config->mouse.data.luaref;
|
||||
config->mouse.data.luaref = LUA_NOREF;
|
||||
} else if (config->mouse.type == kObjectTypeBoolean) {
|
||||
fconfig->mouse = config->mouse.data.boolean ? kWinMouseDefault : kWinMouseIgnore;
|
||||
fconfig->mouse_cb = LUA_NOREF;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "invalid type for 'mouse'");
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, zindex)) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <lauxlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@ -904,6 +905,12 @@ typedef enum {
|
||||
kFloatRelativeMouse = 3,
|
||||
} FloatRelative;
|
||||
|
||||
typedef enum {
|
||||
kWinMouseIgnore = 0,
|
||||
kWinMouseDefault = 1,
|
||||
kWinMouseCallback = 2,
|
||||
} WinMouseEvent;
|
||||
|
||||
/// Keep in sync with win_split_str[] in nvim_win_get_config() (api/win_config.c)
|
||||
typedef enum {
|
||||
kWinSplitLeft = 0,
|
||||
@ -938,7 +945,8 @@ typedef struct {
|
||||
FloatRelative relative;
|
||||
bool external;
|
||||
bool focusable;
|
||||
bool mouse;
|
||||
WinMouseEvent mouse;
|
||||
LuaRef mouse_cb;
|
||||
WinSplit split;
|
||||
int zindex;
|
||||
WinStyle style;
|
||||
@ -965,7 +973,8 @@ typedef struct {
|
||||
.row = 0, .col = 0, .anchor = 0, \
|
||||
.relative = 0, .external = false, \
|
||||
.focusable = true, \
|
||||
.mouse = true, \
|
||||
.mouse = kWinMouseDefault, \
|
||||
.mouse_cb = LUA_NOREF, \
|
||||
.split = 0, \
|
||||
.zindex = kZIndexFloatDefault, \
|
||||
.style = kWinStyleUnused, \
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
@ -13,6 +15,7 @@
|
||||
#include "nvim/edit.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/eval/typval.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/fold.h"
|
||||
#include "nvim/getchar.h"
|
||||
@ -20,6 +23,7 @@
|
||||
#include "nvim/grid.h"
|
||||
#include "nvim/grid_defs.h"
|
||||
#include "nvim/keycodes.h"
|
||||
#include "nvim/lua/executor.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/mark_defs.h"
|
||||
#include "nvim/mbyte.h"
|
||||
@ -222,6 +226,45 @@ static void call_click_def_func(StlClickDefinition *click_defs, int col, int whi
|
||||
got_click = false;
|
||||
}
|
||||
|
||||
/// When mouse events happen in a window with a mouse callback, invoke it.
|
||||
///
|
||||
/// @param button !is_scroll: return value of get_mouse_button()
|
||||
/// is_scroll: a MSCR_* enum
|
||||
///
|
||||
/// @return whether to proceeded with mouse handling.
|
||||
static bool handle_mouse_cb(bool is_click, bool is_drag, bool is_scroll, int button)
|
||||
{
|
||||
static handle_T last_click_win = 0;
|
||||
int grid = mouse_grid;
|
||||
int row = mouse_row;
|
||||
int col = mouse_col;
|
||||
|
||||
win_T *wp = NULL;
|
||||
if (!is_click && !is_scroll && button != MOUSE_RELEASE) { // drag or release
|
||||
if (last_click_win > 0) {
|
||||
wp = win_id2wp(last_click_win);
|
||||
}
|
||||
} else { // click, scroll or move
|
||||
wp = mouse_find_win(&grid, &row, &col);
|
||||
if (is_click) {
|
||||
last_click_win = wp != NULL ? wp->handle : 0;
|
||||
}
|
||||
}
|
||||
if (wp == NULL || wp->w_config.mouse != kWinMouseCallback) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Error err = ERROR_INIT;
|
||||
Object res = nlua_call_ref(wp->w_config.mouse_cb, NULL, (Array)ARRAY_DICT_INIT,
|
||||
kRetNilBool, NULL, &err);
|
||||
bool retval = LUARET_TRUTHY(res);
|
||||
if (ERROR_SET(&err)) {
|
||||
semsg_multiline("E5108: %s", err.msg);
|
||||
api_clear_error(&err);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Translate window coordinates to buffer position without any side effects.
|
||||
/// Returns IN_BUFFER and sets "mpos->col" to the column when in buffer text.
|
||||
/// The column is one for the first column.
|
||||
@ -371,6 +414,10 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handle_mouse_cb(is_click, is_drag, false, which_button)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c == K_MOUSEMOVE) {
|
||||
// Mouse moved without a button pressed.
|
||||
return false;
|
||||
@ -1063,6 +1110,10 @@ void do_mousescroll(cmdarg_T *cap)
|
||||
/// of the MSCR_ values.
|
||||
void ins_mousescroll(int dir)
|
||||
{
|
||||
if (!handle_mouse_cb(false, false, true, dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cmdarg_T cap;
|
||||
oparg_T oa;
|
||||
CLEAR_FIELD(cap);
|
||||
@ -1572,6 +1623,10 @@ static bool do_mousescroll_horiz(colnr_T leftcol)
|
||||
/// "cap->arg", which is one of the MSCR_ values.
|
||||
void nv_mousescroll(cmdarg_T *cap)
|
||||
{
|
||||
if (!handle_mouse_cb(false, false, true, cap->arg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
win_T *const old_curwin = curwin;
|
||||
|
||||
if (mouse_row >= 0 && mouse_col >= 0) {
|
||||
@ -1740,7 +1795,7 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
|
||||
} else if (*gridp > 1) {
|
||||
win_T *wp = get_win_by_grid_handle(*gridp);
|
||||
if (wp && wp->w_grid_alloc.chars
|
||||
&& !(wp->w_floating && !wp->w_config.mouse)) {
|
||||
&& !(wp->w_floating && wp->w_config.mouse == kWinMouseIgnore)) {
|
||||
*rowp = MIN(*rowp - wp->w_grid.row_offset, wp->w_grid.rows - 1);
|
||||
*colp = MIN(*colp - wp->w_grid.col_offset, wp->w_grid.cols - 1);
|
||||
return wp;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "nvim/grid_defs.h"
|
||||
#include "nvim/hashtab.h"
|
||||
#include "nvim/keycodes.h"
|
||||
#include "nvim/lua/executor.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/main.h"
|
||||
#include "nvim/map_defs.h"
|
||||
@ -802,6 +803,9 @@ int win_fdccol_count(win_T *wp)
|
||||
void merge_win_config(WinConfig *dst, const WinConfig src)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (dst->mouse_cb != src.mouse_cb) {
|
||||
api_free_luaref(dst->mouse_cb);
|
||||
}
|
||||
if (dst->title_chunks.items != src.title_chunks.items) {
|
||||
clear_virttext(&dst->title_chunks);
|
||||
}
|
||||
@ -857,7 +861,7 @@ void ui_ext_win_position(win_T *wp, bool validate)
|
||||
String anchor = cstr_as_string(float_anchor_str[c.anchor]);
|
||||
if (!c.hide) {
|
||||
ui_call_win_float_pos(wp->w_grid_alloc.handle, wp->handle, anchor,
|
||||
grid->handle, row, col, c.mouse,
|
||||
grid->handle, row, col, c.mouse != kWinMouseIgnore,
|
||||
wp->w_grid_alloc.zindex);
|
||||
} else {
|
||||
ui_call_win_hide(wp->w_grid_alloc.handle);
|
||||
@ -889,7 +893,7 @@ void ui_ext_win_position(win_T *wp, bool validate)
|
||||
ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col,
|
||||
wp->w_height_outer, wp->w_width_outer, valid, false);
|
||||
ui_check_cursor_grid(wp->w_grid_alloc.handle);
|
||||
wp->w_grid_alloc.mouse_enabled = wp->w_config.mouse;
|
||||
wp->w_grid_alloc.mouse_enabled = wp->w_config.mouse != kWinMouseIgnore;
|
||||
if (!valid) {
|
||||
wp->w_grid_alloc.valid = false;
|
||||
redraw_later(wp, UPD_NOT_VALID);
|
||||
@ -4044,7 +4048,7 @@ void win_alloc_aucmd_win(int idx)
|
||||
fconfig.width = Columns;
|
||||
fconfig.height = 5;
|
||||
fconfig.focusable = false;
|
||||
fconfig.mouse = false;
|
||||
fconfig.mouse = kWinMouseIgnore;
|
||||
aucmd_win[idx].auc_win = win_new_float(NULL, true, fconfig, &err);
|
||||
aucmd_win[idx].auc_win->w_buffer->b_nwindows--;
|
||||
RESET_BINDING(aucmd_win[idx].auc_win);
|
||||
@ -5263,9 +5267,8 @@ void win_free(win_T *wp, tabpage_T *tp)
|
||||
}
|
||||
}
|
||||
|
||||
// free the border text
|
||||
clear_virttext(&wp->w_config.title_chunks);
|
||||
clear_virttext(&wp->w_config.footer_chunks);
|
||||
// free allocated resources in w_config
|
||||
merge_win_config(&wp->w_config, WIN_CONFIG_INIT);
|
||||
|
||||
clear_matches(wp);
|
||||
|
||||
|
@ -389,7 +389,7 @@ win_T *win_float_create(bool enter, bool new_buf)
|
||||
config.row = curwin->w_wrow;
|
||||
config.relative = kFloatRelativeEditor;
|
||||
config.focusable = false;
|
||||
config.mouse = false;
|
||||
config.mouse = kWinMouseIgnore;
|
||||
config.anchor = 0; // NW
|
||||
config.noautocmd = true;
|
||||
config.hide = true;
|
||||
|
Loading…
Reference in New Issue
Block a user