mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
patch 9.2.0467: multi-line statusline loses highlighting attributes
Problem: In a multi-line statusline (and 'tabpanel'), %#XX# / %N*
set on one row do not persist on subsequent rows.
build_stl_str_hl_local() rebuilds stl_items[] from scratch
on every line break ("%@" or "\n"), so the highlight is
reset at each row boundary even though within a row it
stays until %* (or another %# / %*).
Solution: Carry the last Highlight item's stl_minwid across line
breaks via a new in/out int* parameter "carry_hl". At the
start of each row, pre-insert a Highlight item from the
carried value so the row begins under the same highlight;
before returning, update the carried value with the row's
final Highlight item. Apply the same carry to the
tabpanel rendering loop (Hirohito Higashi).
related: #19123
closes: #20180
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
3a8b9e09b2
commit
5ef1eec5c5
+38
-8
@@ -50,7 +50,7 @@ static int build_stl_str_hl_local(stl_mode_T mode, win_T *wp,
|
||||
char_u *out, size_t outlen, char_u **fmt_arg,
|
||||
char_u *opt_name, int opt_scope, int fillchar, int maxwidth,
|
||||
stl_hlrec_T **hltab, stl_hlrec_T **tabtab,
|
||||
stl_clickrec_T **clicktab, int *lbreaks);
|
||||
stl_clickrec_T **clicktab, int *lbreaks, int *carry_hl);
|
||||
#endif
|
||||
static int append_arg_number(win_T *wp, char_u *buf, size_t buflen, int add_file);
|
||||
static void free_buffer(buf_T *);
|
||||
@@ -4393,7 +4393,7 @@ build_stl_str_hl(
|
||||
{
|
||||
return build_stl_str_hl_local(STL_MODE_SINGLE, wp, out, outlen, &fmt,
|
||||
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, clicktab,
|
||||
NULL);
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -4408,11 +4408,13 @@ build_stl_str_hl_mline(
|
||||
int maxwidth,
|
||||
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
|
||||
stl_hlrec_T **tabtab, // return: tab page nrs (can be NULL)
|
||||
stl_clickrec_T **clicktab) // return: click func regions (can be NULL)
|
||||
stl_clickrec_T **clicktab, // return: click func regions (can be NULL)
|
||||
int *carry_hl) // (in/out) %# / %* highlight carried across
|
||||
// line breaks (can be NULL)
|
||||
{
|
||||
return build_stl_str_hl_local(STL_MODE_MULTI, wp, out, outlen, fmt,
|
||||
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, clicktab,
|
||||
NULL);
|
||||
NULL, carry_hl);
|
||||
}
|
||||
|
||||
# ifdef ENABLE_STL_MODE_MULTI_NL
|
||||
@@ -4428,11 +4430,13 @@ build_stl_str_hl_mline_nl(
|
||||
int maxwidth,
|
||||
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
|
||||
stl_hlrec_T **tabtab, // return: tab page nrs (can be NULL)
|
||||
stl_clickrec_T **clicktab) // return: click func regions (can be NULL)
|
||||
stl_clickrec_T **clicktab, // return: click func regions (can be NULL)
|
||||
int *carry_hl) // (in/out) %# / %* highlight carried across
|
||||
// line breaks (can be NULL)
|
||||
{
|
||||
return build_stl_str_hl_local(STL_MODE_MULTI_NL, wp, out, outlen, fmt,
|
||||
opt_name, opt_scope, fillchar, maxwidth, hltab, tabtab, clicktab,
|
||||
NULL);
|
||||
NULL, carry_hl);
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -4453,7 +4457,8 @@ get_stl_rendered_height(
|
||||
++emsg_off;
|
||||
(void)build_stl_str_hl_local(STL_MODE_GET_RENDERED_HEIGHT,
|
||||
wp, buf, sizeof(buf), &fmt,
|
||||
opt_name, opt_scope, 0, 0, NULL, NULL, NULL, &rendered_height);
|
||||
opt_name, opt_scope, 0, 0, NULL, NULL, NULL, &rendered_height,
|
||||
NULL);
|
||||
--emsg_off;
|
||||
return rendered_height;
|
||||
}
|
||||
@@ -4489,7 +4494,9 @@ build_stl_str_hl_local(
|
||||
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
|
||||
stl_hlrec_T **tabtab, // return: tab page nrs (can be NULL)
|
||||
stl_clickrec_T **clicktab, // return: click func regions (can be NULL)
|
||||
int *rendered_height) // return: stl rendered height (can be NULL)
|
||||
int *rendered_height, // return: stl rendered height (can be NULL)
|
||||
int *carry_hl) // (in/out) %# / %* highlight carried across
|
||||
// line breaks (can be NULL)
|
||||
{
|
||||
linenr_T lnum;
|
||||
colnr_T len;
|
||||
@@ -4614,6 +4621,18 @@ build_stl_str_hl_local(
|
||||
# endif
|
||||
p = out;
|
||||
curitem = 0;
|
||||
|
||||
// Pre-insert a Highlight item from carry_hl so that %# / %* set on a
|
||||
// previous multi-line statusline row continues to apply on this row.
|
||||
if (carry_hl != NULL && *carry_hl != 0)
|
||||
{
|
||||
stl_items[curitem].stl_type = Highlight;
|
||||
stl_items[curitem].stl_start = p;
|
||||
stl_items[curitem].stl_minwid = *carry_hl;
|
||||
stl_items[curitem].stl_clickfunc = NULL;
|
||||
curitem++;
|
||||
}
|
||||
|
||||
prevchar_isflag = TRUE;
|
||||
prevchar_isitem = FALSE;
|
||||
for (s = usefmt; *s != NUL; )
|
||||
@@ -5446,6 +5465,17 @@ find_linebreak:
|
||||
outputlen = (size_t)(p - out);
|
||||
itemcnt = curitem;
|
||||
|
||||
// Remember the most recent %# / %* highlight so the next row of a
|
||||
// multi-line statusline can resume it.
|
||||
if (carry_hl != NULL)
|
||||
{
|
||||
int last_hl = 0;
|
||||
for (l = 0; l < itemcnt; l++)
|
||||
if (stl_items[l].stl_type == Highlight)
|
||||
last_hl = stl_items[l].stl_minwid;
|
||||
*carry_hl = last_hl;
|
||||
}
|
||||
|
||||
if (mode == STL_MODE_MULTI
|
||||
# ifdef ENABLE_STL_MODE_MULTI_NL
|
||||
|| mode == STL_MODE_MULTI_NL
|
||||
|
||||
@@ -50,8 +50,8 @@ void maketitle(void);
|
||||
void resettitle(void);
|
||||
void free_titles(void);
|
||||
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab, stl_clickrec_T **clicktab);
|
||||
int build_stl_str_hl_mline(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab, stl_clickrec_T **clicktab);
|
||||
int build_stl_str_hl_mline_nl(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab, stl_clickrec_T **clicktab);
|
||||
int build_stl_str_hl_mline(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab, stl_clickrec_T **clicktab, int *carry_hl);
|
||||
int build_stl_str_hl_mline_nl(win_T *wp, char_u *out, size_t outlen, char_u **fmt, char_u *opt_name, int opt_scope, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab, stl_clickrec_T **clicktab, int *carry_hl);
|
||||
int get_stl_rendered_height(win_T *wp, char_u *fmt, char_u *opt_name, int opt_scope);
|
||||
int get_rel_pos(win_T *wp, char_u *buf, int buflen);
|
||||
char_u *fix_fname(char_u *fname);
|
||||
|
||||
+3
-1
@@ -1479,6 +1479,7 @@ win_redr_custom(
|
||||
*out_count = 0;
|
||||
}
|
||||
|
||||
int carry_hl = 0;
|
||||
for (int i = 0; i < stlh_cnt; i++)
|
||||
{
|
||||
col = col_save;
|
||||
@@ -1487,7 +1488,8 @@ win_redr_custom(
|
||||
&stl_tmp,
|
||||
opt_name, opt_scope,
|
||||
fillchar, maxwidth, &hltab, &tabtab,
|
||||
&clicktab);
|
||||
&clicktab,
|
||||
&carry_hl);
|
||||
|
||||
// Make all characters printable.
|
||||
p = transstr(buf);
|
||||
|
||||
+4
-1
@@ -688,6 +688,8 @@ do_by_tplmode(
|
||||
|
||||
if (usefmt != NULL && *usefmt != NUL)
|
||||
{
|
||||
int carry_hl = 0;
|
||||
|
||||
while (*usefmt != NUL)
|
||||
{
|
||||
char_u buf[IOSIZE];
|
||||
@@ -708,7 +710,8 @@ do_by_tplmode(
|
||||
(args.cwp, buf, sizeof(buf),
|
||||
&usefmt, opt_name, opt_scope, TPL_FILLCHAR,
|
||||
args.col_end - args.col_start, &hltab, &tabtab,
|
||||
tplmode == TPLMODE_REDRAW ? &clicktab : NULL);
|
||||
tplmode == TPLMODE_REDRAW ? &clicktab : NULL,
|
||||
&carry_hl);
|
||||
|
||||
args.prow = &row;
|
||||
args.pcol = &col;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
> +0&#ffffff0@74
|
||||
|~+0#4040ff13&| @73
|
||||
|L+3#0000000&|1|A| @68|L+0&#ffff4012|1|B
|
||||
|L|2| |c|a|r@1|i|e|d| |S|e|a|r|c|h| @57
|
||||
|L+3&#ffffff0|3| |r|e|s|e|t| @66
|
||||
|L+0#ffff4012#4040ff13|4| |u|s|e|r|2| @66
|
||||
|L|5| |c|a|r@1|i|e|d| |u|s|e|r|2| @58
|
||||
|L+3#0000000#ffffff0|6| |r|e|s|e|t| @66
|
||||
| +0&&@74
|
||||
@@ -0,0 +1,9 @@
|
||||
|L+2&#ffffff0|1|A| @16> +0&&@39
|
||||
|L+0&#ffff4012|1|B| @16|~+0#4040ff13#ffffff0| @38
|
||||
|L+0#0000000#ffff4012|2| |c|a|r@1|i|e|d| |S|e|a|r|c|h| @2|~+0#4040ff13#ffffff0| @38
|
||||
|L+2#0000000&|3| |r|e|s|e|t| @11|~+0#4040ff13&| @38
|
||||
|L+0#ffff4012#4040ff13|4| |u|s|e|r|2| @11|~+0#4040ff13#ffffff0| @38
|
||||
|L+0#ffff4012#4040ff13|5| |c|a|r@1|i|e|d| @9|~+0#4040ff13#ffffff0| @38
|
||||
|L+2#0000000&|6| |r|e|s|e|t| @11|~+0#4040ff13&| @38
|
||||
| +1#0000000&@19|~+0#4040ff13&| @38
|
||||
| +1#0000000&@19| +0&&@21|0|,|0|-|1| @8|A|l@1|
|
||||
@@ -235,6 +235,35 @@ func Test_multistatusline_highlight()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_multistatusline_carry_hl()
|
||||
CheckScreendump
|
||||
|
||||
" %#XX# / %N* set on one row should persist on subsequent rows until %*
|
||||
" (or another %# / %*) changes it.
|
||||
let lines =<< trim END
|
||||
func MyStatusLine()
|
||||
return 'L1A%=%#Search#L1B%@'
|
||||
\ .. 'L2 carried Search%@'
|
||||
\ .. '%*L3 reset%@'
|
||||
\ .. '%2*L4 user2%@'
|
||||
\ .. 'L5 carried user2%@'
|
||||
\ .. '%*L6 reset'
|
||||
endfunc
|
||||
|
||||
hi User2 ctermfg=Yellow ctermbg=Blue
|
||||
set laststatus=2
|
||||
set statuslineopt=maxheight:6
|
||||
set statusline=%!MyStatusLine()
|
||||
END
|
||||
call writefile(lines, 'XTest_multistatusline_carry_hl', 'D')
|
||||
|
||||
let buf = g:RunVimInTerminal('-S XTest_multistatusline_carry_hl', {'rows': 9})
|
||||
call term_sendkeys(buf, "\<C-L>")
|
||||
call VerifyScreenDump(buf, 'Test_multistatusline_carry_hl_01', {})
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_statuslineopt_default_stl()
|
||||
CheckScreendump
|
||||
|
||||
|
||||
@@ -1129,6 +1129,36 @@ func Test_tabpanel_empty()
|
||||
set tabpanel&
|
||||
endfunc
|
||||
|
||||
func Test_tabpanel_carry_hl()
|
||||
CheckScreendump
|
||||
|
||||
" %#XX# / %N* set on one row of a tabpanel should persist on subsequent
|
||||
" rows until %* (or another %# / %*) changes it. Both "%@" and "\n" are
|
||||
" accepted as line breaks in 'tabpanel'.
|
||||
let lines =<< trim END
|
||||
func MyTabPanel()
|
||||
return "L1A\n"
|
||||
\ .. "%#Search#L1B\n"
|
||||
\ .. "L2 carried Search\n"
|
||||
\ .. "%*L3 reset\n"
|
||||
\ .. "%2*L4 user2\n"
|
||||
\ .. "L5 carried\n"
|
||||
\ .. "%*L6 reset"
|
||||
endfunc
|
||||
|
||||
hi User2 ctermfg=Yellow ctermbg=Blue
|
||||
set showtabpanel=2
|
||||
set tabpanelopt=columns:20
|
||||
set tabpanel=%!MyTabPanel()
|
||||
END
|
||||
call writefile(lines, 'XTest_tabpanel_carry_hl', 'D')
|
||||
|
||||
let buf = RunVimInTerminal('-S XTest_tabpanel_carry_hl', {'rows': 9, 'cols': 60})
|
||||
call VerifyScreenDump(buf, 'Test_tabpanel_carry_hl_01', {})
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_tabpanel_getinfo_and_scroll()
|
||||
CheckScreendump
|
||||
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
467,
|
||||
/**/
|
||||
466,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user