feat(ui): add 'statuscolumn' option

Problem:    Unable to customize the column next to a window ('gutter').
Solution:   Add 'statuscolumn' option that follows the 'statusline' syntax,
	    allowing to customize the status column. Also supporting the %@
	    click execute function label. Adds new items @C and @s which
	    will print the fold and sign columns. Line numbers and signs
	    can be clicked, highlighted, aligned, transformed, margined etc.
This commit is contained in:
luukvbaal 2023-01-09 18:12:06 +01:00 committed by GitHub
parent 50f03773f4
commit 364b131f42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 681 additions and 43 deletions

View File

@ -2001,10 +2001,10 @@ v:lc_time The current locale setting for time messages of the runtime
command. See |multi-lang|.
*v:lnum* *lnum-variable*
v:lnum Line number for the 'foldexpr' |fold-expr|, 'formatexpr' and
'indentexpr' expressions, tab page number for 'guitablabel'
and 'guitabtooltip'. Only valid while one of these
expressions is being evaluated. Read-only when in the
v:lnum Line number for the 'foldexpr' |fold-expr|, 'formatexpr',
'indentexpr' and 'statuscolumn' expressions, tab page number
for 'guitablabel' and 'guitabtooltip'. Only valid while one of
these expressions is being evaluated. Read-only when in the
|sandbox|.
*v:lua* *lua-variable*
@ -2138,6 +2138,10 @@ v:register The name of the register in effect for the current normal mode
'*' or '+'.
Also see |getreg()| and |setreg()|
*v:relnum* *relnum-variable*
v:relnum Relative line number for the 'statuscolumn' expression.
Read-only.
*v:scrollstart* *scrollstart-variable*
v:scrollstart String describing the script or function that caused the
screen to scroll up. It's only set when it is empty, thus the
@ -2293,6 +2297,11 @@ v:version Vim version number: major version times 100 plus minor
*v:vim_did_enter* *vim_did_enter-variable*
v:vim_did_enter 0 during startup, 1 just before |VimEnter|.
Read-only.
*v:wrap* *wrap-variable*
v:wrap Boolean indicating whether 'statuscolumn' is being evaluated
for the wrapped part of a line.
Read-only.
*v:warningmsg* *warningmsg-variable*

View File

@ -118,6 +118,11 @@ The following new APIs or features were added.
• |'splitkeep'| option to control the scroll behavior of horizontal splits.
• |'statuscolumn'| option to customize the area to the side of a window,
normally containing the fold, sign and number columns. This new option follows
the 'statusline' syntax and can be used to transform the line numbers, create
mouse click callbacks for |signs|, introduce a custom margin or separator etc.
• |nvim_select_popupmenu_item()| now supports |cmdline-completion| popup menu.
• |'diffopt'| now includes a `linematch` option to enable a second-stage diff

View File

@ -6001,6 +6001,52 @@ A jump table for the options with a short description can be found at |Q_op|.
In case of buffer changing commands the cursor is placed at the column
where it was the last time the buffer was edited.
*'statuscolumn'* *'stc'*
'statuscolumn' 'stc' string (default: empty)
local to window
EXPERIMENTAL
When non-empty, this option determines the content of the area to the
side of a window, normally containing the fold, sign and number columns.
The format of this option is like that of 'statusline'.
Some of the items from the 'statusline' format are different for
'statuscolumn':
%l line number of currently drawn line
%r relative line number of currently drawn line
%s sign column for currently drawn line
%C fold column for currently drawn line
To draw the sign and fold columns, they must be included in
'statuscolumn'.
The |v:lnum| variable holds the line number to be drawn.
The |v:relnum| variable holds the relative line number to be drawn.
The |v:wrap| variable holds true for the wrapped part of a line.
Examples: >vim
" Relative number with bar separator and click handlers:
:set statuscolumn=%@SignCb@%s%=%T%@NumCb@%r│%T
" Right aligned relative cursor line number:
:let &stc='%=%{v:relnum?v:relnum:v:lnum} '
" Line numbers in hexadecimal for non wrapped part of lines:
:let &stc='%=%{v:wrap?"":printf("%x",v:lnum)} '
" Human readable line numbers with thousands separator:
:let &stc='%{substitute(v:lnum,"\\d\\zs\\ze\\'
. '%(\\d\\d\\d\\)\\+$",",","g")}'
" Both relative and absolute line numbers with different
" highlighting for odd and even relative numbers:
:let &stc='%#NonText#%{&nu?v:lnum:""}' .
'%=%{&rnu&&(v:lnum%2)?"\ ".v:relnum:""}' .
'%#LineNr#%{&rnu&&!(v:lnum%2)?"\ ".v:relnum:""}'
< WARNING: this expression is evaluated for each screen line so defining
an expensive expression can negatively affect render performance.
*'statusline'* *'stl'* *E540* *E542*
'statusline' 'stl' string (default empty)
global or local to window |global-local|

View File

@ -883,6 +883,7 @@ Short explanation of each option: *option-list*
'splitkeep' 'spk' determines scroll behavior for split windows
'splitright' 'spr' new window is put right of the current one
'startofline' 'sol' commands move cursor to first non-blank in line
'statuscolumn' 'stc' custom format for the status column
'statusline' 'stl' custom format for the status line
'suffixes' 'su' suffixes that are ignored with multiple match
'suffixesadd' 'sua' suffixes added when searching for a file

View File

