mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat: add support for global statusline
Ref: #9342 Adds the option to have a single global statusline for the current window at the bottom of the screen instead of a statusline at the bottom of every window. Enabled by setting `laststatus = 3`. Due to the fact that statuslines at the bottom of windows are removed when global statusline is enabled, horizontal separators are used instead to separate horizontal splits. The horizontal separator character is configurable through the`horiz` item in `'fillchars'`. Separator connector characters are also used to connect the horizontal and vertical separators together, which are also configurable through the `horizup`, `horizdown`, `vertleft`, `vertright` and `verthoriz` items in `fillchars`. The window separators are highlighted using the `WinSeparator` highlight group, which supersedes `VertSplit` and is linked to `VertSplit` by default in order to maintain backwards compatibility.
This commit is contained in:
parent
046950f630
commit
5ab1229174
@ -175,7 +175,7 @@ o Enable Arabic settings [short-cut]
|
||||
vertical separator like "l" or "𝖨" may be used. It may also be
|
||||
hidden by changing its color to the foreground color: >
|
||||
:set fillchars=vert:l
|
||||
:hi VertSplit ctermbg=White
|
||||
:hi WinSeparator ctermbg=White
|
||||
< Note that this is a workaround, not a proper solution.
|
||||
|
||||
If, on the other hand, you'd like to be verbose and explicit and
|
||||
|
@ -2441,7 +2441,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
item default Used for ~
|
||||
stl:c ' ' or '^' statusline of the current window
|
||||
stlnc:c ' ' or '=' statusline of the non-current windows
|
||||
horiz:c '─' or '-' horizontal separators |:split|
|
||||
horizup:c '┴' or '-' upwards facing horizontal separator
|
||||
horizdown:c '┬' or '-' downwards facing horizontal separator
|
||||
vert:c '│' or '|' vertical separators |:vsplit|
|
||||
vertleft:c '┤' or '|' left facing vertical separator
|
||||
vertright:c '├' or '|' right facing vertical separator
|
||||
verthoriz:c '┼' or '+' overlapping vertical and horizontal
|
||||
separator
|
||||
fold:c '·' or '-' filling 'foldtext'
|
||||
foldopen:c '-' mark the beginning of a fold
|
||||
foldclose:c '+' show a closed fold
|
||||
@ -2454,8 +2461,13 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
"stlnc" the space will be used when there is highlighting, '^' or '='
|
||||
otherwise.
|
||||
|
||||
If 'ambiwidth' is "double" then "vert", "foldsep" and "fold" default to
|
||||
single-byte alternatives.
|
||||
Note that "horiz", "horizup", "horizdown", "vertleft", "vertright" and
|
||||
"verthoriz" are only used when 'laststatus' is 3, since only vertical
|
||||
window separators are used otherwise.
|
||||
|
||||
If 'ambiwidth' is "double" then "horiz", "horizup", "horizdown",
|
||||
"vert", "vertleft", "vertright", "verthoriz", "foldsep" and "fold"
|
||||
default to single-byte alternatives.
|
||||
|
||||
Example: >
|
||||
:set fillchars=stl:^,stlnc:=,vert:│,fold:·,diff:-
|
||||
@ -2469,7 +2481,13 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
item highlight group ~
|
||||
stl:c StatusLine |hl-StatusLine|
|
||||
stlnc:c StatusLineNC |hl-StatusLineNC|
|
||||
vert:c VertSplit |hl-VertSplit|
|
||||
horiz:c WinSeparator |hl-WinSeparator|
|
||||
horizup:c WinSeparator |hl-WinSeparator|
|
||||
horizdown:c WinSeparator |hl-WinSeparator|
|
||||
vert:c WinSeparator |hl-WinSeparator|
|
||||
vertleft:c WinSeparator |hl-WinSeparator|
|
||||
vertright:c WinSeparator |hl-WinSeparator|
|
||||
verthoriz:c WinSeparator |hl-WinSeparator|
|
||||
fold:c Folded |hl-Folded|
|
||||
diff:c DiffDelete |hl-DiffDelete|
|
||||
eob:c EndOfBuffer |hl-EndOfBuffer|
|
||||
@ -3652,6 +3670,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
0: never
|
||||
1: only if there are at least two windows
|
||||
2: always
|
||||
3: have a global statusline at the bottom instead of one for
|
||||
each window
|
||||
The screen looks nicer with a status line if you have several
|
||||
windows, but it takes another screen line. |status-line|
|
||||
|
||||
@ -5929,7 +5949,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
empty to avoid further errors. Otherwise screen updating would loop.
|
||||
|
||||
Note that the only effect of 'ruler' when this option is set (and
|
||||
'laststatus' is 2) is controlling the output of |CTRL-G|.
|
||||
'laststatus' is 2 or 3) is controlling the output of |CTRL-G|.
|
||||
|
||||
field meaning ~
|
||||
- Left justify the item. The default is right justified
|
||||
|
@ -5105,8 +5105,8 @@ TermCursor cursor in a focused terminal
|
||||
TermCursorNC cursor in an unfocused terminal
|
||||
*hl-ErrorMsg*
|
||||
ErrorMsg error messages on the command line
|
||||
*hl-VertSplit*
|
||||
VertSplit the column separating vertically split windows
|
||||
*hl-WinSeparator*
|
||||
WinSeparator separators between window splits
|
||||
*hl-Folded*
|
||||
Folded line used for closed folds
|
||||
*hl-FoldColumn*
|
||||
|
@ -482,6 +482,8 @@ statusline:
|
||||
0 never
|
||||
1 only when there are split windows (the default)
|
||||
2 always
|
||||
3 have a global statusline at the bottom instead of one for each
|
||||
window
|
||||
|
||||
Many commands that edit another file have a variant that splits the window.
|
||||
For Command-line commands this is done by prepending an "s". For example:
|
||||
|
@ -211,6 +211,7 @@ Highlight groups:
|
||||
|hl-Substitute|
|
||||
|hl-TermCursor|
|
||||
|hl-TermCursorNC|
|
||||
|hl-WinSeparator| highlights window separators
|
||||
|hl-Whitespace| highlights 'listchars' whitespace
|
||||
|
||||
Input/Mappings:
|
||||
@ -227,9 +228,11 @@ Options:
|
||||
'cpoptions' flags: |cpo-_|
|
||||
'display' flags: "msgsep" minimizes scrolling when showing messages
|
||||
'guicursor' works in the terminal
|
||||
'fillchars' flags: "msgsep" (see 'display')
|
||||
'fillchars' flags: "msgsep" (see 'display'), "horiz", "horizup",
|
||||
"horizdown", "vertleft", "vertright", "verthoriz"
|
||||
'foldcolumn' supports up to 9 dynamic/fixed columns
|
||||
'inccommand' shows interactive results for |:substitute|-like commands
|
||||
'laststatus' global statusline support
|
||||
'pumblend' pseudo-transparent popupmenu
|
||||
'scrollback'
|
||||
'signcolumn' supports up to 9 dynamic/fixed columns
|
||||
@ -348,6 +351,7 @@ Highlight groups:
|
||||
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
|
||||
groups
|
||||
|hl-CursorLine| is low-priority unless foreground color is set
|
||||
*hl-VertSplit* superseded by |hl-WinSeparator|
|
||||
|
||||
Macro/|recording| behavior
|
||||
Replay of a macro recorded during :lmap produces the same actions as when it
|
||||
|
@ -104,6 +104,8 @@ when the last window also has a status line:
|
||||
'laststatus' = 0 never a status line
|
||||
'laststatus' = 1 status line if there is more than one window
|
||||
'laststatus' = 2 always a status line
|
||||
'laststatus' = 3 have a global statusline at the bottom instead
|
||||
of one for each window
|
||||
|
||||
You can change the contents of the status line with the 'statusline' option.
|
||||
This option can be local to the window, so that you can have a different
|
||||
|
@ -2319,7 +2319,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
|
||||
|
||||
maxwidth = (int)opts->maxwidth.data.integer;
|
||||
} else {
|
||||
maxwidth = use_tabline ? Columns : wp->w_width;
|
||||
maxwidth = (use_tabline || global_stl_height() > 0) ? Columns : wp->w_width;
|
||||
}
|
||||
|
||||
char buf[MAXPATHL];
|
||||
|
@ -131,7 +131,7 @@
|
||||
/// An empty string can be used to turn off a specific border, for instance,
|
||||
/// [ "", "", "", ">", "", "", "", "<" ]
|
||||
/// will only make vertical borders but not horizontal ones.
|
||||
/// By default, `FloatBorder` highlight is used, which links to `VertSplit`
|
||||
/// By default, `FloatBorder` highlight is used, which links to `WinSeparator`
|
||||
/// when not defined. It could also be specified by character:
|
||||
/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ].
|
||||
/// - noautocmd: If true then no buffer-related autocommand events such as
|
||||
|
@ -5006,8 +5006,8 @@ void ex_buffer_all(exarg_T *eap)
|
||||
wpnext = wp->w_next;
|
||||
if ((wp->w_buffer->b_nwindows > 1
|
||||
|| ((cmdmod.split & WSP_VERT)
|
||||
? wp->w_height + wp->w_status_height < Rows - p_ch
|
||||
- tabline_height()
|
||||
? wp->w_height + wp->w_hsep_height + wp->w_status_height < Rows - p_ch
|
||||
- tabline_height() - global_stl_height()
|
||||
: wp->w_width != Columns)
|
||||
|| (had_tab > 0 && wp != firstwin))
|
||||
&& !ONE_WINDOW
|
||||
|
@ -1227,7 +1227,13 @@ struct window_S {
|
||||
struct {
|
||||
int stl;
|
||||
int stlnc;
|
||||
int horiz;
|
||||
int horizup;
|
||||
int horizdown;
|
||||
int vert;
|
||||
int vertleft;
|
||||
int vertright;
|
||||
int verthoriz;
|
||||
int fold;
|
||||
int foldopen; ///< when fold is open
|
||||
int foldclosed; ///< when fold is closed
|
||||
@ -1273,7 +1279,8 @@ struct window_S {
|
||||
int w_status_height; // number of status lines (0 or 1)
|
||||
int w_wincol; // Leftmost column of window in screen.
|
||||
int w_width; // Width of window, excluding separation.
|
||||
int w_vsep_width; // Number of separator columns (0 or 1).
|
||||
int w_hsep_height; // Number of horizontal separator rows (0 or 1)
|
||||
int w_vsep_width; // Number of vertical separator columns (0 or 1).
|
||||
pos_save_T w_save_cursor; // backup of cursor pos and topline
|
||||
|
||||
// inner size of window, which can be overridden by external UI
|
||||
|
@ -3886,7 +3886,7 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||
|
||||
wp = mouse_find_win(&grid, &row, &col);
|
||||
if (wp != NULL) {
|
||||
int height = wp->w_height + wp->w_status_height;
|
||||
int height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
|
||||
// The height is adjusted by 1 when there is a bottom border. This is not
|
||||
// necessary for a top border since `row` starts at -1 in that case.
|
||||
if (row < height + wp->w_border_adj[2]) {
|
||||
|
@ -632,7 +632,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
|
||||
|
||||
validate_cursor();
|
||||
// May redraw the status line to show the cursor position.
|
||||
if (p_ru && curwin->w_status_height > 0) {
|
||||
if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) {
|
||||
curwin->w_redr_status = true;
|
||||
}
|
||||
|
||||
@ -3631,7 +3631,7 @@ void compute_cmdrow(void)
|
||||
} else {
|
||||
win_T *wp = lastwin_nofloating();
|
||||
cmdline_row = wp->w_winrow + wp->w_height
|
||||
+ wp->w_status_height;
|
||||
+ wp->w_hsep_height + wp->w_status_height + global_stl_height();
|
||||
}
|
||||
lines_left = cmdline_row;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin)
|
||||
n++;
|
||||
|
||||
// restore height when not full height
|
||||
if (wp->w_height + wp->w_status_height < topframe->fr_height
|
||||
if (wp->w_height + wp->w_hsep_height + wp->w_status_height < topframe->fr_height
|
||||
&& (fprintf(fd,
|
||||
"exe '%dresize ' . ((&lines * %" PRId64
|
||||
" + %" PRId64 ") / %" PRId64 ")\n",
|
||||
|
@ -70,7 +70,8 @@ typedef enum {
|
||||
HLF_R, // return to continue message and yes/no questions
|
||||
HLF_S, // status lines
|
||||
HLF_SNC, // status lines of not-current windows
|
||||
HLF_C, // column to separate vertically split windows
|
||||
HLF_C, // window split separators
|
||||
HLF_VSP, // VertSplit
|
||||
HLF_T, // Titles for output from ":set all", ":autocmd" etc.
|
||||
HLF_V, // Visual mode
|
||||
HLF_VNC, // Visual mode, autoselecting and not clipboard owner
|
||||
@ -129,10 +130,11 @@ EXTERN const char *hlf_names[] INIT(= {
|
||||
[HLF_R] = "Question",
|
||||
[HLF_S] = "StatusLine",
|
||||
[HLF_SNC] = "StatusLineNC",
|
||||
[HLF_C] = "VertSplit",
|
||||
[HLF_C] = "WinSeparator",
|
||||
[HLF_T] = "Title",
|
||||
[HLF_V] = "Visual",
|
||||
[HLF_VNC] = "VisualNC",
|
||||
[HLF_VSP] = "VertSplit",
|
||||
[HLF_W] = "WarningMsg",
|
||||
[HLF_WM] = "WildMenu",
|
||||
[HLF_FL] = "Folded",
|
||||
|
@ -2910,7 +2910,7 @@ ambw_end:
|
||||
|| check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) {
|
||||
errmsg = e_invarg;
|
||||
} else {
|
||||
if (curwin->w_status_height) {
|
||||
if (curwin->w_status_height || global_stl_height()) {
|
||||
curwin->w_redr_status = true;
|
||||
redraw_later(curwin, VALID);
|
||||
}
|
||||
@ -3553,16 +3553,22 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
|
||||
struct chars_tab *tab;
|
||||
|
||||
struct chars_tab fcs_tab[] = {
|
||||
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
|
||||
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
|
||||
{ &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
|
||||
{ &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
|
||||
{ &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
|
||||
{ &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
|
||||
{ &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │
|
||||
{ &wp->w_p_fcs_chars.diff, "diff", '-' },
|
||||
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
|
||||
{ &wp->w_p_fcs_chars.eob, "eob", '~' },
|
||||
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
|
||||
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
|
||||
{ &wp->w_p_fcs_chars.horiz, "horiz", 9472 }, // ─
|
||||
{ &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // ┴
|
||||
{ &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬
|
||||
{ &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
|
||||
{ &wp->w_p_fcs_chars.vertleft, "vertleft", 9508 }, // ┤
|
||||
{ &wp->w_p_fcs_chars.vertright, "vertright", 9500 }, // ├
|
||||
{ &wp->w_p_fcs_chars.verthoriz, "verthoriz", 9532 }, // ┼
|
||||
{ &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
|
||||
{ &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
|
||||
{ &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
|
||||
{ &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │
|
||||
{ &wp->w_p_fcs_chars.diff, "diff", '-' },
|
||||
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
|
||||
{ &wp->w_p_fcs_chars.eob, "eob", '~' },
|
||||
};
|
||||
struct chars_tab lcs_tab[] = {
|
||||
{ &wp->w_p_lcs_chars.eol, "eol", NUL },
|
||||
@ -3589,15 +3595,17 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
|
||||
varp = &p_fcs;
|
||||
}
|
||||
if (*p_ambw == 'd') {
|
||||
// XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is
|
||||
// forbidden (TUI limitation?). Set old defaults.
|
||||
fcs_tab[2].def = '|';
|
||||
fcs_tab[6].def = '|';
|
||||
fcs_tab[3].def = '-';
|
||||
} else {
|
||||
fcs_tab[2].def = 9474; // │
|
||||
fcs_tab[6].def = 9474; // │
|
||||
fcs_tab[3].def = 183; // ·
|
||||
// XXX: If ambiwidth=double then some characters take 2 columns,
|
||||
// which is forbidden (TUI limitation?). Set old defaults.
|
||||
fcs_tab[2].def = '-';
|
||||
fcs_tab[3].def = '-';
|
||||
fcs_tab[4].def = '-';
|
||||
fcs_tab[5].def = '|';
|
||||
fcs_tab[6].def = '|';
|
||||
fcs_tab[7].def = '|';
|
||||
fcs_tab[8].def = '+';
|
||||
fcs_tab[9].def = '-';
|
||||
fcs_tab[12].def = '|';
|
||||
}
|
||||
}
|
||||
|
||||
@ -4474,6 +4482,20 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
|
||||
// 'winminwidth'
|
||||
win_setminwidth();
|
||||
} else if (pp == &p_ls) {
|
||||
// When switching to global statusline, decrease topframe height
|
||||
// Also clear the cmdline to remove the ruler if there is one
|
||||
if (value == 3 && old_value != 3) {
|
||||
frame_new_height(topframe, topframe->fr_height - STATUS_HEIGHT, false, false);
|
||||
(void)win_comp_pos();
|
||||
clear_cmdline = true;
|
||||
}
|
||||
// When switching from global statusline, increase height of topframe by STATUS_HEIGHT
|
||||
// in order to to re-add the space that was previously taken by the global statusline
|
||||
if (old_value == 3 && value != 3) {
|
||||
frame_new_height(topframe, topframe->fr_height + STATUS_HEIGHT, false, false);
|
||||
(void)win_comp_pos();
|
||||
}
|
||||
|
||||
last_status(false); // (re)set last window status line.
|
||||
} else if (pp == &p_stal) {
|
||||
// (re)set tab page line
|
||||
@ -5645,7 +5667,7 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value)
|
||||
|
||||
void comp_col(void)
|
||||
{
|
||||
int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
|
||||
int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
|
||||
|
||||
sc_col = 0;
|
||||
ru_col = 0;
|
||||
|
@ -3597,7 +3597,7 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp
|
||||
win_setwidth(sz);
|
||||
}
|
||||
} else if (sz != win->w_height
|
||||
&& (win->w_height + win->w_status_height + tabline_height()
|
||||
&& (win->w_height + win->w_hsep_height + win->w_status_height + tabline_height()
|
||||
< cmdline_row)) {
|
||||
win_setheight(sz);
|
||||
}
|
||||
|
@ -317,7 +317,8 @@ void update_curbuf(int type)
|
||||
void redraw_buf_status_later(buf_T *buf)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_buffer == buf && wp->w_status_height) {
|
||||
if (wp->w_buffer == buf
|
||||
&& (wp->w_status_height || (wp == curwin && global_stl_height()))) {
|
||||
wp->w_redr_status = true;
|
||||
if (must_redraw < VALID) {
|
||||
must_redraw = VALID;
|
||||
@ -335,6 +336,7 @@ void redraw_buf_status_later(buf_T *buf)
|
||||
int update_screen(int type)
|
||||
{
|
||||
static bool did_intro = false;
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
|
||||
// Don't do anything if the screen structures are (not yet) valid.
|
||||
// A VimResized autocmd can invoke redrawing in the middle of a resize,
|
||||
@ -417,10 +419,13 @@ int update_screen(int type)
|
||||
if (W_ENDROW(wp) > valid) {
|
||||
wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID);
|
||||
}
|
||||
if (W_ENDROW(wp) + wp->w_status_height > valid) {
|
||||
if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) {
|
||||
wp->w_redr_status = true;
|
||||
}
|
||||
}
|
||||
if (is_stl_global && Rows - p_ch - 1 > valid) {
|
||||
curwin->w_redr_status = true;
|
||||
}
|
||||
}
|
||||
msg_grid_set_pos(Rows-p_ch, false);
|
||||
msg_grid_invalid = false;
|
||||
@ -442,13 +447,15 @@ int update_screen(int type)
|
||||
wp->w_redr_type = REDRAW_TOP;
|
||||
} else {
|
||||
wp->w_redr_type = NOT_VALID;
|
||||
if (W_ENDROW(wp) + wp->w_status_height
|
||||
<= msg_scrolled) {
|
||||
wp->w_redr_status = TRUE;
|
||||
if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) {
|
||||
wp->w_redr_status = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) {
|
||||
curwin->w_redr_status = true;
|
||||
}
|
||||
redraw_cmdline = true;
|
||||
redraw_tabline = true;
|
||||
}
|
||||
@ -803,8 +810,11 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
wp->w_lines_valid = 0;
|
||||
}
|
||||
|
||||
// Window is zero-height: nothing to draw.
|
||||
// Window is zero-height: Only need to draw the separator
|
||||
if (wp->w_grid.Rows == 0) {
|
||||
// draw the horizontal separator below this window
|
||||
draw_hsep_win(wp);
|
||||
draw_sep_connectors_win(wp);
|
||||
wp->w_redr_type = 0;
|
||||
return;
|
||||
}
|
||||
@ -812,7 +822,8 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
// Window is zero-width: Only need to draw the separator.
|
||||
if (wp->w_grid.Columns == 0) {
|
||||
// draw the vertical separator right of this window
|
||||
draw_vsep_win(wp, 0);
|
||||
draw_vsep_win(wp);
|
||||
draw_sep_connectors_win(wp);
|
||||
wp->w_redr_type = 0;
|
||||
return;
|
||||
}
|
||||
@ -1747,7 +1758,9 @@ static void win_update(win_T *wp, Providers *providers)
|
||||
kvi_destroy(line_providers);
|
||||
|
||||
if (wp->w_redr_type >= REDRAW_TOP) {
|
||||
draw_vsep_win(wp, 0);
|
||||
draw_vsep_win(wp);
|
||||
draw_hsep_win(wp);
|
||||
draw_sep_connectors_win(wp);
|
||||
}
|
||||
syn_set_timeout(NULL);
|
||||
|
||||
@ -4958,10 +4971,15 @@ void rl_mirror(char_u *str)
|
||||
*/
|
||||
void status_redraw_all(void)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_status_height) {
|
||||
wp->w_redr_status = true;
|
||||
redraw_later(wp, VALID);
|
||||
if (global_stl_height()) {
|
||||
curwin->w_redr_status = true;
|
||||
redraw_later(curwin, VALID);
|
||||
} else {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_status_height) {
|
||||
wp->w_redr_status = true;
|
||||
redraw_later(wp, VALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4975,10 +4993,15 @@ void status_redraw_curbuf(void)
|
||||
/// Marks all status lines of the specified buffer for redraw.
|
||||
void status_redraw_buf(buf_T *buf)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_status_height != 0 && wp->w_buffer == buf) {
|
||||
wp->w_redr_status = true;
|
||||
redraw_later(wp, VALID);
|
||||
if (global_stl_height() != 0 && curwin->w_buffer == buf) {
|
||||
curwin->w_redr_status = true;
|
||||
redraw_later(curwin, VALID);
|
||||
} else {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_status_height != 0 && wp->w_buffer == buf) {
|
||||
wp->w_redr_status = true;
|
||||
redraw_later(wp, VALID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5020,10 +5043,8 @@ void win_redraw_last_status(const frame_T *frp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the verticap separator right of window "wp" starting with line "row".
|
||||
*/
|
||||
static void draw_vsep_win(win_T *wp, int row)
|
||||
/// Draw the vertical separator right of window "wp"
|
||||
static void draw_vsep_win(win_T *wp)
|
||||
{
|
||||
int hl;
|
||||
int c;
|
||||
@ -5031,15 +5052,97 @@ static void draw_vsep_win(win_T *wp, int row)
|
||||
if (wp->w_vsep_width) {
|
||||
// draw the vertical separator right of this window
|
||||
c = fillchar_vsep(wp, &hl);
|
||||
grid_fill(&default_grid, wp->w_winrow + row, W_ENDROW(wp),
|
||||
grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp),
|
||||
W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw the horizontal separator below window "wp"
|
||||
static void draw_hsep_win(win_T *wp)
|
||||
{
|
||||
int hl;
|
||||
int c;
|
||||
|
||||
/*
|
||||
* Get the length of an item as it will be shown in the status line.
|
||||
*/
|
||||
if (wp->w_hsep_height) {
|
||||
// draw the horizontal separator below this window
|
||||
c = fillchar_hsep(wp, &hl);
|
||||
grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1,
|
||||
wp->w_wincol, W_ENDCOL(wp), c, c, hl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the separator connector for specified window corner of window "wp"
|
||||
static int get_corner_sep_connector(win_T *wp, WindowCorner corner)
|
||||
{
|
||||
// It's impossible for windows to be connected neither vertically nor horizontally
|
||||
// So if they're not vertically connected, assume they're horizontally connected
|
||||
if (vsep_connected(wp, corner)) {
|
||||
if (hsep_connected(wp, corner)) {
|
||||
return wp->w_p_fcs_chars.verthoriz;
|
||||
} else if (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) {
|
||||
return wp->w_p_fcs_chars.vertright;
|
||||
} else {
|
||||
return wp->w_p_fcs_chars.vertleft;
|
||||
}
|
||||
} else if (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) {
|
||||
return wp->w_p_fcs_chars.horizdown;
|
||||
} else {
|
||||
return wp->w_p_fcs_chars.horizup;
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw seperator connecting characters on the corners of window "wp"
|
||||
static void draw_sep_connectors_win(win_T *wp)
|
||||
{
|
||||
// Don't draw separator connectors unless global statusline is enabled and the window has
|
||||
// either a horizontal or vertical separator
|
||||
if (global_stl_height() == 0 || !(wp->w_hsep_height == 1 || wp->w_vsep_width == 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int hl = win_hl_attr(wp, HLF_C);
|
||||
|
||||
// Determine which edges of the screen the window is located on so we can avoid drawing separators
|
||||
// on corners contained in those edges
|
||||
bool win_at_top;
|
||||
bool win_at_bottom = wp->w_hsep_height == 0;
|
||||
bool win_at_left;
|
||||
bool win_at_right = wp->w_vsep_width == 0;
|
||||
frame_T *frp;
|
||||
|
||||
for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
|
||||
if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
win_at_top = frp->fr_parent == NULL;
|
||||
for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
|
||||
if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
win_at_left = frp->fr_parent == NULL;
|
||||
|
||||
// Draw the appropriate separator connector in every corner where drawing them is necessary
|
||||
if (!(win_at_top || win_at_left)) {
|
||||
grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_LEFT),
|
||||
wp->w_winrow - 1, wp->w_wincol - 1, hl);
|
||||
}
|
||||
if (!(win_at_top || win_at_right)) {
|
||||
grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_RIGHT),
|
||||
wp->w_winrow - 1, W_ENDCOL(wp), hl);
|
||||
}
|
||||
if (!(win_at_bottom || win_at_left)) {
|
||||
grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_LEFT),
|
||||
W_ENDROW(wp), wp->w_wincol - 1, hl);
|
||||
}
|
||||
if (!(win_at_bottom || win_at_right)) {
|
||||
grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_RIGHT),
|
||||
W_ENDROW(wp), W_ENDCOL(wp), hl);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the length of an item as it will be shown in the status line.
|
||||
static int status_match_len(expand_T *xp, char_u *s)
|
||||
{
|
||||
int len = 0;
|
||||
@ -5240,7 +5343,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
|
||||
// Create status line if needed by setting 'laststatus' to 2.
|
||||
// Set 'winminheight' to zero to avoid that the window is
|
||||
// resized.
|
||||
if (lastwin->w_status_height == 0) {
|
||||
if (lastwin->w_status_height == 0 && global_stl_height() == 0) {
|
||||
save_p_ls = p_ls;
|
||||
save_p_wmh = p_wmh;
|
||||
p_ls = 2;
|
||||
@ -5276,12 +5379,15 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
|
||||
static void win_redr_status(win_T *wp)
|
||||
{
|
||||
int row;
|
||||
int col;
|
||||
char_u *p;
|
||||
int len;
|
||||
int fillchar;
|
||||
int attr;
|
||||
int width;
|
||||
int this_ru_col;
|
||||
static int busy = FALSE;
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
static int busy = false;
|
||||
|
||||
// May get here recursively when 'statusline' (indirectly)
|
||||
// invokes ":redrawstatus". Simply ignore the call then.
|
||||
@ -5292,9 +5398,9 @@ static void win_redr_status(win_T *wp)
|
||||
}
|
||||
busy = true;
|
||||
|
||||
wp->w_redr_status = FALSE;
|
||||
if (wp->w_status_height == 0) {
|
||||
// no status line, can only be last window
|
||||
wp->w_redr_status = false;
|
||||
if (wp->w_status_height == 0 && !(is_stl_global && wp == curwin)) {
|
||||
// no status line, either global statusline is enabled or the window is a last window
|
||||
redraw_cmdline = true;
|
||||
} else if (!redrawing()) {
|
||||
// Don't redraw right now, do it later. Don't update status line when
|
||||
@ -5305,6 +5411,7 @@ static void win_redr_status(win_T *wp)
|
||||
redraw_custom_statusline(wp);
|
||||
} else {
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
width = is_stl_global ? Columns : wp->w_width;
|
||||
|
||||
get_trans_bufname(wp->w_buffer);
|
||||
p = NameBuff;
|
||||
@ -5333,9 +5440,9 @@ static void win_redr_status(win_T *wp)
|
||||
// len += (int)STRLEN(p + len); // dead assignment
|
||||
}
|
||||
|
||||
this_ru_col = ru_col - (Columns - wp->w_width);
|
||||
if (this_ru_col < (wp->w_width + 1) / 2) {
|
||||
this_ru_col = (wp->w_width + 1) / 2;
|
||||
this_ru_col = ru_col - (Columns - width);
|
||||
if (this_ru_col < (width + 1) / 2) {
|
||||
this_ru_col = (width + 1) / 2;
|
||||
}
|
||||
if (this_ru_col <= 1) {
|
||||
p = (char_u *)"<"; // No room for file name!
|
||||
@ -5360,10 +5467,11 @@ static void win_redr_status(win_T *wp)
|
||||
}
|
||||
}
|
||||
|
||||
row = W_ENDROW(wp);
|
||||
grid_puts(&default_grid, p, row, wp->w_wincol, attr);
|
||||
grid_fill(&default_grid, row, row + 1, len + wp->w_wincol,
|
||||
this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
|
||||
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
|
||||
col = is_stl_global ? 0 : wp->w_wincol;
|
||||
grid_puts(&default_grid, p, row, col, attr);
|
||||
grid_fill(&default_grid, row, row + 1, len + col,
|
||||
this_ru_col + col, fillchar, fillchar, attr);
|
||||
|
||||
if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
|
||||
&& this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
|
||||
@ -5442,6 +5550,76 @@ bool stl_connected(win_T *wp)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if horizontal separator of window "wp" at specified window corner is connected to the
|
||||
/// horizontal separator of another window
|
||||
/// Assumes global statusline is enabled
|
||||
static bool hsep_connected(win_T *wp, WindowCorner corner)
|
||||
{
|
||||
bool before = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT);
|
||||
int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT)
|
||||
? wp->w_winrow - 1 : W_ENDROW(wp);
|
||||
frame_T *fr = wp->w_frame;
|
||||
|
||||
while (fr->fr_parent != NULL) {
|
||||
if (fr->fr_parent->fr_layout == FR_ROW && (before ? fr->fr_prev : fr->fr_next) != NULL) {
|
||||
fr = before ? fr->fr_prev : fr->fr_next;
|
||||
break;
|
||||
}
|
||||
fr = fr->fr_parent;
|
||||
}
|
||||
if (fr->fr_parent == NULL) {
|
||||
return false;
|
||||
}
|
||||
while (fr->fr_layout != FR_LEAF) {
|
||||
fr = fr->fr_child;
|
||||
if (fr->fr_parent->fr_layout == FR_ROW && before) {
|
||||
while (fr->fr_next != NULL) {
|
||||
fr = fr->fr_next;
|
||||
}
|
||||
} else {
|
||||
while (fr->fr_next != NULL && frame2win(fr)->w_winrow + fr->fr_height < sep_row) {
|
||||
fr = fr->fr_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sep_row == fr->fr_win->w_winrow - 1 || sep_row == W_ENDROW(fr->fr_win));
|
||||
}
|
||||
|
||||
/// Check if vertical separator of window "wp" at specified window corner is connected to the
|
||||
/// vertical separator of another window
|
||||
static bool vsep_connected(win_T *wp, WindowCorner corner)
|
||||
{
|
||||
bool before = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT);
|
||||
int sep_col = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT)
|
||||
? wp->w_wincol - 1 : W_ENDCOL(wp);
|
||||
frame_T *fr = wp->w_frame;
|
||||
|
||||
while (fr->fr_parent != NULL) {
|
||||
if (fr->fr_parent->fr_layout == FR_COL && (before ? fr->fr_prev : fr->fr_next) != NULL) {
|
||||
fr = before ? fr->fr_prev : fr->fr_next;
|
||||
break;
|
||||
}
|
||||
fr = fr->fr_parent;
|
||||
}
|
||||
if (fr->fr_parent == NULL) {
|
||||
return false;
|
||||
}
|
||||
while (fr->fr_layout != FR_LEAF) {
|
||||
fr = fr->fr_child;
|
||||
if (fr->fr_parent->fr_layout == FR_COL && before) {
|
||||
while (fr->fr_next != NULL) {
|
||||
fr = fr->fr_next;
|
||||
}
|
||||
} else {
|
||||
while (fr->fr_next != NULL && frame2win(fr)->w_wincol + fr->fr_width < sep_col) {
|
||||
fr = fr->fr_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (sep_col == fr->fr_win->w_wincol - 1 || sep_col == W_ENDCOL(fr->fr_win));
|
||||
}
|
||||
|
||||
/// Get the value to show for the language mappings, active 'keymap'.
|
||||
///
|
||||
@ -5508,6 +5686,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
|
||||
int use_sandbox = false;
|
||||
win_T *ewp;
|
||||
int p_crb_save;
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
|
||||
ScreenGrid *grid = &default_grid;
|
||||
|
||||
@ -5529,9 +5708,9 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
|
||||
maxwidth = Columns;
|
||||
use_sandbox = was_set_insecurely(wp, "tabline", 0);
|
||||
} else {
|
||||
row = W_ENDROW(wp);
|
||||
row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
maxwidth = wp->w_width;
|
||||
maxwidth = is_stl_global ? Columns : wp->w_width;
|
||||
|
||||
if (draw_ruler) {
|
||||
stl = p_ruf;
|
||||
@ -5549,12 +5728,12 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
|
||||
stl = p_ruf;
|
||||
}
|
||||
}
|
||||
col = ru_col - (Columns - wp->w_width);
|
||||
if (col < (wp->w_width + 1) / 2) {
|
||||
col = (wp->w_width + 1) / 2;
|
||||
col = ru_col - (Columns - maxwidth);
|
||||
if (col < (maxwidth + 1) / 2) {
|
||||
col = (maxwidth + 1) / 2;
|
||||
}
|
||||
maxwidth = wp->w_width - col;
|
||||
if (!wp->w_status_height) {
|
||||
maxwidth = maxwidth - col;
|
||||
if (!wp->w_status_height && !is_stl_global) {
|
||||
grid = &msg_grid_adj;
|
||||
row = Rows - 1;
|
||||
maxwidth--; // writing in last column may cause scrolling
|
||||
@ -5572,7 +5751,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
|
||||
use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
|
||||
}
|
||||
|
||||
col += wp->w_wincol;
|
||||
col += is_stl_global ? 0 : wp->w_wincol;
|
||||
}
|
||||
|
||||
if (maxwidth <= 0) {
|
||||
@ -7154,10 +7333,10 @@ int showmode(void)
|
||||
clear_showcmd();
|
||||
}
|
||||
|
||||
// If the last window has no status line, the ruler is after the mode
|
||||
// message and must be redrawn
|
||||
// If the last window has no status line and global statusline is disabled,
|
||||
// the ruler is after the mode message and must be redrawn
|
||||
win_T *last = lastwin_nofloating();
|
||||
if (redrawing() && last->w_status_height == 0) {
|
||||
if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
|
||||
win_redr_ruler(last, true);
|
||||
}
|
||||
redraw_cmdline = false;
|
||||
@ -7472,16 +7651,22 @@ int fillchar_status(int *attr, win_T *wp)
|
||||
return '=';
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the character to use in a separator between vertically split windows.
|
||||
* Get its attributes in "*attr".
|
||||
*/
|
||||
/// Get the character to use in a separator between vertically split windows.
|
||||
/// Get its attributes in "*attr".
|
||||
static int fillchar_vsep(win_T *wp, int *attr)
|
||||
{
|
||||
*attr = win_hl_attr(wp, HLF_C);
|
||||
return wp->w_p_fcs_chars.vert;
|
||||
}
|
||||
|
||||
/// Get the character to use in a separator between horizontally split windows.
|
||||
/// Get its attributes in "*attr".
|
||||
static int fillchar_hsep(win_T *wp, int *attr)
|
||||
{
|
||||
*attr = win_hl_attr(wp, HLF_C);
|
||||
return wp->w_p_fcs_chars.horiz;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if redrawing should currently be done.
|
||||
*/
|
||||
@ -7507,7 +7692,8 @@ void showruler(bool always)
|
||||
if (!always && !redrawing()) {
|
||||
return;
|
||||
}
|
||||
if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) {
|
||||
if ((*p_stl != NUL || *curwin->w_p_stl != NUL)
|
||||
&& (curwin->w_status_height || global_stl_height())) {
|
||||
redraw_custom_statusline(curwin);
|
||||
} else {
|
||||
win_redr_ruler(curwin, always);
|
||||
@ -7526,6 +7712,7 @@ void showruler(bool always)
|
||||
|
||||
static void win_redr_ruler(win_T *wp, bool always)
|
||||
{
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
static bool did_show_ext_ruler = false;
|
||||
|
||||
// If 'ruler' off or redrawing disabled, don't do anything
|
||||
@ -7543,7 +7730,7 @@ static void win_redr_ruler(win_T *wp, bool always)
|
||||
|
||||
// Don't draw the ruler while doing insert-completion, it might overwrite
|
||||
// the (long) mode message.
|
||||
if (wp == lastwin && lastwin->w_status_height == 0) {
|
||||
if (wp == lastwin && lastwin->w_status_height == 0 && !is_stl_global) {
|
||||
if (edit_submode != NULL) {
|
||||
return;
|
||||
}
|
||||
@ -7598,6 +7785,12 @@ static void win_redr_ruler(win_T *wp, bool always)
|
||||
off = wp->w_wincol;
|
||||
width = wp->w_width;
|
||||
part_of_status = true;
|
||||
} else if (is_stl_global) {
|
||||
row = Rows - p_ch - 1;
|
||||
fillchar = fillchar_status(&attr, wp);
|
||||
off = 0;
|
||||
width = Columns;
|
||||
part_of_status = true;
|
||||
} else {
|
||||
row = Rows - 1;
|
||||
fillchar = ' ';
|
||||
@ -7637,7 +7830,7 @@ static void win_redr_ruler(win_T *wp, bool always)
|
||||
int i = (int)STRLEN(buffer);
|
||||
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
|
||||
int o = i + vim_strsize(buffer + i + 1);
|
||||
if (wp->w_status_height == 0) { // can't use last char of screen
|
||||
if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
|
||||
o++;
|
||||
}
|
||||
int this_ru_col = ru_col - (Columns - width);
|
||||
|
@ -21,6 +21,14 @@
|
||||
#define NOT_VALID 40 // buffer needs complete redraw
|
||||
#define CLEAR 50 // screen messed up, clear it
|
||||
|
||||
/// corner value flags for hsep_connected and vsep_connected
|
||||
typedef enum {
|
||||
WC_TOP_LEFT = 0,
|
||||
WC_TOP_RIGHT,
|
||||
WC_BOTTOM_LEFT,
|
||||
WC_BOTTOM_RIGHT
|
||||
} WindowCorner;
|
||||
|
||||
/// By default, all widows are draw on a single rectangular grid, represented by
|
||||
/// this ScreenGrid instance. In multigrid mode each window will have its own
|
||||
/// grid, then this is only used for global screen elements that hasn't been
|
||||
|
@ -6173,6 +6173,7 @@ static const char *highlight_init_both[] = {
|
||||
"TermCursor cterm=reverse gui=reverse",
|
||||
"VertSplit cterm=reverse gui=reverse",
|
||||
"WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
|
||||
"default link WinSeparator VertSplit",
|
||||
"default link EndOfBuffer NonText",
|
||||
"default link LineNrAbove LineNr",
|
||||
"default link LineNrBelow LineNr",
|
||||
@ -6183,7 +6184,7 @@ static const char *highlight_init_both[] = {
|
||||
"default link Whitespace NonText",
|
||||
"default link MsgSeparator StatusLine",
|
||||
"default link NormalFloat Pmenu",
|
||||
"default link FloatBorder VertSplit",
|
||||
"default link FloatBorder WinSeparator",
|
||||
"default FloatShadow blend=80 guibg=Black",
|
||||
"default FloatShadowThrough blend=100 guibg=Black",
|
||||
"RedrawDebugNormal cterm=reverse gui=reverse",
|
||||
|
@ -146,7 +146,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
|
||||
" 'abcd |abcd '
|
||||
" ^^^^ ^^^^^^^^^ no highlight
|
||||
" ^ 'Search' highlight
|
||||
" ^ 'VertSplit' highlight
|
||||
" ^ 'WinSeparator' highlight
|
||||
let attrs0 = ScreenAttrs(1, 15)[0]
|
||||
call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
|
||||
call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14])
|
||||
@ -160,7 +160,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
|
||||
" 'abcd |abcd '
|
||||
" ^^^^ underline
|
||||
" ^ 'Search' highlight with underline
|
||||
" ^ 'VertSplit' highlight
|
||||
" ^ 'WinSeparator' highlight
|
||||
" ^^^^^^^^^ no highlight
|
||||
|
||||
" underline
|
||||
|
@ -60,7 +60,7 @@
|
||||
|
||||
#define NOWIN (win_T *)-1 // non-existing window
|
||||
|
||||
#define ROWS_AVAIL (Rows - p_ch - tabline_height())
|
||||
#define ROWS_AVAIL (Rows - p_ch - tabline_height() - global_stl_height())
|
||||
|
||||
/// flags for win_enter_ext()
|
||||
typedef enum {
|
||||
@ -647,6 +647,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
|
||||
}
|
||||
wp->w_floating = 1;
|
||||
wp->w_status_height = 0;
|
||||
wp->w_hsep_height = 0;
|
||||
wp->w_vsep_width = 0;
|
||||
|
||||
win_config_float(wp, fconfig);
|
||||
@ -956,6 +957,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
int before;
|
||||
int minheight;
|
||||
int wmh1;
|
||||
int hsep_height;
|
||||
bool did_set_fraction = false;
|
||||
|
||||
if (flags & WSP_TOP) {
|
||||
@ -1063,6 +1065,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hsep_height = global_stl_height() > 0 ? 1 : STATUS_HEIGHT;
|
||||
layout = FR_COL;
|
||||
|
||||
/*
|
||||
@ -1071,7 +1074,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
*/
|
||||
// Current window requires at least 1 space.
|
||||
wmh1 = p_wmh == 0 ? 1 : p_wmh;
|
||||
needed = wmh1 + STATUS_HEIGHT;
|
||||
needed = wmh1 + hsep_height;
|
||||
if (flags & WSP_ROOM) {
|
||||
needed += p_wh - wmh1;
|
||||
}
|
||||
@ -1113,15 +1116,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
new_size = oldwin_height / 2;
|
||||
}
|
||||
|
||||
if (new_size > available - minheight - STATUS_HEIGHT) {
|
||||
new_size = available - minheight - STATUS_HEIGHT;
|
||||
if (new_size > available - minheight - hsep_height) {
|
||||
new_size = available - minheight - hsep_height;
|
||||
}
|
||||
if (new_size < wmh1) {
|
||||
new_size = wmh1;
|
||||
}
|
||||
|
||||
// if it doesn't fit in the current window, need win_equal()
|
||||
if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) {
|
||||
if (oldwin_height - new_size - hsep_height < p_wmh) {
|
||||
do_equal = true;
|
||||
}
|
||||
|
||||
@ -1134,7 +1137,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
set_fraction(oldwin);
|
||||
did_set_fraction = true;
|
||||
|
||||
win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
|
||||
win_setheight_win(oldwin->w_height + new_size + hsep_height,
|
||||
oldwin);
|
||||
oldwin_height = oldwin->w_height;
|
||||
if (need_status) {
|
||||
@ -1151,8 +1154,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
while (frp != NULL) {
|
||||
if (frp->fr_win != oldwin && frp->fr_win != NULL
|
||||
&& (frp->fr_win->w_height > new_size
|
||||
|| frp->fr_win->w_height > oldwin_height - new_size
|
||||
- STATUS_HEIGHT)) {
|
||||
|| frp->fr_win->w_height > oldwin_height - new_size - hsep_height)) {
|
||||
do_equal = true;
|
||||
break;
|
||||
}
|
||||
@ -1278,13 +1280,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
||||
// set height and row of new window to full height
|
||||
wp->w_winrow = tabline_height();
|
||||
win_new_height(wp, curfrp->fr_height - (p_ls > 0));
|
||||
wp->w_status_height = (p_ls > 0);
|
||||
win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2));
|
||||
wp->w_status_height = (p_ls == 1 || p_ls == 2);
|
||||
wp->w_hsep_height = 0;
|
||||
} else {
|
||||
// height and row of new window is same as current window
|
||||
wp->w_winrow = oldwin->w_winrow;
|
||||
win_new_height(wp, oldwin->w_height);
|
||||
wp->w_status_height = oldwin->w_status_height;
|
||||
wp->w_hsep_height = oldwin->w_hsep_height;
|
||||
}
|
||||
frp->fr_height = curfrp->fr_height;
|
||||
|
||||
@ -1317,6 +1321,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
frame_fix_width(oldwin);
|
||||
frame_fix_width(wp);
|
||||
} else {
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
// width and column of new window is same as current window
|
||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
||||
wp->w_wincol = 0;
|
||||
@ -1332,28 +1337,53 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
// "new_size" of the current window goes to the new window, use
|
||||
// one row for the status line
|
||||
win_new_height(wp, new_size);
|
||||
if (before) {
|
||||
wp->w_hsep_height = is_stl_global ? 1 : 0;
|
||||
} else {
|
||||
wp->w_hsep_height = oldwin->w_hsep_height;
|
||||
oldwin->w_hsep_height = is_stl_global ? 1 : 0;
|
||||
}
|
||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
||||
int new_fr_height = curfrp->fr_height - new_size;
|
||||
|
||||
if (!((flags & WSP_BOT) && p_ls == 0)) {
|
||||
if (!((flags & WSP_BOT) && p_ls == 0) && global_stl_height() == 0) {
|
||||
new_fr_height -= STATUS_HEIGHT;
|
||||
} else if (global_stl_height() > 0) {
|
||||
if (flags & WSP_BOT) {
|
||||
frame_add_hsep(curfrp);
|
||||
} else {
|
||||
new_fr_height -= 1;
|
||||
}
|
||||
}
|
||||
frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, false);
|
||||
} else {
|
||||
win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
|
||||
win_new_height(oldwin, oldwin_height - (new_size
|
||||
+ (global_stl_height() > 0 ? 1 : STATUS_HEIGHT)));
|
||||
}
|
||||
|
||||
if (before) { // new window above current one
|
||||
wp->w_winrow = oldwin->w_winrow;
|
||||
wp->w_status_height = STATUS_HEIGHT;
|
||||
oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
|
||||
|
||||
if (is_stl_global) {
|
||||
wp->w_status_height = 0;
|
||||
oldwin->w_winrow += wp->w_height + 1;
|
||||
} else {
|
||||
wp->w_status_height = STATUS_HEIGHT;
|
||||
oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
|
||||
}
|
||||
} else { // new window below current one
|
||||
wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
|
||||
wp->w_status_height = oldwin->w_status_height;
|
||||
if (!(flags & WSP_BOT)) {
|
||||
oldwin->w_status_height = STATUS_HEIGHT;
|
||||
if (is_stl_global) {
|
||||
wp->w_winrow = oldwin->w_winrow + oldwin->w_height + 1;
|
||||
wp->w_status_height = 0;
|
||||
} else {
|
||||
wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
|
||||
wp->w_status_height = oldwin->w_status_height;
|
||||
if (!(flags & WSP_BOT)) {
|
||||
oldwin->w_status_height = STATUS_HEIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & WSP_BOT) {
|
||||
if ((flags & WSP_BOT) && global_stl_height() == 0) {
|
||||
frame_add_statusline(curfrp);
|
||||
}
|
||||
frame_fix_height(wp);
|
||||
@ -1595,10 +1625,10 @@ int make_windows(int count, bool vertical)
|
||||
maxcount = (curwin->w_width + curwin->w_vsep_width
|
||||
- (p_wiw - p_wmw)) / (p_wmw + 1);
|
||||
} else {
|
||||
// Each window needs at least 'winminheight' lines and a status line.
|
||||
maxcount = (curwin->w_height
|
||||
+ curwin->w_status_height
|
||||
- (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
|
||||
// Each window needs at least 'winminheight' lines
|
||||
// If statusline isn't global, each window also needs a statusline
|
||||
maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
|
||||
- (p_wh - p_wmh)) / (p_wmh + (global_stl_height() > 0 ? 1 : STATUS_HEIGHT));
|
||||
}
|
||||
|
||||
if (maxcount < 2) {
|
||||
@ -1693,7 +1723,7 @@ static void win_exchange(long Prenum)
|
||||
* if wp != wp2
|
||||
* 3. remove wp from the list
|
||||
* 4. insert wp after wp2
|
||||
* 5. exchange the status line height and vsep width.
|
||||
* 5. exchange the status line height, hsep height and vsep width.
|
||||
*/
|
||||
wp2 = curwin->w_prev;
|
||||
frp2 = curwin->w_frame->fr_prev;
|
||||
@ -1719,6 +1749,9 @@ static void win_exchange(long Prenum)
|
||||
temp = curwin->w_vsep_width;
|
||||
curwin->w_vsep_width = wp->w_vsep_width;
|
||||
wp->w_vsep_width = temp;
|
||||
temp = curwin->w_hsep_height;
|
||||
curwin->w_hsep_height = wp->w_hsep_height;
|
||||
wp->w_hsep_height = temp;
|
||||
|
||||
frame_fix_height(curwin);
|
||||
frame_fix_height(wp);
|
||||
@ -1793,10 +1826,13 @@ static void win_rotate(bool upwards, int count)
|
||||
frame_insert(frp->fr_parent->fr_child, frp);
|
||||
}
|
||||
|
||||
// exchange status height and vsep width of old and new last window
|
||||
// exchange status height, hsep height and vsep width of old and new last window
|
||||
n = wp2->w_status_height;
|
||||
wp2->w_status_height = wp1->w_status_height;
|
||||
wp1->w_status_height = n;
|
||||
n = wp2->w_hsep_height;
|
||||
wp2->w_hsep_height = wp1->w_hsep_height;
|
||||
wp1->w_hsep_height = n;
|
||||
frame_fix_height(wp1);
|
||||
frame_fix_height(wp2);
|
||||
n = wp2->w_vsep_width;
|
||||
@ -1870,11 +1906,16 @@ void win_move_after(win_T *win1, win_T *win2)
|
||||
|
||||
// check if there is something to do
|
||||
if (win2->w_next != win1) {
|
||||
// may need move the status line/vertical separator of the last window
|
||||
// may need move the status line, horizontal or vertical separator of the last window
|
||||
if (win1 == lastwin) {
|
||||
height = win1->w_prev->w_status_height;
|
||||
win1->w_prev->w_status_height = win1->w_status_height;
|
||||
win1->w_status_height = height;
|
||||
|
||||
height = win1->w_prev->w_hsep_height;
|
||||
win1->w_prev->w_hsep_height = win1->w_hsep_height;
|
||||
win1->w_hsep_height = height;
|
||||
|
||||
if (win1->w_prev->w_vsep_width == 1) {
|
||||
// Remove the vertical separator from the last-but-one window,
|
||||
// add it to the last window. Adjust the frame widths.
|
||||
@ -1887,6 +1928,11 @@ void win_move_after(win_T *win1, win_T *win2)
|
||||
height = win1->w_status_height;
|
||||
win1->w_status_height = win2->w_status_height;
|
||||
win2->w_status_height = height;
|
||||
|
||||
height = win1->w_hsep_height;
|
||||
win1->w_hsep_height = win2->w_hsep_height;
|
||||
win2->w_hsep_height = height;
|
||||
|
||||
if (win1->w_vsep_width == 1) {
|
||||
// Remove the vertical separator from win1, add it to the last
|
||||
// window, win2. Adjust the frame widths.
|
||||
@ -1950,6 +1996,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
|
||||
int room = 0;
|
||||
int new_size;
|
||||
int has_next_curwin = 0;
|
||||
int hsep_height;
|
||||
bool hnc;
|
||||
|
||||
if (topfr->fr_layout == FR_LEAF) {
|
||||
@ -2095,19 +2142,22 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
|
||||
totwincount -= wincount;
|
||||
}
|
||||
} else { // topfr->fr_layout == FR_COL
|
||||
hsep_height = global_stl_height() > 0 ? 1 : STATUS_HEIGHT;
|
||||
topfr->fr_width = width;
|
||||
topfr->fr_height = height;
|
||||
|
||||
if (dir != 'h') { // equalize frame heights
|
||||
// Compute maximum number of windows vertically in this frame.
|
||||
n = frame_minheight(topfr, NOWIN);
|
||||
// add one for the bottom window if it doesn't have a statusline
|
||||
// add one for the bottom window if it doesn't have a statusline or separator
|
||||
if (row + height == cmdline_row && p_ls == 0) {
|
||||
extra_sep = STATUS_HEIGHT;
|
||||
} else if (global_stl_height() > 0) {
|
||||
extra_sep = 1;
|
||||
} else {
|
||||
extra_sep = 0;
|
||||
}
|
||||
totwincount = (n + extra_sep) / (p_wmh + 1);
|
||||
totwincount = (n + extra_sep) / (p_wmh + hsep_height);
|
||||
has_next_curwin = frame_has_win(topfr, next_curwin);
|
||||
|
||||
/*
|
||||
@ -2142,7 +2192,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
|
||||
} else {
|
||||
// These windows don't use up room.
|
||||
totwincount -= (n + (fr->fr_next == NULL
|
||||
? extra_sep : 0)) / (p_wmh + 1);
|
||||
? extra_sep : 0)) / (p_wmh + hsep_height);
|
||||
}
|
||||
room -= new_size - n;
|
||||
if (room < 0) {
|
||||
@ -2188,7 +2238,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
|
||||
// Compute the maximum number of windows vert. in "fr".
|
||||
n = frame_minheight(fr, NOWIN);
|
||||
wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
|
||||
/ (p_wmh + 1);
|
||||
/ (p_wmh + hsep_height);
|
||||
m = frame_minheight(fr, next_curwin);
|
||||
if (has_next_curwin) {
|
||||
hnc = frame_has_win(fr, next_curwin);
|
||||
@ -3134,7 +3184,7 @@ static tabpage_T *alt_tabpage(void)
|
||||
/*
|
||||
* Find the left-upper window in frame "frp".
|
||||
*/
|
||||
static win_T *frame2win(frame_T *frp)
|
||||
win_T *frame2win(frame_T *frp)
|
||||
{
|
||||
while (frp->fr_win == NULL) {
|
||||
frp = frp->fr_child;
|
||||
@ -3161,23 +3211,40 @@ static bool frame_has_win(const frame_T *frp, const win_T *wp)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if current window is at the bottom
|
||||
/// Returns true if there are no windows below current window
|
||||
static bool is_bottom_win(win_T *wp)
|
||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
frame_T *frp;
|
||||
for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
|
||||
if (frp->fr_parent->fr_layout == FR_COL && frp->fr_next != NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/// Set a new height for a frame. Recursively sets the height for contained
|
||||
/// frames and windows. Caller must take care of positions.
|
||||
///
|
||||
/// @param topfirst resize topmost contained frame first.
|
||||
/// @param wfh obey 'winfixheight' when there is a choice;
|
||||
/// may cause the height not to be set.
|
||||
static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
|
||||
void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
frame_T *frp;
|
||||
int extra_lines;
|
||||
int h;
|
||||
win_T *wp;
|
||||
|
||||
if (topfrp->fr_win != NULL) {
|
||||
// Simple case: just one window.
|
||||
win_new_height(topfrp->fr_win,
|
||||
height - topfrp->fr_win->w_status_height);
|
||||
wp = topfrp->fr_win;
|
||||
if (is_bottom_win(wp)) {
|
||||
wp->w_hsep_height = 0;
|
||||
}
|
||||
win_new_height(wp, height - wp->w_hsep_height - wp->w_status_height);
|
||||
} else if (topfrp->fr_layout == FR_ROW) {
|
||||
do {
|
||||
// All frames in this row get the same new height.
|
||||
@ -3333,8 +3400,8 @@ static void frame_add_statusline(frame_T *frp)
|
||||
if (frp->fr_layout == FR_LEAF) {
|
||||
wp = frp->fr_win;
|
||||
if (wp->w_status_height == 0) {
|
||||
if (wp->w_height > 0) { // don't make it negative
|
||||
--wp->w_height;
|
||||
if (wp->w_height - STATUS_HEIGHT >= 0) { // don't make it negative
|
||||
wp->w_height -= STATUS_HEIGHT;
|
||||
}
|
||||
wp->w_status_height = STATUS_HEIGHT;
|
||||
}
|
||||
@ -3454,10 +3521,8 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw
|
||||
topfrp->fr_width = width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the vertical separator to windows at the right side of "frp".
|
||||
* Note: Does not check if there is room!
|
||||
*/
|
||||
/// Add the vertical separator to windows at the right side of "frp".
|
||||
/// Note: Does not check if there is room!
|
||||
static void frame_add_vsep(const frame_T *frp)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
@ -3487,6 +3552,37 @@ static void frame_add_vsep(const frame_T *frp)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the horizontal separator to windows at the bottom of "frp".
|
||||
/// Note: Does not check if there is room or whether the windows have a statusline!
|
||||
static void frame_add_hsep(const frame_T *frp)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
win_T *wp;
|
||||
|
||||
if (frp->fr_layout == FR_LEAF) {
|
||||
wp = frp->fr_win;
|
||||
if (wp->w_hsep_height == 0) {
|
||||
if (wp->w_height > 0) { // don't make it negative
|
||||
wp->w_height++;
|
||||
}
|
||||
wp->w_hsep_height = 1;
|
||||
}
|
||||
} else if (frp->fr_layout == FR_ROW) {
|
||||
// Handle all the frames in the row.
|
||||
FOR_ALL_FRAMES(frp, frp->fr_child) {
|
||||
frame_add_hsep(frp);
|
||||
}
|
||||
} else {
|
||||
assert(frp->fr_layout == FR_COL);
|
||||
// Only need to handle the last frame in the column.
|
||||
frp = frp->fr_child;
|
||||
while (frp->fr_next != NULL) {
|
||||
frp = frp->fr_next;
|
||||
}
|
||||
frame_add_hsep(frp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set frame width from the window it contains.
|
||||
*/
|
||||
@ -3501,7 +3597,7 @@ static void frame_fix_width(win_T *wp)
|
||||
static void frame_fix_height(win_T *wp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
|
||||
wp->w_frame->fr_height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3519,10 +3615,11 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
|
||||
|
||||
if (topfrp->fr_win != NULL) {
|
||||
if (topfrp->fr_win == next_curwin) {
|
||||
m = p_wh + topfrp->fr_win->w_status_height;
|
||||
m = p_wh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
|
||||
} else {
|
||||
// window: minimal height of the window plus status line
|
||||
m = p_wmh + topfrp->fr_win->w_status_height;
|
||||
// window: minimal height of the window plus separator column or status line
|
||||
// depending on whether global statusline is enabled
|
||||
m = p_wmh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
|
||||
if (topfrp->fr_win == curwin && next_curwin == NULL) {
|
||||
// Current window is minimal one line high.
|
||||
if (p_wmh == 0) {
|
||||
@ -3751,7 +3848,7 @@ static int win_alloc_firstwin(win_T *oldwin)
|
||||
new_frame(curwin);
|
||||
topframe = curwin->w_frame;
|
||||
topframe->fr_width = Columns;
|
||||
topframe->fr_height = Rows - p_ch;
|
||||
topframe->fr_height = Rows - p_ch - global_stl_height();
|
||||
|
||||
return OK;
|
||||
}
|
||||
@ -5147,11 +5244,8 @@ void win_size_restore(garray_T *gap)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the position for all windows, using the width and height of the
|
||||
* frames.
|
||||
* Returns the row just after the last window.
|
||||
*/
|
||||
// Update the position for all windows, using the width and height of the frames.
|
||||
// Returns the row just after the last window and global statusline (if there is one).
|
||||
int win_comp_pos(void)
|
||||
{
|
||||
int row = tabline_height();
|
||||
@ -5166,7 +5260,7 @@ int win_comp_pos(void)
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
return row + global_stl_height();
|
||||
}
|
||||
|
||||
void win_reconfig_floats(void)
|
||||
@ -5200,7 +5294,7 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
|
||||
wp->w_redr_status = true;
|
||||
wp->w_pos_changed = true;
|
||||
}
|
||||
const int h = wp->w_height + wp->w_status_height;
|
||||
const int h = wp->w_height + wp->w_hsep_height + wp->w_status_height;
|
||||
*row += h > topfrp->fr_height ? topfrp->fr_height : h;
|
||||
*col += wp->w_width + wp->w_vsep_width;
|
||||
} else {
|
||||
@ -5249,7 +5343,7 @@ void win_setheight_win(int height, win_T *win)
|
||||
win_config_float(win, win->w_float_config);
|
||||
redraw_later(win, NOT_VALID);
|
||||
} else {
|
||||
frame_setheight(win->w_frame, height + win->w_status_height);
|
||||
frame_setheight(win->w_frame, height + win->w_hsep_height + win->w_status_height);
|
||||
|
||||
// recompute the window positions
|
||||
int row = win_comp_pos();
|
||||
@ -5340,8 +5434,8 @@ static void frame_setheight(frame_T *curfrp, int height)
|
||||
room_cmdline = 0;
|
||||
} else {
|
||||
win_T *wp = lastwin_nofloating();
|
||||
room_cmdline = Rows - p_ch
|
||||
- (wp->w_winrow + wp->w_height + wp->w_status_height);
|
||||
room_cmdline = Rows - p_ch - global_stl_height()
|
||||
- (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height);
|
||||
if (room_cmdline < 0) {
|
||||
room_cmdline = 0;
|
||||
}
|
||||
@ -5703,7 +5797,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
|
||||
} else { // drag down
|
||||
up = false;
|
||||
// Only dragging the last status line can reduce p_ch.
|
||||
room = Rows - cmdline_row;
|
||||
room = Rows - cmdline_row - global_stl_height();
|
||||
if (curfr->fr_next == NULL) {
|
||||
room -= 1;
|
||||
} else {
|
||||
@ -6344,72 +6438,104 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
|
||||
return find_file_name_in_path(ptr, len, options, count, rel_fname);
|
||||
}
|
||||
|
||||
/// Add or remove a status line for the bottom window(s), according to the
|
||||
/// Add or remove a status line from window(s), according to the
|
||||
/// value of 'laststatus'.
|
||||
///
|
||||
/// @param morewin pretend there are two or more windows if true.
|
||||
void last_status(bool morewin)
|
||||
{
|
||||
// Don't make a difference between horizontal or vertical split.
|
||||
last_status_rec(topframe, (p_ls == 2
|
||||
|| (p_ls == 1 && (morewin || !one_window()))));
|
||||
last_status_rec(topframe, (p_ls == 2 || (p_ls == 1 && (morewin || !one_window()))),
|
||||
global_stl_height() > 0);
|
||||
}
|
||||
|
||||
static void last_status_rec(frame_T *fr, bool statusline)
|
||||
// Look for resizable frames and take lines from them to make room for the statusline
|
||||
static void resize_frame_for_status(frame_T *fr, int resize_amount)
|
||||
{
|
||||
// Find a frame to take a line from.
|
||||
frame_T *fp = fr;
|
||||
win_T *wp = fr->fr_win;
|
||||
int n;
|
||||
|
||||
while (resize_amount > 0) {
|
||||
while (fp->fr_height <= frame_minheight(fp, NULL)) {
|
||||
if (fp == topframe) {
|
||||
emsg(_(e_noroom));
|
||||
return;
|
||||
}
|
||||
// In a column of frames: go to frame above. If already at
|
||||
// the top or in a row of frames: go to parent.
|
||||
if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
|
||||
fp = fp->fr_prev;
|
||||
} else {
|
||||
fp = fp->fr_parent;
|
||||
}
|
||||
}
|
||||
n = MIN(fp->fr_height - frame_minheight(fp, NULL), resize_amount);
|
||||
resize_amount -= n;
|
||||
|
||||
if (fp != fr) {
|
||||
frame_new_height(fp, fp->fr_height - n, false, false);
|
||||
frame_fix_height(wp);
|
||||
(void)win_comp_pos();
|
||||
} else {
|
||||
win_new_height(wp, wp->w_height - n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
|
||||
{
|
||||
frame_T *fp;
|
||||
win_T *wp;
|
||||
|
||||
if (fr->fr_layout == FR_LEAF) {
|
||||
wp = fr->fr_win;
|
||||
if (wp->w_status_height != 0 && !statusline) {
|
||||
// remove status line
|
||||
win_new_height(wp, wp->w_height + 1);
|
||||
bool is_last = is_bottom_win(wp);
|
||||
|
||||
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();
|
||||
} else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
|
||||
// Add statusline to window if needed
|
||||
wp->w_status_height = STATUS_HEIGHT;
|
||||
resize_frame_for_status(fr, STATUS_HEIGHT);
|
||||
comp_col();
|
||||
}
|
||||
} 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
|
||||
if (STATUS_HEIGHT - 1 != 0) {
|
||||
win_new_height(wp, wp->w_height + STATUS_HEIGHT - 1);
|
||||
}
|
||||
wp->w_status_height = 0;
|
||||
wp->w_hsep_height = 1;
|
||||
comp_col();
|
||||
} else if (wp->w_status_height == 0 && statusline) {
|
||||
// Find a frame to take a line from.
|
||||
fp = fr;
|
||||
while (fp->fr_height <= frame_minheight(fp, NULL)) {
|
||||
if (fp == topframe) {
|
||||
emsg(_(e_noroom));
|
||||
return;
|
||||
}
|
||||
// In a column of frames: go to frame above. If already at
|
||||
// the top or in a row of frames: go to parent.
|
||||
if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
|
||||
fp = fp->fr_prev;
|
||||
} else {
|
||||
fp = fp->fr_parent;
|
||||
}
|
||||
}
|
||||
wp->w_status_height = 1;
|
||||
if (fp != fr) {
|
||||
frame_new_height(fp, fp->fr_height - 1, false, false);
|
||||
frame_fix_height(wp);
|
||||
(void)win_comp_pos();
|
||||
} else {
|
||||
win_new_height(wp, wp->w_height - 1);
|
||||
}
|
||||
} 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;
|
||||
wp->w_hsep_height = 0;
|
||||
resize_frame_for_status(fr, STATUS_HEIGHT - 1);
|
||||
comp_col();
|
||||
redraw_all_later(SOME_VALID);
|
||||
}
|
||||
} else if (fr->fr_layout == FR_ROW) {
|
||||
// vertically split windows, set status line for each one
|
||||
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);
|
||||
last_status_rec(fp, statusline, is_stl_global);
|
||||
}
|
||||
} else {
|
||||
// horizontally split window, set status line for last one
|
||||
for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
|
||||
// For a 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);
|
||||
}
|
||||
last_status_rec(fp, statusline);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of lines used by the tab page line.
|
||||
*/
|
||||
/// Return the number of lines used by the tab page line.
|
||||
int tabline_height(void)
|
||||
{
|
||||
if (ui_has(kUITabline)) {
|
||||
@ -6425,10 +6551,14 @@ int tabline_height(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the minimal number of rows that is needed on the screen to display
|
||||
* the current number of windows.
|
||||
*/
|
||||
/// Return the number of lines used by the global statusline
|
||||
int global_stl_height(void)
|
||||
{
|
||||
return (p_ls == 3) ? STATUS_HEIGHT : 0;
|
||||
}
|
||||
|
||||
/// Return the minimal number of rows that is needed on the screen to display
|
||||
/// the current number of windows.
|
||||
int min_rows(void)
|
||||
{
|
||||
if (firstwin == NULL) { // not initialized yet
|
||||
@ -6442,7 +6572,7 @@ int min_rows(void)
|
||||
total = n;
|
||||
}
|
||||
}
|
||||
total += tabline_height();
|
||||
total += tabline_height() + global_stl_height();
|
||||
total += 1; // count the room for the command line
|
||||
return total;
|
||||
}
|
||||
|
@ -212,10 +212,10 @@ describe('ui/cursor', function()
|
||||
if m.blinkwait then m.blinkwait = 700 end
|
||||
end
|
||||
if m.hl_id then
|
||||
m.hl_id = 60
|
||||
m.hl_id = 61
|
||||
m.attr = {background = Screen.colors.DarkGray}
|
||||
end
|
||||
if m.id_lm then m.id_lm = 61 end
|
||||
if m.id_lm then m.id_lm = 62 end
|
||||
end
|
||||
|
||||
-- Assert the new expectation.
|
||||
|
233
test/functional/ui/global_statusline_spec.lua
Normal file
233
test/functional/ui/global_statusline_spec.lua
Normal file
@ -0,0 +1,233 @@
|
||||
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
|
||||
|
||||
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=[[
|
||||
{1:│} {1:│} {1:│}^ |
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
|
||||
{1:────────────────────┴────────────────┴─┤}{2:~ }|
|
||||
{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{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=[[
|
||||
{1:│} {1:│} {1:│}^ |
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
|
||||
{1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
|
||||
{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{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=[[
|
||||
{1:│} {1:│} {1:│}^ |
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
|
||||
{1:────────────────────┴────────────────┴─┤}{2:~ }|
|
||||
{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{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=[[
|
||||
{1:│} {1:│} {1:│}^ |
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
|
||||
{1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
|
||||
{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{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=[[
|
||||
{1:│} {1:│} {1:│}^ |
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
|
||||
{2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
|
||||
{1:────────────────────┴────────────────┴─┤}{2:~ }|
|
||||
{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{2:~ }|
|
||||
{2:~ }{1:│}{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)
|
||||
end)
|
@ -59,7 +59,7 @@ describe('ext_hlstate detailed highlights', function()
|
||||
|
||||
it('work with cleared UI highlights', function()
|
||||
screen:set_default_attr_ids({
|
||||
[1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
|
||||
[1] = {{}, {{hi_name = "VertSplit", ui_name = "WinSeparator", kind = "ui"}}},
|
||||
[2] = {{bold = true, foreground = Screen.colors.Blue1},
|
||||
{{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
|
||||
[3] = {{bold = true, reverse = true},
|
||||
|
@ -48,6 +48,7 @@ local predefined_hl_defs = {
|
||||
TermCursor=true,
|
||||
VertSplit=true,
|
||||
WildMenu=true,
|
||||
WinSeparator=true,
|
||||
EndOfBuffer=true,
|
||||
QuickFixLine=true,
|
||||
Substitute=true,
|
||||
|
Loading…
Reference in New Issue
Block a user