diff --git a/src/buffer.c b/src/buffer.c index 44e504c537..43cba3ad8c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -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 diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro index 13c273d6aa..7c29256426 100644 --- a/src/proto/buffer.pro +++ b/src/proto/buffer.pro @@ -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); diff --git a/src/screen.c b/src/screen.c index 57b041d40d..9c76b8763b 100644 --- a/src/screen.c +++ b/src/screen.c @@ -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); diff --git a/src/tabpanel.c b/src/tabpanel.c index 1e833c7b65..f7889a5e59 100644 --- a/src/tabpanel.c +++ b/src/tabpanel.c @@ -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; diff --git a/src/testdir/dumps/Test_multistatusline_carry_hl_01.dump b/src/testdir/dumps/Test_multistatusline_carry_hl_01.dump new file mode 100644 index 0000000000..724d844bd6 --- /dev/null +++ b/src/testdir/dumps/Test_multistatusline_carry_hl_01.dump @@ -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 diff --git a/src/testdir/dumps/Test_tabpanel_carry_hl_01.dump b/src/testdir/dumps/Test_tabpanel_carry_hl_01.dump new file mode 100644 index 0000000000..87a130f293 --- /dev/null +++ b/src/testdir/dumps/Test_tabpanel_carry_hl_01.dump @@ -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| diff --git a/src/testdir/test_statuslineopt.vim b/src/testdir/test_statuslineopt.vim index 6454dbff87..653529e356 100644 --- a/src/testdir/test_statuslineopt.vim +++ b/src/testdir/test_statuslineopt.vim @@ -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, "\") + call VerifyScreenDump(buf, 'Test_multistatusline_carry_hl_01', {}) + + call StopVimInTerminal(buf) +endfunc + func Test_statuslineopt_default_stl() CheckScreendump diff --git a/src/testdir/test_tabpanel.vim b/src/testdir/test_tabpanel.vim index b5bf678a10..3b5fe390f4 100644 --- a/src/testdir/test_tabpanel.vim +++ b/src/testdir/test_tabpanel.vim @@ -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 diff --git a/src/version.c b/src/version.c index 705339b344..a5ba4c7960 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 467, /**/ 466, /**/