@ -452,6 +452,9 @@ call <SID>Header(gettext("multiple windows"))
call <SID>AddOption("laststatus", gettext("0, 1, 2 or 3; when to use a status line for the last window"))
call append("$", " \tset ls=" . &ls)
if has("statusline")
call <SID>AddOption("statuscolumn", gettext("custom format for the status column"))
call append("$", "\t" .. s:local_to_window)
call <SID>OptionG("stc", &stc)
call <SID>AddOption("statusline", gettext("alternate format to be used for a status line"))
call <SID>OptionG("stl", &stl)
endif

View File

@ -2238,6 +2238,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
fillchar,
maxwidth,
hltab_ptr,
NULL,
NULL);
PUT(result, "width", INTEGER_OBJ(width));

View File

@ -3236,7 +3236,7 @@ void maketitle(void)
if (*p_titlestring != NUL) {
if (stl_syntax & STL_IN_TITLE) {
build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring,
"titlestring", 0, 0, maxlen, NULL, NULL);
"titlestring", 0, 0, maxlen, NULL, NULL, NULL);
title_str = buf;
} else {
title_str = p_titlestring;
@ -3342,7 +3342,7 @@ void maketitle(void)
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring,
"iconstring", 0, 0, 0, NULL, NULL);
"iconstring", 0, 0, 0, NULL, NULL, NULL);
} else {
icon_str = p_iconstring;
}

View File

