aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFamiu Haque <famiuhaque@protonmail.com>2022-05-23 19:11:24 +0600
committerGitHub <noreply@github.com>2022-05-23 06:11:24 -0700
commit4c6626f03dc645a426c1e63ca372b96f1073581b (patch)
treee0ab7136f9b7c32a827ad59bbe1d0cc3f6b7dd65
parent9e1ee9fb1d747facb6fa97a32dc5e22c7dfcb346 (diff)
downloadrneovim-4c6626f03dc645a426c1e63ca372b96f1073581b.tar.gz
rneovim-4c6626f03dc645a426c1e63ca372b96f1073581b.tar.bz2
rneovim-4c6626f03dc645a426c1e63ca372b96f1073581b.zip
feat: click support for 'statusline', 'winbar' #18650
The mouseclick item "%@" is now supported by 'statusline' and 'winbar'. Previously it was only supported by 'tabline'.
-rw-r--r--runtime/doc/options.txt4
-rw-r--r--src/nvim/buffer_defs.h12
-rw-r--r--src/nvim/grid_defs.h18
-rw-r--r--src/nvim/mouse.c4
-rw-r--r--src/nvim/normal.c153
-rw-r--r--src/nvim/screen.c82
-rw-r--r--src/nvim/screen.h18
-rw-r--r--src/nvim/window.c47
-rw-r--r--test/functional/ui/global_statusline_spec.lua260
-rw-r--r--test/functional/ui/statusline_spec.lua317
10 files changed, 529 insertions, 386 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 9015f0a97e..77aa294027 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6009,7 +6009,7 @@ A jump table for the options with a short description can be found at |Q_op|.
the label, e.g.: %3Xclose%X. Use %999X for a "close current
tab" label. Clicking this label with left mouse button closes
specified tab page.
- @ N For 'tabline': start of execute function label. Use %X or %T to
+ @ N Start of execute function label. Use %X or %T to
end the label, e.g.: %10@SwitchBuffer@foo.c%X. Clicking this
label runs specified function: in the example when clicking once
using left mouse button on "foo.c" "SwitchBuffer(10, 1, 'l',
@@ -6033,8 +6033,6 @@ A jump table for the options with a short description can be found at |Q_op|.
is a bug that denotes that new mouse button recognition was
added without modifying code that reacts on mouse clicks on
this label.
- Note: to test whether your version of Neovim contains this
- feature use `has('tablineat')`.
< - Where to truncate line if too long. Default is at the start.
No width fields allowed.
= - Separation point between alignment sections. Each section will
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 9efa540210..22eef020a1 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -6,6 +6,8 @@
// for FILE
#include <stdio.h>
+#include "grid_defs.h"
+
typedef struct file_buffer buf_T; // Forward declaration
// Reference to a buffer that stores the value of buf_free_count.
@@ -1492,6 +1494,16 @@ struct window_S {
// Location list reference used in the location list window.
// In a non-location list window, w_llist_ref is NULL.
qf_info_T *w_llist_ref;
+
+ // Status line click definitions
+ StlClickDefinition *w_status_click_defs;
+ // Size of the w_status_click_defs array
+ size_t w_status_click_defs_size;
+
+ // Window bar click definitions
+ StlClickDefinition *w_winbar_click_defs;
+ // Size of the w_winbar_click_defs array
+ size_t w_winbar_click_defs_size;
};
static inline int win_hl_attr(win_T *wp, int hlf)
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index a97a1c2c39..f2427f8aef 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -111,4 +111,22 @@ struct ScreenGrid {
false, 0, 0, NULL, false, true, 0, \
0, 0, 0, 0, 0, false }
+/// Status line click definition
+typedef struct {
+ enum {
+ kStlClickDisabled = 0, ///< Clicks to this area are ignored.
+ kStlClickTabSwitch, ///< Switch to the given tab.
+ kStlClickTabClose, ///< Close given tab.
+ kStlClickFuncRun, ///< Run user function.
+ } type; ///< Type of the click.
+ int tabnr; ///< Tab page number.
+ char *func; ///< Function to run.
+} StlClickDefinition;
+
+/// Used for tabline clicks
+typedef struct {
+ StlClickDefinition def; ///< Click definition.
+ const char *start; ///< Location where region starts.
+} StlClickRecord;
+
#endif // NVIM_GRID_DEFS_H
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 8736c73080..347adc589f 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -241,8 +241,8 @@ retnomove:
}
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (on_status_line && which_button == MOUSE_LEFT) {
- if (dragwin != NULL) {
+ } else if (on_status_line) {
+ if (which_button == MOUSE_LEFT && dragwin != NULL) {
// Drag the status line
count = row - dragwin->w_winrow - dragwin->w_height + 1
- on_status_line;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 0c55c64b5c..7c7a042eac 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -32,6 +32,7 @@
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/grid_defs.h"
#include "nvim/indent.h"
#include "nvim/keycodes.h"
#include "nvim/log.h"
@@ -1432,6 +1433,63 @@ static void move_tab_to_mouse(void)
}
}
+/// Call click definition function for column "col" in the "click_defs" array for button
+/// "which_button".
+static void call_click_def_func(StlClickDefinition *click_defs, int col, int which_button)
+{
+ typval_T argv[] = {
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = (varnumber_T)click_defs[col].tabnr
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_NUMBER,
+ .vval = {
+ .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
+ ? 4
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
+ ? 3
+ : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
+ ? 2
+ : 1)))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (which_button == MOUSE_LEFT
+ ? "l"
+ : (which_button == MOUSE_RIGHT
+ ? "r"
+ : (which_button == MOUSE_MIDDLE
+ ? "m"
+ : "?")))
+ },
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = {
+ .v_string = (char[]) {
+ (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
+ (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
+ (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
+ (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
+ NUL
+ }
+ },
+ }
+ };
+ typval_T rettv;
+ (void)call_vim_function(click_defs[col].func, ARRAY_SIZE(argv), argv, &rettv);
+ tv_clear(&rettv);
+}
+
/// Do the appropriate action for the current mouse click in the current mode.
/// Not used for Command-line mode.
///
@@ -1481,6 +1539,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
int jump_flags = 0; // flags for jump_to_mouse()
pos_T start_visual;
bool moved; // Has cursor moved?
+ bool in_winbar; // mouse in window bar
bool in_status_line; // mouse in status line
static bool in_tab_line = false; // mouse clicked in tab line
bool in_sep_line; // mouse in vertical separator line
@@ -1711,66 +1770,10 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
}
}
break;
- case kStlClickFuncRun: {
- typval_T argv[] = {
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = (varnumber_T)tab_page_click_defs[mouse_col].tabnr
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_NUMBER,
- .vval = {
- .v_number = ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK
- ? 4
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK
- ? 3
- : ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK
- ? 2
- : 1)))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (which_button == MOUSE_LEFT
- ? "l"
- : (which_button == MOUSE_RIGHT
- ? "r"
- : (which_button == MOUSE_MIDDLE
- ? "m"
- : "?")))
- },
- },
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (char[]) {
- (char)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
- (char)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
- (char)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
- (char)(mod_mask & MOD_MASK_META ? 'm' : ' '),
- NUL
- }
- },
- }
- };
- typval_T rettv;
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
- (void)call_func(tab_page_click_defs[mouse_col].func, -1,
- &rettv, ARRAY_SIZE(argv), argv, &funcexe);
- tv_clear(&rettv);
+ case kStlClickFuncRun:
+ call_click_def_func(tab_page_click_defs, mouse_col, which_button);
break;
}
- }
}
return true;
} else if (is_drag && in_tab_line) {
@@ -1840,15 +1843,39 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
oap == NULL ? NULL : &(oap->inclusive),
which_button);
- // A click in the window bar has no side effects.
- if (jump_flags & MOUSE_WINBAR) {
- return false;
- }
-
moved = (jump_flags & CURSOR_MOVED);
+ in_winbar = (jump_flags & MOUSE_WINBAR);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
+ if ((in_winbar || in_status_line) && is_click) {
+ // Handle click event on window bar or status lin
+ int click_grid = mouse_grid;
+ int click_row = mouse_row;
+ int click_col = mouse_col;
+ win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
+
+ StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs
+ : wp->w_winbar_click_defs;
+
+ if (click_defs != NULL) {
+ switch (click_defs[click_col].type) {
+ case kStlClickDisabled:
+ break;
+ case kStlClickFuncRun:
+ call_click_def_func(click_defs, click_col, which_button);
+ break;
+ default:
+ assert(false && "winbar and statusline only support %@ for clicks");
+ break;
+ }
+ }
+
+ return false;
+ } else if (in_winbar) {
+ // A drag or release event in the window bar has no side effects.
+ return false;
+ }
// When jumping to another window, clear a pending operator. That's a bit
// friendlier than beeping and not jumping to that window.
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 770099ab65..dbe6cf2077 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -88,6 +88,7 @@
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
@@ -5337,11 +5338,27 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
attr = (wp == curwin) ? HL_ATTR(HLF_WBR) : HL_ATTR(HLF_WBRNC);
maxwidth = wp->w_width_inner;
use_sandbox = was_set_insecurely(wp, "winbar", 0);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ // Allocate / resize the click definitions array for winbar if needed.
+ if (wp->w_winbar_height && wp->w_winbar_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = (size_t)maxwidth;
+ wp->w_winbar_click_defs = xcalloc(wp->w_winbar_click_defs_size, sizeof(StlClickRecord));
+ }
} else {
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
maxwidth = is_stl_global ? Columns : wp->w_width;
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ // Allocate / resize the click definitions array for statusline if needed.
+ if (wp->w_status_click_defs_size < (size_t)maxwidth) {
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = maxwidth;
+ wp->w_status_click_defs = xcalloc(wp->w_status_click_defs_size, sizeof(StlClickRecord));
+ }
+
if (draw_ruler) {
stl = p_ruf;
// advance past any leading group spec - implicit in ru_col
@@ -5445,26 +5462,38 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
grid_puts_line_flush(false);
- if (wp == NULL) {
- // Fill the tab_page_click_defs array for clicking in the tab pages line.
- col = 0;
- len = 0;
- p = buf;
- StlClickDefinition cur_click_def = {
- .type = kStlClickDisabled,
- };
- for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
- while (col < len) {
- tab_page_click_defs[col++] = cur_click_def;
- }
- p = (char_u *)tabtab[n].start;
- cur_click_def = tabtab[n].def;
+ // Fill the tab_page_click_defs, w_status_click_defs or w_winbar_click_defs array for clicking
+ // in the tab page line, status line or window bar
+ StlClickDefinition *click_defs = (wp == NULL) ? tab_page_click_defs
+ : draw_winbar ? wp->w_winbar_click_defs
+ : wp->w_status_click_defs;
+
+ if (click_defs == NULL) {
+ goto theend;
+ }
+
+ col = 0;
+ len = 0;
+ p = buf;
+ StlClickDefinition cur_click_def = {
+ .type = kStlClickDisabled,
+ };
+ for (n = 0; tabtab[n].start != NULL; n++) {
+ len += vim_strnsize(p, (int)(tabtab[n].start - (char *)p));
+ while (col < len) {
+ click_defs[col++] = cur_click_def;
}
- while (col < Columns) {
- tab_page_click_defs[col++] = cur_click_def;
+ p = (char_u *)tabtab[n].start;
+ cur_click_def = tabtab[n].def;
+ if ((wp != NULL) && !(cur_click_def.type == kStlClickDisabled
+ || cur_click_def.type == kStlClickFuncRun)) {
+ // window bar and status line only support click functions
+ cur_click_def.type = kStlClickDisabled;
}
}
+ while (col < maxwidth) {
+ click_defs[col++] = cur_click_def;
+ }
theend:
entered = false;
@@ -5572,7 +5601,6 @@ void check_for_delay(bool check_msg_scroll)
}
}
-
/// Resize the screen to Rows and Columns.
///
/// Allocate default_grid.chars[] and other grid arrays.
@@ -5641,7 +5669,7 @@ retry:
StlClickDefinition *new_tab_page_click_defs =
xcalloc((size_t)Columns, sizeof(*new_tab_page_click_defs));
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
xfree(tab_page_click_defs);
tab_page_click_defs = new_tab_page_click_defs;
@@ -5672,19 +5700,19 @@ retry:
resizing = false;
}
-/// Clear tab_page_click_defs table
+/// Clear status line, window bar or tab page line click definition table
///
/// @param[out] tpcd Table to clear.
/// @param[in] tpcd_size Size of the table.
-void clear_tab_page_click_defs(StlClickDefinition *const tpcd, const long tpcd_size)
+void stl_clear_click_defs(StlClickDefinition *const click_defs, const long click_defs_size)
{
- if (tpcd != NULL) {
- for (long i = 0; i < tpcd_size; i++) {
- if (i == 0 || tpcd[i].func != tpcd[i - 1].func) {
- xfree(tpcd[i].func);
+ if (click_defs != NULL) {
+ for (long i = 0; i < click_defs_size; i++) {
+ if (i == 0 || click_defs[i].func != click_defs[i - 1].func) {
+ xfree(click_defs[i].func);
}
}
- memset(tpcd, 0, (size_t)tpcd_size * sizeof(tpcd[0]));
+ memset(click_defs, 0, (size_t)click_defs_size * sizeof(click_defs[0]));
}
}
@@ -6200,7 +6228,7 @@ void draw_tabline(void)
// Init TabPageIdxs[] to zero: Clicking outside of tabs has no effect.
assert(Columns == tab_page_click_defs_size);
- clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
+ stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size);
// Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
index f3beeff8a9..0afbc24538 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -30,24 +30,6 @@ typedef enum {
// Maximum columns for terminal highlight attributes
#define TERM_ATTRS_MAX 1024
-/// Status line click definition
-typedef struct {
- enum {
- kStlClickDisabled = 0, ///< Clicks to this area are ignored.
- kStlClickTabSwitch, ///< Switch to the given tab.
- kStlClickTabClose, ///< Close given tab.
- kStlClickFuncRun, ///< Run user function.
- } type; ///< Type of the click.
- int tabnr; ///< Tab page number.
- char *func; ///< Function to run.
-} StlClickDefinition;
-
-/// Used for tabline clicks
-typedef struct {
- StlClickDefinition def; ///< Click definition.
- const char *start; ///< Location where region starts.
-} StlClickRecord;
-
/// Array defining what should be done when tabline is clicked
EXTERN StlClickDefinition *tab_page_click_defs INIT(= NULL);
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4076bb2531..835aba204d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5119,6 +5119,12 @@ static void win_free(win_T *wp, tabpage_T *tp)
xfree(wp->w_localdir);
xfree(wp->w_prevdir);
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+
// Remove the window from the b_wininfo lists, it may happen that the
// freed memory is re-used for another window.
FOR_ALL_BUFFERS(buf) {
@@ -6612,6 +6618,23 @@ void last_status(bool morewin)
global_stl_height() > 0);
}
+// Remove status line from window, replacing it with a horizontal separator if needed.
+static void win_remove_status_line(win_T *wp, bool add_hsep)
+{
+ wp->w_status_height = 0;
+ if (add_hsep) {
+ wp->w_hsep_height = 1;
+ } else {
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT);
+ }
+ comp_col();
+
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = 0;
+ wp->w_status_click_defs = NULL;
+}
+
// Look for resizable frames and take lines from them to make room for the statusline
static void resize_frame_for_status(frame_T *fr)
{
@@ -6652,10 +6675,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
if (is_last) {
if (wp->w_status_height != 0 && (!statusline || is_stl_global)) {
- // Remove status line
- wp->w_status_height = 0;
- win_new_height(wp, wp->w_height + STATUS_HEIGHT);
- comp_col();
+ win_remove_status_line(wp, false);
} else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
// Add statusline to window if needed
wp->w_status_height = STATUS_HEIGHT;
@@ -6665,9 +6685,7 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
} else if (wp->w_status_height != 0 && is_stl_global) {
// If statusline is global and the window has a statusline, replace it with a horizontal
// separator
- wp->w_status_height = 0;
- wp->w_hsep_height = 1;
- comp_col();
+ win_remove_status_line(wp, true);
} else if (wp->w_status_height == 0 && !is_stl_global) {
// If statusline isn't global and the window doesn't have a statusline, re-add it
wp->w_status_height = STATUS_HEIGHT;
@@ -6675,13 +6693,8 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
comp_col();
}
redraw_all_later(SOME_VALID);
- } else if (fr->fr_layout == FR_COL) {
- // For a column frame, recursively call this function for all child frames
- FOR_ALL_FRAMES(fp, fr->fr_child) {
- last_status_rec(fp, statusline, is_stl_global);
- }
} else {
- // For a row frame, recursively call this function for all child frames
+ // For a column or row frame, recursively call this function for all child frames
FOR_ALL_FRAMES(fp, fr->fr_child) {
last_status_rec(fp, statusline, is_stl_global);
}
@@ -6697,6 +6710,14 @@ void set_winbar(void)
wp->w_winbar_height = winbar_height;
win_set_inner_size(wp);
wp->w_redr_winbar = winbar_height;
+
+ if (winbar_height == 0) {
+ // When removing winbar, deallocate the w_winbar_click_defs array
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = 0;
+ wp->w_winbar_click_defs = NULL;
+ }
}
}
}
diff --git a/test/functional/ui/global_statusline_spec.lua b/test/functional/ui/global_statusline_spec.lua
deleted file mode 100644
index 369c4a31f1..0000000000
--- a/test/functional/ui/global_statusline_spec.lua
+++ /dev/null
@@ -1,260 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local Screen = require('test.functional.ui.screen')
-local clear, command, feed = helpers.clear, helpers.command, helpers.feed
-local eq, funcs, meths = helpers.eq, helpers.funcs, helpers.meths
-
-describe('global statusline', function()
- local screen
-
- before_each(function()
- clear()
- screen = Screen.new(60, 16)
- screen:attach()
- command('set laststatus=3')
- command('set ruler')
- end)
-
- it('works', function()
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {bold = true, foreground = Screen.colors.Blue1};
- [2] = {bold = true, reverse = true};
- }}
-
- feed('i<CR><CR>')
- screen:expect{grid=[[
- |
- |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] [+] 3,1 All}|
- {3:-- INSERT --} |
- ]], attr_ids={
- [1] = {bold = true, foreground = Screen.colors.Blue};
- [2] = {bold = true, reverse = true};
- [3] = {bold = true};
- }}
- end)
-
- it('works with splits', function()
- command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {bold = true, foreground = Screen.colors.Blue1};
- [3] = {bold = true, reverse = true};
- }}
- end)
-
- it('works when switching between values of laststatus', function()
- command('set laststatus=1')
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- 0,0-1 All |
- ]], attr_ids={
- [1] = {foreground = Screen.colors.Blue, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {foreground = Screen.colors.Blue, bold = true};
- [2] = {reverse = true, bold = true};
- }}
-
- command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
- command('set laststatus=2')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{1:< Name] 0,0-1 }│{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{3:<No Name] 0,0-1 All}|
- {2:~ }│{2:~ }│{2:~}│ |
- {1:<No Name] 0,0-1 All < Name] 0,0-1 <}│{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {1:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=0')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{1:< Name] 0,0-1 }│{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{3:<No Name] 0,0-1 All}|
- {2:~ }│{2:~ }│{2:~}│ |
- {1:<No Name] 0,0-1 All < Name] 0,0-1 <}│{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- 0,0-1 All |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
-
- command('set laststatus=3')
- screen:expect{grid=[[
- │ │ │^ |
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }├────────────────┤{2:~}│{2:~ }|
- {2:~ }│ │{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}│{2:~ }|
- {2:~ }│{2:~ }│{2:~}├────────────────────|
- {2:~ }│{2:~ }│{2:~}│ |
- ────────────────────┴────────────────┴─┤{2:~ }|
- │{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {2:~ }│{2:~ }|
- {3:[No Name] 0,0-1 All}|
- |
- ]], attr_ids={
- [1] = {reverse = true};
- [2] = {foreground = Screen.colors.Blue, bold = true};
- [3] = {reverse = true, bold = true};
- }}
- end)
-
- it('win_move_statusline() can reduce cmdheight to 1', function()
- eq(1, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, -1)
- eq(2, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, -1)
- eq(3, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, 1)
- eq(2, meths.get_option('cmdheight'))
- funcs.win_move_statusline(0, 1)
- eq(1, meths.get_option('cmdheight'))
- end)
-
- it('mouse dragging can reduce cmdheight to 1', function()
- command('set mouse=a')
- meths.input_mouse('left', 'press', '', 0, 14, 10)
- eq(1, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 13, 10)
- eq(2, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 12, 10)
- eq(3, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 13, 10)
- eq(2, meths.get_option('cmdheight'))
- meths.input_mouse('left', 'drag', '', 0, 14, 10)
- eq(1, meths.get_option('cmdheight'))
- end)
-end)
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
new file mode 100644
index 0000000000..3e1b284856
--- /dev/null
+++ b/test/functional/ui/statusline_spec.lua
@@ -0,0 +1,317 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+local eq = helpers.eq
+local funcs = helpers.funcs
+local meths = helpers.meths
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
+local eval = helpers.eval
+
+describe('statusline clicks', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ command('set laststatus=2')
+ exec([=[
+ function! MyClickFunc(minwid, clicks, button, mods)
+ let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
+ endfunction
+ ]=])
+ end)
+
+ it('works', function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar', 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)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar in floating window', function()
+ meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5,
+ border = "single" })
+ meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T',
+ { scope = 'local' })
+ meths.input_mouse('left', 'press', '', 0, 2, 23)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works when there are multiple windows', function()
+ command('split')
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ 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, 4, 17)
+ eq('0 1 r', eval("g:testvar"))
+ meths.input_mouse('middle', 'press', '', 0, 3, 17)
+ eq('0 1 m', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works with Lua function', function()
+ exec_lua([[
+ function clicky_func(minwid, clicks, button, mods)
+ vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
+ end
+ ]])
+ meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('ignores unsupported click items', function()
+ command('tabnew | tabprevious')
+ meths.set_option('statusline', '%2TNot clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(1, meths.get_current_tabpage().id)
+ meths.set_option('statusline', '%2XNot clicky stuff%X')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(2, #meths.list_tabpages())
+ end)
+end)
+
+describe('global statusline', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 16)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ [4] = {reverse = true};
+ })
+ command('set laststatus=3')
+ command('set ruler')
+ end)
+
+ it('works', function()
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ feed('i<CR><CR>')
+ screen:expect([[
+ |
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] 3,1 All}|
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('works with splits', function()
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('works when switching between values of laststatus', function()
+ command('set laststatus=1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ command('set laststatus=2')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {4:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=0')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('win_move_statusline() can reduce cmdheight to 1', function()
+ eq(1, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(3, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+
+ it('mouse dragging can reduce cmdheight to 1', function()
+ command('set mouse=a')
+ meths.input_mouse('left', 'press', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 12, 10)
+ eq(3, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+end)