aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/mouse.c102
-rw-r--r--test/functional/ui/statusline_spec.lua25
2 files changed, 91 insertions, 36 deletions
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 2ea108d3df..a4a521fa80 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -128,8 +128,10 @@ bool is_mouse_key(int c)
/// @param which_button MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
int jump_to_mouse(int flags, bool *inclusive, int which_button)
{
- static int on_status_line = 0; // #lines below bottom of window
- static int on_sep_line = 0; // on separator right of window
+ static int status_line_offset = 0; // #lines offset from status line
+ static int sep_line_offset = 0; // #cols offset from sep line
+ static bool on_status_line = false;
+ static bool on_sep_line = false;
static bool on_winbar = false;
static int prev_row = -1;
static int prev_col = -1;
@@ -144,6 +146,7 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
int col = mouse_col;
int grid = mouse_grid;
int fdc = 0;
+ bool keep_focus = flags & MOUSE_FOCUS;
mouse_past_bottom = false;
mouse_past_eol = false;
@@ -164,10 +167,10 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
retnomove:
// before moving the cursor for a left click which is NOT in a status
// line, stop Visual mode
- if (on_status_line) {
+ if (status_line_offset) {
return IN_STATUS_LINE;
}
- if (on_sep_line) {
+ if (sep_line_offset) {
return IN_SEP_LINE;
}
if (on_winbar) {
@@ -189,49 +192,78 @@ retnomove:
old_curwin = curwin;
old_cursor = curwin->w_cursor;
- if (!(flags & MOUSE_FOCUS)) {
- if (row < 0 || col < 0) { // check if it makes sense
- return IN_UNKNOWN;
+ if (row < 0 || col < 0) { // check if it makes sense
+ return IN_UNKNOWN;
+ }
+
+ // find the window where the row is in
+ wp = mouse_find_win(&grid, &row, &col);
+ if (wp == NULL) {
+ return IN_UNKNOWN;
+ }
+
+ on_status_line = (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height)
+ ? row + wp->w_winbar_height - wp->w_height + 1 == 1
+ : false;
+
+ on_winbar = (row == -1)
+ ? wp->w_winbar_height != 0
+ : false;
+
+ on_sep_line = grid == DEFAULT_GRID_HANDLE && col >= wp->w_width
+ ? col - wp->w_width + 1 == 1
+ : false;
+
+ // The rightmost character of the status line might be a vertical
+ // separator character if there is no connecting window to the right.
+ if (on_status_line && on_sep_line) {
+ if (stl_connected(wp)) {
+ on_sep_line = false;
+ } else {
+ on_status_line = false;
}
+ }
- // find the window where the row is in
- wp = mouse_find_win(&grid, &row, &col);
- if (wp == NULL) {
- return IN_UNKNOWN;
+ if (keep_focus) {
+ // If we can't change focus, set the value of row, col and grid back to absolute values
+ // since the values relative to the window are only used when keep_focus is false
+ row = mouse_row;
+ col = mouse_col;
+ grid = mouse_grid;
+ }
+
+ if (!keep_focus) {
+ if (on_winbar) {
+ return IN_OTHER_WIN | MOUSE_WINBAR;
}
+
fdc = win_fdccol_count(wp);
dragwin = NULL;
- if (row == -1) {
- on_winbar = wp->w_winbar_height != 0;
- return IN_OTHER_WIN | (on_winbar ? MOUSE_WINBAR : 0);
- }
- on_winbar = false;
-
// winpos and height may change in win_enter()!
if (grid == DEFAULT_GRID_HANDLE && row + wp->w_winbar_height >= wp->w_height) {
// In (or below) status line
- on_status_line = row + wp->w_winbar_height - wp->w_height + 1;
+ status_line_offset = row + wp->w_winbar_height - wp->w_height + 1;
dragwin = wp;
} else {
- on_status_line = 0;
+ status_line_offset = 0;
}
if (grid == DEFAULT_GRID_HANDLE && col >= wp->w_width) {
// In separator line
- on_sep_line = col - wp->w_width + 1;
+ sep_line_offset = col - wp->w_width + 1;
dragwin = wp;
} else {
- on_sep_line = 0;
+ sep_line_offset = 0;
}
// The rightmost character of the status line might be a vertical
// separator character if there is no connecting window to the right.
- if (on_status_line && on_sep_line) {
+ if (status_line_offset && sep_line_offset) {
if (stl_connected(wp)) {
- on_sep_line = 0;
+ sep_line_offset = 0;
} else {
- on_status_line = 0;
+ status_line_offset = 0;
}
}
@@ -239,8 +271,8 @@ retnomove:
// click, stop Visual mode.
if (VIsual_active
&& (wp->w_buffer != curwin->w_buffer
- || (!on_status_line
- && !on_sep_line
+ || (!status_line_offset
+ && !sep_line_offset
&& (wp->w_p_rl
? col < wp->w_width_inner - fdc
: col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1))
@@ -251,7 +283,7 @@ retnomove:
if (cmdwin_type != 0 && wp != curwin) {
// A click outside the command-line window: Use modeless
// selection if possible. Allow dragging the status lines.
- on_sep_line = 0;
+ sep_line_offset = 0;
row = 0;
col += wp->w_wincol;
wp = curwin;
@@ -266,7 +298,7 @@ retnomove:
if (curwin != old_curwin) {
set_mouse_topline(curwin);
}
- if (on_status_line) { // In (or below) status line
+ if (status_line_offset) { // In (or below) status line
// Don't use start_arrow() if we're in the same window
if (curwin == old_curwin) {
return IN_STATUS_LINE;
@@ -274,7 +306,7 @@ retnomove:
return IN_STATUS_LINE | CURSOR_MOVED;
}
}
- if (on_sep_line) { // In (or below) status line
+ if (sep_line_offset) { // In (or below) status line
// Don't use start_arrow() if we're in the same window
if (curwin == old_curwin) {
return IN_SEP_LINE;
@@ -284,25 +316,27 @@ retnomove:
}
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (on_status_line) {
+ } else if (status_line_offset) {
if (which_button == MOUSE_LEFT && dragwin != NULL) {
// Drag the status line
count = row - dragwin->w_winrow - dragwin->w_height + 1
- - on_status_line;
+ - status_line_offset;
win_drag_status_line(dragwin, count);
did_drag |= count;
}
return IN_STATUS_LINE; // Cursor didn't move
- } else if (on_sep_line && which_button == MOUSE_LEFT) {
+ } else if (sep_line_offset && which_button == MOUSE_LEFT) {
if (dragwin != NULL) {
// Drag the separator column
count = col - dragwin->w_wincol - dragwin->w_width + 1
- - on_sep_line;
+ - sep_line_offset;
win_drag_vsep_line(dragwin, count);
did_drag |= count;
}
return IN_SEP_LINE; // Cursor didn't move
- } else if (on_winbar) {
+ } else if (on_status_line && which_button == MOUSE_RIGHT) {
+ return IN_STATUS_LINE;
+ } else if (on_winbar && which_button == MOUSE_RIGHT) {
// After a click on the window bar don't start Visual mode.
return IN_OTHER_WIN | MOUSE_WINBAR;
} else {
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 2733b9dd4a..82e669856f 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -20,7 +20,12 @@ describe('statusline clicks', function()
command('set laststatus=2')
exec([=[
function! MyClickFunc(minwid, clicks, button, mods)
- let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
+ let mods = trim(a:mods)
+ if mods ==# ''
+ let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
+ else
+ let g:testvar = printf("%d %d %s %s", a:minwid, a:clicks, a:button, mods)
+ endif
endfunction
]=])
end)
@@ -37,7 +42,7 @@ describe('statusline clicks', function()
meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
meths.input_mouse('left', 'press', '', 0, 0, 17)
eq('0 1 l', eval("g:testvar"))
- meths.input_mouse('right', 'press', '', 0, 6, 17)
+ meths.input_mouse('right', 'press', '', 0, 0, 17)
eq('0 1 r', eval("g:testvar"))
end)
@@ -84,6 +89,22 @@ describe('statusline clicks', function()
meths.input_mouse('left', 'press', '', 0, 6, 0)
eq(2, #meths.list_tabpages())
end)
+
+ it("right click works when statusline isn't focused #18994", function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 2 r', eval("g:testvar"))
+ end)
+
+ it("click works with modifiers #18994", function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('right', 'press', 's', 0, 6, 17)
+ eq('0 1 r s', eval("g:testvar"))
+ meths.input_mouse('left', 'press', 's', 0, 6, 17)
+ eq('0 1 l s', eval("g:testvar"))
+ end)
end)
describe('global statusline', function()