@ -204,6 +204,8 @@ typedef struct {
#define w_p_cc w_onebuf_opt.wo_cc // 'colorcolumn'
char *wo_sbr;
#define w_p_sbr w_onebuf_opt.wo_sbr // 'showbreak'
char *wo_stc;
#define w_p_stc w_onebuf_opt.wo_stc // 'statuscolumn'
char *wo_stl;
#define w_p_stl w_onebuf_opt.wo_stl // 'statusline'
char *wo_wbr;
@ -1300,6 +1302,7 @@ struct window_S {
linenr_T w_redraw_bot; // when != 0: last line needing redraw
bool w_redr_status; // if true statusline/winbar must be redrawn
bool w_redr_border; // if true border must be redrawn
bool w_redr_statuscol; // if true 'statuscolumn' must be redrawn
// remember what is shown in the ruler for this window (if 'ruler' set)
pos_T w_ru_cursor; // cursor position shown in ruler
@ -1404,6 +1407,31 @@ struct window_S {
StlClickDefinition *w_winbar_click_defs;
// Size of the w_winbar_click_defs array
size_t w_winbar_click_defs_size;
// Status column click definitions
StlClickDefinition *w_statuscol_click_defs;
// Size of the w_statuscol_click_defs array
size_t w_statuscol_click_defs_size;
};
/// Struct to hold info for 'statuscolumn'
typedef struct statuscol statuscol_T;
struct statuscol {
int width; // width of the status column
int cur_attr; // current attributes in text
int num_attr; // attributes used for line number
int fold_attr; // attributes used for fold column
int sign_attr[SIGN_SHOW_MAX]; // attributes used for signs
int truncate; // truncated width
bool draw; // draw statuscolumn or not
char fold_text[10]; // text in fold column (%C)
char *sign_text[SIGN_SHOW_MAX]; // text in sign column (%s)
char text[MAXPATHL]; // text in status column
char *textp; // current position in text
size_t text_len; // length of text
stl_hlrec_t *hlrec; // highlight groups
stl_hlrec_t *hlrecp; // current highlight group
};
/// Macros defined in Vim, but not in Neovim

View File

@ -21,6 +21,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawline.h"
#include "nvim/eval.h"
#include "nvim/extmark_defs.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
@ -43,6 +44,7 @@
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/statusline.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/terminal.h"
@ -60,6 +62,7 @@ typedef enum {
WL_FOLD, // 'foldcolumn'
WL_SIGN, // column for signs
WL_NR, // line number
WL_STC, // 'statuscolumn'
WL_BRI, // 'breakindent'
WL_SBR, // 'showbreak' or 'diff'
WL_LINE, // text in the line
@ -395,6 +398,90 @@ static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int
return num_signs;
}
static void get_statuscol_str(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines,
int cul_attr, int sign_num_attr, SignTextAttrs *sattrs,
foldinfo_T foldinfo, char_u *extra, statuscol_T *stcp)
{
long relnum;
bool wrapped = row != startrow + filler_lines;
bool use_cul = use_cursor_line_sign(wp, lnum);
// Set num, fold and sign text and attrs, empty when wrapped
if (row == startrow) {
relnum = labs(get_cursor_rel_lnum(wp, lnum));
stcp->num_attr = sign_num_attr ? sign_num_attr
: get_line_number_attr(wp, lnum, row, startrow, filler_lines);
if (compute_foldcolumn(wp, 0)) {
size_t n = fill_foldcolumn((char_u *)stcp->fold_text, wp, foldinfo, lnum);
stcp->fold_text[n] = NUL;
stcp->fold_attr = win_hl_attr(wp, use_cul ? HLF_CLF : HLF_FC);
}
}
int i = 0;
for (; i < wp->w_scwidth; i++) {
SignTextAttrs *sattr = wrapped ? NULL : sign_get_attr(i, sattrs, wp->w_scwidth);
stcp->sign_text[i] = sattr && sattr->text ? sattr->text : " ";
stcp->sign_attr[i] = use_cul && cul_attr ? cul_attr : sattr ? sattr->hl_attr_id : 0;
}
stcp->sign_text[i] = NULL;
int width = build_statuscol_str(wp, row == startrow, wrapped, lnum, relnum,
stcp->width, ' ', stcp->text, &stcp->hlrec, stcp);
// Force a redraw in case of error or when truncated
if (*wp->w_p_stc == NUL || (stcp->truncate > 0 && wp->w_nrwidth < MAX_NUMBERWIDTH)) {
if (stcp->truncate) { // Avoid truncating 'statuscolumn'
wp->w_nrwidth = MIN(MAX_NUMBERWIDTH, wp->w_nrwidth + stcp->truncate);
wp->w_nrwidth_width = wp->w_nrwidth;
} else { // 'statuscolumn' reset due to error
wp->w_nrwidth_line_count = 0;
wp->w_nrwidth = (wp->w_p_nu || wp->w_p_rnu) * number_width(wp);
}
wp->w_redr_statuscol = true;
return;
}
// Reset text/highlight pointer and current attr for new line
stcp->textp = stcp->text;
stcp->hlrecp = stcp->hlrec;
stcp->cur_attr = stcp->num_attr;
stcp->text_len = strlen(stcp->text);
int fill = stcp->width - width;
if (fill > 0) {
// Fill up with ' '
memset(&stcp->text[stcp->text_len], ' ', (size_t)fill);
stcp->text_len += (size_t)fill;
stcp->text[stcp->text_len] = NUL;
}
}
static void get_statuscol_display_info(LineDrawState *draw_state, int *char_attr, int *n_extrap,
int *c_extrap, int *c_finalp, char_u *extra, char **pp_extra,
statuscol_T *stcp)
{
*c_extrap = NUL;
*c_finalp = NUL;
do {
*draw_state = WL_STC;
*char_attr = stcp->cur_attr;
*pp_extra = stcp->textp;
*n_extrap = stcp->hlrecp->start ? (int)(stcp->hlrecp->start - stcp->textp)
: (int)strlen(*pp_extra);
// Prepare for next highlight section if not yet at the end
if (stcp->textp + *n_extrap < stcp->text + stcp->text_len) {
int hl = stcp->hlrecp->userhl;
stcp->textp = stcp->hlrecp->start;
stcp->cur_attr = hl < 0 ? syn_id2attr(-stcp->hlrecp->userhl)
: hl > 0 ? hl : stcp->num_attr;
stcp->hlrecp++;
*draw_state = WL_STC - 1;
}
// Skip over empty highlight sections
} while (*n_extrap == 0 && stcp->textp < stcp->text + stcp->text_len);
}
/// Return true if CursorLineNr highlight is to be used for the number column.
///
/// - 'cursorline' must be set
@ -1098,6 +1185,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
extra_check = true;
}
statuscol_T statuscol = { 0 };
if (*wp->w_p_stc != NUL) {
// Draw the 'statuscolumn' if option is set.
statuscol.draw = true;
statuscol.width = win_col_off(wp);
}
int sign_idx = 0;
// Repeat for the whole displayed line.
for (;;) {
@ -1125,9 +1219,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
// Skip fold, sign and number states if 'statuscolumn' is set.
if (draw_state == WL_FOLD - 1 && n_extra == 0 && statuscol.draw) {
draw_state = WL_STC - 1;
}
if (draw_state == WL_FOLD - 1 && n_extra == 0) {
int fdc = compute_foldcolumn(wp, 0);
draw_state = WL_FOLD;
if (fdc > 0) {
// Draw the 'foldcolumn'. Allocate a buffer, "extra" may
@ -1217,7 +1315,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
if (draw_state == WL_NR && n_extra == 0) {
if (draw_state == WL_STC - 1 && n_extra == 0) {
draw_state = WL_STC;
// Draw the 'statuscolumn' if option is set.
if (statuscol.draw) {
if (statuscol.text_len == 0) {
get_statuscol_str(wp, lnum, row, startrow, filler_lines, cul_attr,
sign_num_attr, sattrs, foldinfo, extra, &statuscol);
if (wp->w_redr_statuscol) {
return 0;
}
}
get_statuscol_display_info(&draw_state, &char_attr, &n_extra, &c_extra,
&c_final, extra, &p_extra, &statuscol);
}
}
if (draw_state == WL_STC && n_extra == 0) {
win_col_offset = off;
}
@ -1349,7 +1463,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& wp == curwin
&& lnum == wp->w_cursor.lnum
&& vcol >= (long)wp->w_virtcol)
|| (number_only && draw_state > WL_NR))
|| (number_only && draw_state > WL_STC))
&& filler_todo <= 0) {
draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row);
grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp, bg_attr, false);
@ -2214,7 +2328,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
&& wp->w_p_list
&& (wp->w_p_wrap ? (wp->w_skipcol > 0 && row == 0) : wp->w_leftcol > 0)
&& filler_todo <= 0
&& draw_state > WL_NR
&& draw_state > WL_STC
&& c != NUL) {
c = wp->w_p_lcs_chars.prec;
lcs_prec_todo = NUL;
@ -2508,7 +2622,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
col++;
// UTF-8: Put a 0 in the second screen char.
linebuf_char[off][0] = 0;
if (draw_state > WL_NR && filler_todo <= 0) {
if (draw_state > WL_STC && filler_todo <= 0) {
vcol++;
}
// When "tocol" is halfway through a character, set it to the end of
@ -2591,7 +2705,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
// Only advance the "vcol" when after the 'number' or 'relativenumber'
// column.
if (draw_state > WL_NR
if (draw_state > WL_STC
&& filler_todo <= 0) {
vcol++;
}
@ -2601,7 +2715,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
// restore attributes after "predeces" in 'listchars'
if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) {
if (draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) {
char_attr = saved_attr3;
}
@ -2697,6 +2811,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
if (filler_todo <= 0) {
need_showbreak = true;
}
if (statuscol.draw) {
if (row == startrow + 1 || row == startrow + filler_lines) {
// Re-evaluate 'statuscolumn' for the first wrapped row and non filler line
statuscol.text_len = 0;
} else { // Otherwise just reset the text/hlrec pointers
statuscol.textp = statuscol.text;
statuscol.hlrecp = statuscol.hlrec;
} // Fall back to default columns if the 'n' flag isn't in 'cpo'
statuscol.draw = vim_strchr(p_cpo, CPO_NUMCOL) == NULL;
}
filler_todo--;
// When the filler lines are actually below the last line of the
// file, don't draw the line itself, break here.

View File

@ -522,7 +522,7 @@ int update_screen(void)
// TODO(bfredl): special casing curwin here is SÅ JÄVLA BULL.
// Either this should be done for all windows or not at all.
if (curwin->w_redr_type < UPD_NOT_VALID
&& curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
&& curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu || *curwin->w_p_stc)
? number_width(curwin) : 0)) {
curwin->w_redr_type = UPD_NOT_VALID;
}
@ -1032,7 +1032,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Force redraw when width of 'number' or 'relativenumber' column
// changes.
int nrwidth = (wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) : 0;
int nrwidth = (wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc) ? number_width(wp) : 0;
if (wp->w_nrwidth != nrwidth) {
type = UPD_NOT_VALID;
wp->w_nrwidth = nrwidth;
@ -1823,6 +1823,18 @@ static void win_update(win_T *wp, DecorProviders *providers)
did_update = DID_NONE;
}
// 'statuscolumn' width has changed or errored, start from the top.
if (wp->w_redr_statuscol) {
wp->w_redr_statuscol = false;
idx = 0;
row = 0;
lnum = wp->w_topline;
wp->w_lines_valid = 0;
wp->w_valid &= ~VALID_WCOL;
decor_providers_invoke_win(wp, providers, &line_providers, &provider_err);
continue;
}
if (lnum > buf->b_ml.ml_line_count) {
eof = true;
break;

View File

@ -267,6 +267,8 @@ static struct vimvar {
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
VV(VV_RELNUM, "relnum", VAR_NUMBER, VV_RO),
VV(VV_WRAP, "wrap", VAR_BOOL, VV_RO),
};
#undef VV

View File

@ -165,6 +165,8 @@ typedef enum {
VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
VV__NULL_BLOB, // Blob with NULL value. For test purposes only.
VV_LUA,
VV_RELNUM,
VV_WRAP,
} VimVarIndex;
/// All recognized msgpack types

View File

@ -291,6 +291,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
pos_T start_visual;
bool moved; // Has cursor moved?
bool in_winbar; // mouse in window bar
bool in_statuscol; // mouse in status column
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
@ -645,10 +646,11 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
moved = (jump_flags & CURSOR_MOVED);
in_winbar = (jump_flags & MOUSE_WINBAR);
in_statuscol = (jump_flags & MOUSE_STATUSCOL);
in_status_line = (jump_flags & IN_STATUS_LINE);
in_sep_line = (jump_flags & IN_SEP_LINE);
if ((in_winbar || in_status_line) && is_click) {
if ((in_winbar || in_status_line || in_statuscol) && is_click) {
// Handle click event on window bar or status lin
int click_grid = mouse_grid;
int click_row = mouse_row;
@ -659,7 +661,8 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
}
StlClickDefinition *click_defs = in_status_line ? wp->w_status_click_defs
: wp->w_winbar_click_defs;
: in_winbar ? wp->w_winbar_click_defs
: wp->w_statuscol_click_defs;
if (in_status_line && global_stl_height() > 0) {
// global statusline is displayed for the current window,
@ -682,8 +685,8 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
}
return false;
} else if (in_winbar) {
// A drag or release event in the window bar has no side effects.
} else if (in_winbar || in_statuscol) {
// A drag or release event in the window bar and status column has no side effects.
return false;
}
@ -1027,6 +1030,7 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
static bool on_status_line = false;
static bool on_sep_line = false;
static bool on_winbar = false;
static bool on_statuscol = false;
static int prev_row = -1;
static int prev_col = -1;
static int did_drag = false; // drag was noticed
@ -1069,6 +1073,9 @@ retnomove:
if (on_winbar) {
return IN_OTHER_WIN | MOUSE_WINBAR;
}
if (on_statuscol) {
return IN_OTHER_WIN | MOUSE_STATUSCOL;
}
if (flags & MOUSE_MAY_STOP_VIS) {
end_visual_mode();
redraw_curbuf_later(UPD_INVERTED); // delete the inversion
@ -1103,6 +1110,10 @@ retnomove:
? wp->w_winbar_height != 0
: false;
on_statuscol = grid == (col < win_col_off(wp))
? *wp->w_p_stc != NUL
: false;
on_sep_line = grid == DEFAULT_GRID_HANDLE && col >= wp->w_width
? col - wp->w_width + 1 == 1
: false;
@ -1130,6 +1141,10 @@ retnomove:
return IN_OTHER_WIN | MOUSE_WINBAR;
}
if (on_statuscol) {
return IN_OTHER_WIN | MOUSE_STATUSCOL;
}
fdc = win_fdccol_count(wp);
dragwin = NULL;
@ -1230,6 +1245,9 @@ retnomove:
} 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 if (on_statuscol && which_button == MOUSE_RIGHT) {
// After a click on the status column don't start Visual mode.
return IN_OTHER_WIN | MOUSE_STATUSCOL;
} else {
// keep_window_focus must be true
// before moving the cursor for a left click, stop Visual mode

View File

@ -9,17 +9,18 @@
#include "nvim/window.h"
/// jump_to_mouse() returns one of first five these values, possibly with
/// some of the other four added.
/// some of the other five added.
enum {
IN_UNKNOWN = 0,
IN_BUFFER = 1,
IN_STATUS_LINE = 2, ///< on status or command line
IN_SEP_LINE = 4, ///< on vertical separator line
IN_OTHER_WIN = 8, ///< in other window but can't go there
IN_STATUS_LINE = 2, ///< on status or command line
IN_SEP_LINE = 4, ///< on vertical separator line
IN_OTHER_WIN = 8, ///< in other window but can't go there
CURSOR_MOVED = 0x100,
MOUSE_FOLD_CLOSE = 0x200, ///< clicked on '-' in fold column
MOUSE_FOLD_OPEN = 0x400, ///< clicked on '+' in fold column
MOUSE_WINBAR = 0x800, ///< in window toolbar
MOUSE_FOLD_CLOSE = 0x200, ///< clicked on '-' in fold column
MOUSE_FOLD_OPEN = 0x400, ///< clicked on '+' in fold column
MOUSE_WINBAR = 0x800, ///< in window toolbar
MOUSE_STATUSCOL = 0x1000, ///< in 'statuscolumn'
};
/// flags for jump_to_mouse()

View File

@ -649,7 +649,8 @@ void validate_cursor_col(void)
// fold column and sign column (these don't move when scrolling horizontally).
int win_col_off(win_T *wp)
{
return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
return ((wp->w_p_nu || wp->w_p_rnu || (*wp->w_p_stc != NUL)) ?
(number_width(wp) + (*wp->w_p_stc == NUL)) : 0)
+ (cmdwin_type == 0 || wp != curwin ? 0 : 1)
+ win_fdccol_count(wp)
+ (win_signcol_count(wp) * win_signcol_width(wp));

View File

@ -2094,6 +2094,9 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
if (curwin->w_p_spell) {
errmsg = did_set_spelllang(curwin);
}
} else if (((int *)varp == &curwin->w_p_nu || (int *)varp == &curwin->w_p_rnu)
&& *curwin->w_p_stc != NUL) { // '(relative)number' + 'statuscolumn'
curwin->w_nrwidth_line_count = 0;
}
if ((int *)varp == &curwin->w_p_arab) {
@ -2316,7 +2319,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
} else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) {
if (value < 1) {
errmsg = e_positive;
} else if (value > 20) {
} else if (value > MAX_NUMBERWIDTH) {
errmsg = e_invarg;
}
} else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) {
@ -3630,6 +3633,9 @@ void unset_global_local_option(char *name, void *from)
clear_string_option(&((win_T *)from)->w_p_ve);
((win_T *)from)->w_ve_flags = 0;
break;
case PV_STC:
clear_string_option(&((win_T *)from)->w_p_stc);
break;
}
}
@ -4014,6 +4020,8 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curwin->w_p_winhl);
case PV_WINBL:
return (char_u *)&(curwin->w_p_winbl);
case PV_STC:
return (char_u *)&(curwin->w_p_stc);
default:
iemsg(_("E356: get_varp ERROR"));
}
@ -4102,6 +4110,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_scl = copy_option_val(from->wo_scl);
to->wo_winhl = copy_option_val(from->wo_winhl);
to->wo_winbl = from->wo_winbl;
to->wo_stc = copy_option_val(from->wo_stc);
// Copy the script context so that we know were the value was last set.
memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx));
@ -4139,6 +4148,7 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_ve);
check_string_option(&wop->wo_wbr);
check_string_option(&wop->wo_stc);
}
/// Free the allocated memory inside a winopt_T.
@ -4165,6 +4175,7 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_ve);
clear_string_option(&wop->wo_wbr);
clear_string_option(&wop->wo_stc);
}
void didset_window_options(win_T *wp, bool valid_cursor)

