mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #13592 from bfredl/setmouse
ui: make 'mouse' handling in external UI more consistent
This commit is contained in:
commit
90f619f140
@ -213,11 +213,9 @@ the editor.
|
|||||||
|
|
||||||
["mouse_on"]
|
["mouse_on"]
|
||||||
["mouse_off"]
|
["mouse_off"]
|
||||||
|'mouse'| was enabled/disabled in the current editor mode. Useful for
|
'mouse' was enabled/disabled in the current editor mode. Useful for
|
||||||
a terminal UI, or other situations where Nvim mouse would conflict
|
a terminal UI, or embedding into an application where Nvim mouse would
|
||||||
with other usages of the mouse. UIs may ignore this and always send
|
conflict with other usages of the mouse. Other UI:s may ignore this event.
|
||||||
mouse input, because 'mouse' decides the behavior of |nvim_input()|
|
|
||||||
implicitly.
|
|
||||||
|
|
||||||
["busy_start"]
|
["busy_start"]
|
||||||
["busy_stop"]
|
["busy_stop"]
|
||||||
|
@ -8329,9 +8329,6 @@ static void ins_mouse(int c)
|
|||||||
pos_T tpos;
|
pos_T tpos;
|
||||||
win_T *old_curwin = curwin;
|
win_T *old_curwin = curwin;
|
||||||
|
|
||||||
if (!mouse_has(MOUSE_INSERT))
|
|
||||||
return;
|
|
||||||
|
|
||||||
undisplay_dollar();
|
undisplay_dollar();
|
||||||
tpos = curwin->w_cursor;
|
tpos = curwin->w_cursor;
|
||||||
if (do_mouse(NULL, c, BACKWARD, 1, 0)) {
|
if (do_mouse(NULL, c, BACKWARD, 1, 0)) {
|
||||||
|
@ -1884,9 +1884,6 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
return command_line_not_changed(s); // Ignore mouse
|
return command_line_not_changed(s); // Ignore mouse
|
||||||
|
|
||||||
case K_MIDDLEMOUSE:
|
case K_MIDDLEMOUSE:
|
||||||
if (!mouse_has(MOUSE_COMMAND)) {
|
|
||||||
return command_line_not_changed(s); // Ignore mouse
|
|
||||||
}
|
|
||||||
cmdline_paste(eval_has_provider("clipboard") ? '*' : 0, true, true);
|
cmdline_paste(eval_has_provider("clipboard") ? '*' : 0, true, true);
|
||||||
redrawcmd();
|
redrawcmd();
|
||||||
return command_line_changed(s);
|
return command_line_changed(s);
|
||||||
@ -1910,10 +1907,6 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
s->ignore_drag_release = false;
|
s->ignore_drag_release = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mouse_has(MOUSE_COMMAND)) {
|
|
||||||
return command_line_not_changed(s); // Ignore mouse
|
|
||||||
}
|
|
||||||
|
|
||||||
ccline.cmdspos = cmd_startcol();
|
ccline.cmdspos = cmd_startcol();
|
||||||
for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
|
for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
|
||||||
ccline.cmdpos++) {
|
ccline.cmdpos++) {
|
||||||
|
@ -1157,15 +1157,7 @@ void wait_return(int redraw)
|
|||||||
|| c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
|
|| c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
|
||||||
|| c == K_RIGHTDRAG || c == K_RIGHTRELEASE
|
|| c == K_RIGHTDRAG || c == K_RIGHTRELEASE
|
||||||
|| c == K_MOUSELEFT || c == K_MOUSERIGHT
|
|| c == K_MOUSELEFT || c == K_MOUSERIGHT
|
||||||
|| c == K_MOUSEDOWN || c == K_MOUSEUP
|
|| c == K_MOUSEDOWN || c == K_MOUSEUP);
|
||||||
|| (!mouse_has(MOUSE_RETURN)
|
|
||||||
&& mouse_row < msg_row
|
|
||||||
&& (c == K_LEFTMOUSE
|
|
||||||
|| c == K_MIDDLEMOUSE
|
|
||||||
|| c == K_RIGHTMOUSE
|
|
||||||
|| c == K_X1MOUSE
|
|
||||||
|| c == K_X2MOUSE))
|
|
||||||
);
|
|
||||||
os_breakcheck();
|
os_breakcheck();
|
||||||
/*
|
/*
|
||||||
* Avoid that the mouse-up event causes visual mode to start.
|
* Avoid that the mouse-up event causes visual mode to start.
|
||||||
|
@ -526,53 +526,9 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
|
|||||||
void setmouse(void)
|
void setmouse(void)
|
||||||
{
|
{
|
||||||
ui_cursor_shape();
|
ui_cursor_shape();
|
||||||
|
ui_check_mouse();
|
||||||
// Be quick when mouse is off.
|
|
||||||
if (*p_mouse == NUL) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int checkfor = MOUSE_NORMAL; // assume normal mode
|
|
||||||
if (VIsual_active) {
|
|
||||||
checkfor = MOUSE_VISUAL;
|
|
||||||
} else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE) {
|
|
||||||
checkfor = MOUSE_RETURN;
|
|
||||||
} else if (State & INSERT) {
|
|
||||||
checkfor = MOUSE_INSERT;
|
|
||||||
} else if (State & CMDLINE) {
|
|
||||||
checkfor = MOUSE_COMMAND;
|
|
||||||
} else if (State == CONFIRM || State == EXTERNCMD) {
|
|
||||||
checkfor = ' '; // don't use mouse for ":confirm" or ":!cmd"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouse_has(checkfor)) {
|
|
||||||
ui_call_mouse_on();
|
|
||||||
} else {
|
|
||||||
ui_call_mouse_off();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return true if
|
|
||||||
* - "c" is in 'mouse', or
|
|
||||||
* - 'a' is in 'mouse' and "c" is in MOUSE_A, or
|
|
||||||
* - the current buffer is a help file and 'h' is in 'mouse' and we are in a
|
|
||||||
* normal editing mode (not at hit-return message).
|
|
||||||
*/
|
|
||||||
int mouse_has(int c)
|
|
||||||
{
|
|
||||||
for (char_u *p = p_mouse; *p; ++p)
|
|
||||||
switch (*p) {
|
|
||||||
case 'a': if (vim_strchr((char_u *)MOUSE_A, c) != NULL)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
case MOUSE_HELP: if (c != MOUSE_RETURN && curbuf->b_help)
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
default: if (c == *p) return true; break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set orig_topline. Used when jumping to another window, so that a double
|
// Set orig_topline. Used when jumping to another window, so that a double
|
||||||
// click still works.
|
// click still works.
|
||||||
|
@ -2375,10 +2375,10 @@ do_mouse (
|
|||||||
* Also paste at the cursor if the current mode isn't in 'mouse' (only
|
* Also paste at the cursor if the current mode isn't in 'mouse' (only
|
||||||
* happens for the GUI).
|
* happens for the GUI).
|
||||||
*/
|
*/
|
||||||
if ((State & INSERT) || !mouse_has(MOUSE_NORMAL)) {
|
if ((State & INSERT)) {
|
||||||
if (regname == '.')
|
if (regname == '.') {
|
||||||
insert_reg(regname, true);
|
insert_reg(regname, true);
|
||||||
else {
|
} else {
|
||||||
if (regname == 0 && eval_has_provider("clipboard")) {
|
if (regname == 0 && eval_has_provider("clipboard")) {
|
||||||
regname = '*';
|
regname = '*';
|
||||||
}
|
}
|
||||||
@ -2558,8 +2558,9 @@ do_mouse (
|
|||||||
* on a status line */
|
* on a status line */
|
||||||
if (VIsual_active)
|
if (VIsual_active)
|
||||||
jump_flags |= MOUSE_MAY_STOP_VIS;
|
jump_flags |= MOUSE_MAY_STOP_VIS;
|
||||||
} else if (mouse_has(MOUSE_VISUAL))
|
} else {
|
||||||
jump_flags |= MOUSE_MAY_VIS;
|
jump_flags |= MOUSE_MAY_VIS;
|
||||||
|
}
|
||||||
} else if (which_button == MOUSE_RIGHT) {
|
} else if (which_button == MOUSE_RIGHT) {
|
||||||
if (is_click && VIsual_active) {
|
if (is_click && VIsual_active) {
|
||||||
/*
|
/*
|
||||||
@ -2575,7 +2576,6 @@ do_mouse (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
jump_flags |= MOUSE_FOCUS;
|
jump_flags |= MOUSE_FOCUS;
|
||||||
if (mouse_has(MOUSE_VISUAL))
|
|
||||||
jump_flags |= MOUSE_MAY_VIS;
|
jump_flags |= MOUSE_MAY_VIS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2790,8 +2790,7 @@ do_mouse (
|
|||||||
/* Handle double clicks, unless on status line */
|
/* Handle double clicks, unless on status line */
|
||||||
else if (in_status_line) {
|
else if (in_status_line) {
|
||||||
} else if (in_sep_line) {
|
} else if (in_sep_line) {
|
||||||
} else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))
|
} else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))) {
|
||||||
&& mouse_has(MOUSE_VISUAL)) {
|
|
||||||
if (is_click || !VIsual_active) {
|
if (is_click || !VIsual_active) {
|
||||||
if (VIsual_active) {
|
if (VIsual_active) {
|
||||||
orig_cursor = VIsual;
|
orig_cursor = VIsual;
|
||||||
|
@ -3210,12 +3210,8 @@ ambw_end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (varp == &p_mouse) {
|
if (varp == &p_mouse) {
|
||||||
if (*p_mouse == NUL) {
|
|
||||||
ui_call_mouse_off();
|
|
||||||
} else {
|
|
||||||
setmouse(); // in case 'mouse' changed
|
setmouse(); // in case 'mouse' changed
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (curwin->w_curswant != MAXCOL
|
if (curwin->w_curswant != MAXCOL
|
||||||
&& (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
|
&& (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
|
||||||
@ -4984,13 +4980,9 @@ void ui_refresh_options(void)
|
|||||||
ui_call_option_set(name, value);
|
ui_call_option_set(name, value);
|
||||||
}
|
}
|
||||||
if (p_mouse != NULL) {
|
if (p_mouse != NULL) {
|
||||||
if (*p_mouse == NUL) {
|
|
||||||
ui_call_mouse_off();
|
|
||||||
} else {
|
|
||||||
setmouse();
|
setmouse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// showoneopt: show the value of one option
|
/// showoneopt: show the value of one option
|
||||||
/// must not be called with a hidden option!
|
/// must not be called with a hidden option!
|
||||||
|
@ -61,6 +61,9 @@ static bool pending_mode_info_update = false;
|
|||||||
static bool pending_mode_update = false;
|
static bool pending_mode_update = false;
|
||||||
static handle_T cursor_grid_handle = DEFAULT_GRID_HANDLE;
|
static handle_T cursor_grid_handle = DEFAULT_GRID_HANDLE;
|
||||||
|
|
||||||
|
static bool has_mouse = false;
|
||||||
|
static int pending_has_mouse = -1;
|
||||||
|
|
||||||
#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL
|
#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL
|
||||||
# define UI_LOG(funname)
|
# define UI_LOG(funname)
|
||||||
#else
|
#else
|
||||||
@ -220,6 +223,7 @@ void ui_refresh(void)
|
|||||||
ui_mode_info_set();
|
ui_mode_info_set();
|
||||||
pending_mode_update = true;
|
pending_mode_update = true;
|
||||||
ui_cursor_shape();
|
ui_cursor_shape();
|
||||||
|
pending_has_mouse = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ui_pum_get_height(void)
|
int ui_pum_get_height(void)
|
||||||
@ -459,10 +463,69 @@ void ui_flush(void)
|
|||||||
ui_call_mode_change(cstr_as_string(full_name), ui_mode_idx);
|
ui_call_mode_change(cstr_as_string(full_name), ui_mode_idx);
|
||||||
pending_mode_update = false;
|
pending_mode_update = false;
|
||||||
}
|
}
|
||||||
|
if (pending_has_mouse != has_mouse) {
|
||||||
|
(has_mouse ? ui_call_mouse_on : ui_call_mouse_off)();
|
||||||
|
pending_has_mouse = has_mouse;
|
||||||
|
}
|
||||||
ui_call_flush();
|
ui_call_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Check if 'mouse' is active for the current mode
|
||||||
|
///
|
||||||
|
/// TODO(bfredl): precompute the State -> active mapping when 'mouse' changes,
|
||||||
|
/// then this can be checked directly in ui_flush()
|
||||||
|
void ui_check_mouse(void)
|
||||||
|
{
|
||||||
|
has_mouse = false;
|
||||||
|
// Be quick when mouse is off.
|
||||||
|
if (*p_mouse == NUL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int checkfor = MOUSE_NORMAL; // assume normal mode
|
||||||
|
if (VIsual_active) {
|
||||||
|
checkfor = MOUSE_VISUAL;
|
||||||
|
} else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE) {
|
||||||
|
checkfor = MOUSE_RETURN;
|
||||||
|
} else if (State & INSERT) {
|
||||||
|
checkfor = MOUSE_INSERT;
|
||||||
|
} else if (State & CMDLINE) {
|
||||||
|
checkfor = MOUSE_COMMAND;
|
||||||
|
} else if (State == CONFIRM || State == EXTERNCMD) {
|
||||||
|
checkfor = ' '; // don't use mouse for ":confirm" or ":!cmd"
|
||||||
|
}
|
||||||
|
|
||||||
|
// mouse should be active if at least one of the following is true:
|
||||||
|
// - "c" is in 'mouse', or
|
||||||
|
// - 'a' is in 'mouse' and "c" is in MOUSE_A, or
|
||||||
|
// - the current buffer is a help file and 'h' is in 'mouse' and we are in a
|
||||||
|
// normal editing mode (not at hit-return message).
|
||||||
|
for (char_u *p = p_mouse; *p; p++) {
|
||||||
|
switch (*p) {
|
||||||
|
case 'a':
|
||||||
|
if (vim_strchr((char_u *)MOUSE_A, checkfor) != NULL) {
|
||||||
|
has_mouse = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MOUSE_HELP:
|
||||||
|
if (checkfor != MOUSE_RETURN && curbuf->b_help) {
|
||||||
|
has_mouse = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (checkfor == *p) {
|
||||||
|
has_mouse = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if current mode has changed.
|
/// Check if current mode has changed.
|
||||||
|
///
|
||||||
/// May update the shape of the cursor.
|
/// May update the shape of the cursor.
|
||||||
void ui_cursor_shape(void)
|
void ui_cursor_shape(void)
|
||||||
{
|
{
|
||||||
|
@ -45,13 +45,33 @@ describe('ui/mouse/input', function()
|
|||||||
|
|
||||||
it('single left click moves cursor', function()
|
it('single left click moves cursor', function()
|
||||||
feed('<LeftMouse><2,1>')
|
feed('<LeftMouse><2,1>')
|
||||||
screen:expect([[
|
screen:expect{grid=[[
|
||||||
testing |
|
testing |
|
||||||
mo^use |
|
mo^use |
|
||||||
support and selection |
|
support and selection |
|
||||||
{0:~ }|
|
{0:~ }|
|
||||||
|
|
|
|
||||||
|
]], mouse_enabled=true}
|
||||||
|
feed('<LeftMouse><0,0>')
|
||||||
|
screen:expect([[
|
||||||
|
^testing |
|
||||||
|
mouse |
|
||||||
|
support and selection |
|
||||||
|
{0:~ }|
|
||||||
|
|
|
||||||
]])
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("in external ui works with unset 'mouse'", function()
|
||||||
|
meths.set_option('mouse', '')
|
||||||
|
feed('<LeftMouse><2,1>')
|
||||||
|
screen:expect{grid=[[
|
||||||
|
testing |
|
||||||
|
mo^use |
|
||||||
|
support and selection |
|
||||||
|
{0:~ }|
|
||||||
|
|
|
||||||
|
]], mouse_enabled=false}
|
||||||
feed('<LeftMouse><0,0>')
|
feed('<LeftMouse><0,0>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
^testing |
|
^testing |
|
||||||
|
@ -170,7 +170,7 @@ function Screen.new(width, height)
|
|||||||
ruler = {},
|
ruler = {},
|
||||||
hl_groups = {},
|
hl_groups = {},
|
||||||
_default_attr_ids = nil,
|
_default_attr_ids = nil,
|
||||||
_mouse_enabled = true,
|
mouse_enabled = true,
|
||||||
_attrs = {},
|
_attrs = {},
|
||||||
_hl_info = {[0]={}},
|
_hl_info = {[0]={}},
|
||||||
_attr_table = {[0]={{},{}}},
|
_attr_table = {[0]={{},{}}},
|
||||||
@ -318,7 +318,7 @@ function Screen:expect(expected, attr_ids, ...)
|
|||||||
assert(next({...}) == nil, "invalid args to expect()")
|
assert(next({...}) == nil, "invalid args to expect()")
|
||||||
if type(expected) == "table" then
|
if type(expected) == "table" then
|
||||||
assert(not (attr_ids ~= nil))
|
assert(not (attr_ids ~= nil))
|
||||||
local is_key = {grid=true, attr_ids=true, condition=true,
|
local is_key = {grid=true, attr_ids=true, condition=true, mouse_enabled=true,
|
||||||
any=true, mode=true, unchanged=true, intermediate=true,
|
any=true, mode=true, unchanged=true, intermediate=true,
|
||||||
reset=true, timeout=true, request_cb=true, hl_groups=true}
|
reset=true, timeout=true, request_cb=true, hl_groups=true}
|
||||||
for _, v in ipairs(ext_keys) do
|
for _, v in ipairs(ext_keys) do
|
||||||
@ -422,12 +422,15 @@ screen:redraw_debug() to show all intermediate screen states. ]])
|
|||||||
if expected.mode ~= nil then
|
if expected.mode ~= nil then
|
||||||
extstate.mode = self.mode
|
extstate.mode = self.mode
|
||||||
end
|
end
|
||||||
|
if expected.mouse_enabled ~= nil then
|
||||||
|
extstate.mouse_enabled = self.mouse_enabled
|
||||||
|
end
|
||||||
if expected.win_viewport == nil then
|
if expected.win_viewport == nil then
|
||||||
extstate.win_viewport = nil
|
extstate.win_viewport = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Convert assertion errors into invalid screen state descriptions.
|
-- Convert assertion errors into invalid screen state descriptions.
|
||||||
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
|
for _, k in ipairs(concat_tables(ext_keys, {'mode', 'mouse_enabled'})) do
|
||||||
-- Empty states are considered the default and need not be mentioned.
|
-- Empty states are considered the default and need not be mentioned.
|
||||||
if (not (expected[k] == nil and isempty(extstate[k]))) then
|
if (not (expected[k] == nil and isempty(extstate[k]))) then
|
||||||
local status, res = pcall(eq, expected[k], extstate[k], k)
|
local status, res = pcall(eq, expected[k], extstate[k], k)
|
||||||
@ -799,11 +802,11 @@ function Screen:_handle_busy_stop()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_handle_mouse_on()
|
function Screen:_handle_mouse_on()
|
||||||
self._mouse_enabled = true
|
self.mouse_enabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_handle_mouse_off()
|
function Screen:_handle_mouse_off()
|
||||||
self._mouse_enabled = false
|
self.mouse_enabled = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_handle_mode_change(mode, idx)
|
function Screen:_handle_mode_change(mode, idx)
|
||||||
|
Loading…
Reference in New Issue
Block a user