View File

@ -19,6 +19,8 @@ typedef enum {
#define BCO_ALWAYS 2 // always copy the options
#define BCO_NOHELP 4 // don't touch the help related options
#define MAX_NUMBERWIDTH 20 // used for 'numberwidth' and 'statuscolumn'
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.h.generated.h"
#endif

View File

@ -337,6 +337,8 @@ enum {
STL_ARGLISTSTAT = 'a', ///< Argument list status as (x of y).
STL_PAGENUM = 'N', ///< Page number (when printing).
STL_SHOWCMD = 'S', ///< 'showcmd' buffer
STL_FOLDCOL = 'C', ///< Fold column for 'statuscolumn'
STL_SIGNCOL = 's', ///< Sign column for 'statuscolumn'
STL_VIM_EXPR = '{', ///< Start of expression to substitute.
STL_SEPARATE = '=', ///< Separation between alignment sections.
STL_TRUNCMARK = '<', ///< Truncation mark if line is too long.
@ -354,8 +356,9 @@ enum {
STL_HELPFLAG, STL_HELPFLAG_ALT, STL_FILETYPE, STL_FILETYPE_ALT, \
STL_PREVIEWFLAG, STL_PREVIEWFLAG_ALT, STL_MODIFIED, STL_MODIFIED_ALT, \
STL_QUICKFIX, STL_PERCENTAGE, STL_ALTPERCENT, STL_ARGLISTSTAT, STL_PAGENUM, \
STL_SHOWCMD, STL_VIM_EXPR, STL_SEPARATE, STL_TRUNCMARK, STL_USER_HL, \
STL_HIGHLIGHT, STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \
STL_SHOWCMD, STL_FOLDCOL, STL_SIGNCOL, STL_VIM_EXPR, STL_SEPARATE, \
STL_TRUNCMARK, STL_USER_HL, STL_HIGHLIGHT, STL_TABPAGENR, STL_TABCLOSENR, \
STL_CLICK_FUNC, STL_TABPAGENR, STL_TABCLOSENR, STL_CLICK_FUNC, \
0, \
})
@ -955,6 +958,7 @@ enum {
WV_CULOPT,
WV_CC,
WV_SBR,
WV_STC,
WV_STL,
WV_WFH,
WV_WFW,

View File

@ -2297,6 +2297,15 @@ return {
varname='p_sol',
defaults={if_true=false}
},
{
full_name='statuscolumn', abbreviation='stc',
short_desc=N_("custom format for the status column"),
type='string', scope={'window'},
redraw={'current_window'},
secure=true,
alloced=true,
defaults={if_true=""}
},
{
full_name='statusline', abbreviation='stl',
short_desc=N_("custom format for the status line"),

View File

@ -1177,12 +1177,14 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
redraw_titles();
}
} else if (gvarp == &p_stl || gvarp == &p_wbr || varp == &p_tal
|| varp == &p_ruf) {
// 'statusline', 'winbar', 'tabline' or 'rulerformat'
|| varp == &p_ruf || varp == &curwin->w_p_stc) {
// 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn'
int wid;
if (varp == &p_ruf) { // reset ru_wid first
ru_wid = 0;
} else if (varp == &curwin->w_p_stc) {
curwin->w_nrwidth_line_count = 0;
}
s = *varp;
if (varp == &p_ruf && *s == '%') {
@ -1197,7 +1199,8 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
errmsg = check_stl_option(p_ruf);
}
} else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
// check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!"
// check 'statusline', 'winbar', 'tabline' or 'statuscolumn'
// only if it doesn't start with "%!"
errmsg = check_stl_option(s);
}
if (varp == &p_ruf && errmsg == NULL) {

View File

@ -780,6 +780,16 @@ int number_width(win_T *wp)
}
wp->w_nrwidth_line_count = lnum;
// make best estimate for 'statuscolumn'
if (*wp->w_p_stc != NUL) {
char buf[MAXPATHL];
wp->w_nrwidth_width = 0;
n = build_statuscol_str(wp, true, false, lnum, 0, 0, NUL, buf, NULL, NULL);
n = MAX(n, (wp->w_p_nu || wp->w_p_rnu) * (int)wp->w_p_nuw);
wp->w_nrwidth_width = MIN(n, MAX_NUMBERWIDTH);
return wp->w_nrwidth_width;
}
n = 0;
do {
lnum /= 10;

View File

@ -367,8 +367,9 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
// Make a copy, because the statusline may include a function call that
// might change the option value and free the memory.
stl = xstrdup(stl);
width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name,
opt_scope, fillchar, maxwidth, &hltab, &tabtab);
width = build_stl_str_hl(ewp, buf, sizeof(buf), stl, opt_name, opt_scope,
fillchar, maxwidth, &hltab, &tabtab, NULL);
xfree(stl);
ewp->w_p_crb = p_crb_save;
@ -867,6 +868,32 @@ void draw_tabline(void)
redraw_tabline = false;
}
int build_statuscol_str(win_T *wp, bool setnum, bool wrap, linenr_T lnum, long relnum, int maxwidth,
int fillchar, char *buf, stl_hlrec_t **hlrec, statuscol_T *stcp)
{
if (setnum) {
set_vim_var_nr(VV_LNUM, lnum);
set_vim_var_nr(VV_RELNUM, relnum);
}
set_vim_var_bool(VV_WRAP, wrap);
StlClickRecord *clickrec;
char *stc = xstrdup(wp->w_p_stc);
int width = build_stl_str_hl(wp, buf, MAXPATHL, stc, "statuscolumn", OPT_LOCAL,
fillchar, maxwidth, hlrec, &clickrec, stcp);
xfree(stc);
// Allocate and fill click def array if width has changed
if (wp->w_status_click_defs_size != (size_t)width) {
stl_clear_click_defs(wp->w_statuscol_click_defs, wp->w_statuscol_click_defs_size);
wp->w_statuscol_click_defs = stl_alloc_click_defs(wp->w_statuscol_click_defs, width,
&wp->w_statuscol_click_defs_size);
stl_fill_click_defs(wp->w_statuscol_click_defs, clickrec, buf, width, false);
}
return width;
}
/// Build a string from the status line items in "fmt".
/// Return length of string in screen cells.
///
@ -890,11 +917,13 @@ void draw_tabline(void)
/// @param fillchar Character to use when filling empty space in the statusline
/// @param maxwidth The maximum width to make the statusline
/// @param hltab HL attributes (can be NULL)
/// @param tabtab Tab clicks definition (can be NULL).
/// @param tabtab Tab clicks definition (can be NULL)
/// @param stcp Status column attributes (can be NULL)
///
/// @return The final width of the statusline
int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_name, int opt_scope,
int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
int fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab,
statuscol_T *stcp)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@ -1466,8 +1495,9 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
}
case STL_LINE:
num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
? 0L : (long)(wp->w_cursor.lnum);
// Overload %l with v:lnum for 'statuscolumn'
num = strcmp(opt_name, "statuscolumn") == 0 ? get_vim_var_nr(VV_LNUM)
: (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum);
break;
case STL_NUMLINES:
@ -1565,9 +1595,14 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
case STL_ROFLAG:
case STL_ROFLAG_ALT:
itemisflag = true;
if (wp->w_buffer->b_p_ro) {
str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]");
// Overload %r with v:relnum for 'statuscolumn'
if (strcmp(opt_name, "statuscolumn") == 0) {
num = get_vim_var_nr(VV_RELNUM);
} else {
itemisflag = true;
if (wp->w_buffer->b_p_ro) {
str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]");
}
}
break;
@ -1579,6 +1614,33 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
}
break;
case STL_FOLDCOL: // 'C' for 'statuscolumn'
case STL_SIGNCOL: { // 's' for 'statuscolumn'
if (stcp == NULL) {
break;
}
bool fold = opt == STL_FOLDCOL;
*buf_tmp = NUL;
for (int i = 0; i <= 9; i++) {
char *p = fold ? stcp->fold_text : stcp->sign_text[i];
if ((!p || !*p) && *buf_tmp == NUL) {
break;
}
stl_items[curitem].type = Highlight;
stl_items[curitem].start = out_p + strlen(buf_tmp);
stl_items[curitem].minwid = !p || (fold && i) ? 0 : fold ? stcp->fold_attr
: stcp->sign_attr[i];
curitem++;
if (!p || (fold && i)) {
str = buf_tmp;
break;
}
STRCAT(buf_tmp, p);
}
break;
}
case STL_FILETYPE:
// Copy the filetype if it is not null and the formatted string will fit
// in the temporary buffer
@ -1850,6 +1912,10 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, char *opt_n
// What follows is post-processing to handle alignment and highlighting.
int width = vim_strsize(out);
// Return truncated width for 'statuscolumn'
if (stcp != NULL && width > maxwidth) {
stcp->truncate = width - maxwidth;
}
if (maxwidth > 0 && width > maxwidth) {
// Result is too long, must truncate somewhere.
int item_idx = 0;

View File

@ -5094,6 +5094,9 @@ static void win_free(win_T *wp, tabpage_T *tp)
stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
xfree(wp->w_winbar_click_defs);
stl_clear_click_defs(wp->w_statuscol_click_defs, wp->w_statuscol_click_defs_size);
xfree(wp->w_statuscol_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) {

View File

@ -29,6 +29,7 @@ describe('ffi.cdef', function()
typedef struct window_S win_T;
typedef struct {} stl_hlrec_t;
typedef struct {} StlClickRecord;
typedef struct {} statuscol_T;
typedef struct {} Error;
win_T *find_window_by_handle(int Window, Error *err);
@ -43,7 +44,8 @@ describe('ffi.cdef', function()
int fillchar,
int maxwidth,
stl_hlrec_t **hltab,
StlClickRecord **tabtab
StlClickRecord **tabtab,
statuscol_T *scp
);
]]
@ -57,6 +59,7 @@ describe('ffi.cdef', function()
0,
0,
nil,
nil,
nil
)
]=])

View File

@ -0,0 +1,273 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
local meths = helpers.meths
local pcall_err = helpers.pcall_err
describe('statuscolumn', function()
local screen
before_each(function()
clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM')
screen = Screen.new()
screen:attach()
end)
it('fails with invalid \'statuscolumn\'', function()
command('set stc=%{v:relnum?v:relnum:(v:lnum==5?invalid:v:lnum)}\\ ')
screen:expect([[
4 aaaaa |
3 aaaaa |
2 aaaaa |
1 aaaaa |
8 ^aaaaa |
1 aaaaa |
2 aaaaa |
3 aaaaa |
4 aaaaa |
5 aaaaa |
6 aaaaa |
7 aaaaa |
8 aaaaa |
|
]])
command('norm 5G')
eq('Vim(redraw):E121: Undefined variable: invalid', pcall_err(command, 'redraw!'))
eq('', eval('&statuscolumn'))
end)
it('widens with irregular \'statuscolumn\' width', function()
command('set stc=%{v:relnum?v:relnum:(v:lnum==5?\'bbbbb\':v:lnum)}')
command('norm 5G | redraw!')
screen:expect([[
1 aaaaa |
bbbbba^eaaa |
1 aaaaa |
2 aaaaa |
3 aaaaa |
4 aaaaa |
5 aaaaa |
6 aaaaa |
7 aaaaa |
8 aaaaa |
9 aaaaa |
10 aaaaa |
11 aaaaa |
|
]])
end)
it('works with \'statuscolumn\'', function()
command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
screen:expect([[
4 aaaaa |
5 aaaaa |
6 aaaaa |
7 aaaaa |
8 ^aaaaa |
9 aaaaa |
10aaaaa |
11aaaaa |
12aaaaa |
13aaaaa |
14aaaaa |
15aaaaa |
16aaaaa |
|
]])
command('set relativenumber')
screen:expect([[
4 4aaaaa |
5 3aaaaa |
6 2aaaaa |
7 1aaaaa |
8 0^aaaaa |
9 1aaaaa |
10 2aaaaa |
11 3aaaaa |
12 4aaaaa |
13 5aaaaa |
14 6aaaaa |
15 7aaaaa |
16 8aaaaa |
|
]])
command('norm 12GH')
screen:expect([[
4 0^aaaaa |
5 1aaaaa |
6 2aaaaa |
7 3aaaaa |
8 4aaaaa |
9 5aaaaa |
10 6aaaaa |
11 7aaaaa |
12 8aaaaa |
13 9aaaaa |
14 10aaaaa |
15 11aaaaa |
16 12aaaaa |
|
]])
end)
it('works with highlighted \'statuscolumn\'', function()
command([[set stc=%#NonText#%{&nu?v:lnum:''}]] ..
[[%=%{&rnu&&(v:lnum%2)?'\ '.v:relnum:''}]] ..
[[%#LineNr#%{&rnu&&!(v:lnum%2)?'\ '.v:relnum:''}│]])
screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue},
[1] = {foreground = Screen.colors.Brown},
})
screen:expect([[
{0:4 }{1:}aaaaa |
{0:5 }{1:}aaaaa |
{0:6 }{1:}aaaaa |
{0:7 }{1:}aaaaa |
{0:8 }{1:}^aaaaa |
{0:9 }{1:}aaaaa |
{0:10}{1:}aaaaa |
{0:11}{1:}aaaaa |
{0:12}{1:}aaaaa |
{0:13}{1:}aaaaa |
{0:14}{1:}aaaaa |
{0:15}{1:}aaaaa |
{0:16}{1:}aaaaa |
|
]])
command('set relativenumber')
screen:expect([[
{0:4 }{1: 4}aaaaa |
{0:5 3}{1:}aaaaa |
{0:6 }{1: 2}aaaaa |
{0:7 1}{1:}aaaaa |
{0:8 }{1: 0}^aaaaa |
{0:9 1}{1:}aaaaa |
{0:10}{1: 2}aaaaa |
{0:11 3}{1:}aaaaa |
{0:12}{1: 4}aaaaa |
{0:13 5}{1:}aaaaa |
{0:14}{1: 6}aaaaa |
{0:15 7}{1:}aaaaa |
{0:16}{1: 8}aaaaa |
|
]])
command('set nonumber')
screen:expect([[
{1:4}aaaaa |
{0:3}{1:}aaaaa |
{1:2}aaaaa |
{0:1}{1:}aaaaa |
{1:0}^aaaaa |
{0:1}{1:}aaaaa |
{1:2}aaaaa |
{0:3}{1:}aaaaa |
{1:4}aaaaa |
{0:5}{1:}aaaaa |
{1:6}aaaaa |
{0:7}{1:}aaaaa |
{1:8}aaaaa |
|
]])
end)
it('works with wrapped lines, signs and folds', function()
command("set stc=%C%s%=%{v:wrap?'':v:lnum}│\\ ")
command("call setline(1,repeat([repeat('aaaaa',10)],16))")
screen:set_default_attr_ids({
[0] = {bold = true, foreground = Screen.colors.Blue},
[1] = {foreground = Screen.colors.Brown},
[2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey},
[3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
})
screen:expect([[
{1: 4 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1: 5 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1: 6 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1: 7 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1: 8 }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1: 9 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }a |
{1:10 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
|
]])
command('set signcolumn=auto:2 foldcolumn=auto')
command('sign define piet1 text=>> texthl=LineNr')
command('sign define piet2 text=>! texthl=NonText')
command('sign place 1 line=4 name=piet1 buffer=1')
command('sign place 2 line=5 name=piet2 buffer=1')
command('sign place 3 line=6 name=piet1 buffer=1')
command('sign place 4 line=6 name=piet2 buffer=1')
screen:expect([[
{1:>> 4 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{0:>!}{1: 5 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{1:>>}{0:>!}{1: 6 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{1: 7 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{1: 8 }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{1: 9 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{1: }aaaaa |
{1: 10 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
|
]])
command('norm zf$')
-- Check that alignment works properly with signs after %=
command("set stc=%C%=%{v:wrap?'':v:lnum}│%s\\ ")
screen:expect([[
{2: }{1: 4>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
{2: }{1: 5}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
{2: }{1: 6>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
{2: }{1: 7 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
{2:+}{1: 8 }{3:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{2: }{1: 9 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
{2: }{1:10 }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{2: }{1: }aaaaaa |
|
]])
end)
it('works with \'statuscolumn\' clicks', function()
command('set mousemodel=extend')
command([[
function! MyClickFunc(minwid, clicks, button, mods)
let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line)
if a:mods !=# ' '
let g:testvar ..= '(' .. a:mods .. ')'
endif
endfunction
set stc=%0@MyClickFunc@%=%l%T
]])
meths.input_mouse('left', 'press', '', 0, 0, 0)
eq('0 1 l 4', eval("g:testvar"))
meths.input_mouse('left', 'press', '', 0, 0, 0)
eq('0 2 l 4', eval("g:testvar"))
meths.input_mouse('left', 'press', '', 0, 0, 0)
eq('0 3 l 4', eval("g:testvar"))
meths.input_mouse('left', 'press', '', 0, 0, 0)
eq('0 4 l 4', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 1 r 7', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 2 r 7', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 3 r 7', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 4 r 7', eval("g:testvar"))
end)
end)

View File

@ -238,6 +238,7 @@ describe('buffer functions', function()
fillchar,
maximum_cell_count,
NULL,
NULL,
NULL)
end