# HG changeset patch # User Bram Moolenaar # Date 1656953104 -7200 # Node ID 9dce192d1ac2d5ca6e39dcae78e2e89cf0aaca57 # Parent f0f3018d296b5495070074970bf3878ce244ce8a patch 9.0.0036: 'fillchars' cannot have window-local values Commit: https://github.com/vim/vim/commit/96ba25ac01279f73c0ecb5d4aa4ff37aa359e5eb Author: Bram Moolenaar Date: Mon Jul 4 17:34:33 2022 +0100 patch 9.0.0036: 'fillchars' cannot have window-local values Problem: 'fillchars' cannot have window-local values. Solution: Make 'fillchars' global-local. (closes https://github.com/vim/vim/issues/5206) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3376,22 +3376,24 @@ A jump table for the options with a shor *'fillchars'* *'fcs'* 'fillchars' 'fcs' string (default "vert:|,fold:-,eob:~") - global + global or local to window |global-local| {not available when compiled without the |+folding| feature} - Characters to fill the statuslines and vertical separators. - It is a comma-separated list of items: - - item default Used for ~ - stl:c ' ' or '^' statusline of the current window - stlnc:c ' ' or '=' statusline of the non-current windows - vert:c '|' vertical separators |:vsplit| - fold:c '-' filling 'foldtext' - foldopen:c '-' mark the beginning of a fold - foldclose:c '+' show a closed fold - foldsep:c '|' open fold middle character - diff:c '-' deleted lines of the 'diff' option - eob:c '~' empty lines below the end of a buffer + Characters to fill the statuslines, vertical separators and special + lines in the window. + It is a comma-separated list of items. Each item has a name, a colon + and the value of that item: + + item name default Used for ~ + stl ' ' or '^' statusline of the current window + stlnc ' ' or '=' statusline of the non-current windows + vert '|' vertical separators |:vsplit| + fold '-' filling 'foldtext' + foldopen '-' mark the beginning of a fold + foldclose '+' show a closed fold + foldsep '|' open fold middle character + diff '-' deleted lines of the 'diff' option + eob '~' empty lines below the end of a buffer Any one that is omitted will fall back to the default. For "stl" and "stlnc" the space will be used when there is highlighting, '^' or '=' @@ -3407,13 +3409,13 @@ A jump table for the options with a shor characters are not supported. The highlighting used for these items: - item highlight group ~ - stl:c StatusLine |hl-StatusLine| - stlnc:c StatusLineNC |hl-StatusLineNC| - vert:c VertSplit |hl-VertSplit| - fold:c Folded |hl-Folded| - diff:c DiffDelete |hl-DiffDelete| - eob:c EndOfBuffer |hl-EndOfBuffer| + item name highlight group ~ + stl StatusLine |hl-StatusLine| + stlnc StatusLineNC |hl-StatusLineNC| + vert VertSplit |hl-VertSplit| + fold Folded |hl-Folded| + diff DiffDelete |hl-DiffDelete| + eob EndOfBuffer |hl-EndOfBuffer| *'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'* 'fixendofline' 'fixeol' boolean (default on) diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -1268,14 +1268,14 @@ win_line( if (filler_todo > 0) { // Draw "deleted" diff line(s). - if (char2cells(fill_diff) > 1) + if (char2cells(wp->w_fill_chars.diff) > 1) { c_extra = '-'; c_final = NUL; } else { - c_extra = fill_diff; + c_extra = wp->w_fill_chars.diff; c_final = NUL; } # ifdef FEAT_RIGHTLEFT @@ -1352,7 +1352,7 @@ win_line( #endif ) { - screen_line(screen_row, wp->w_wincol, col, -wp->w_width, + screen_line(wp, screen_row, wp->w_wincol, col, -wp->w_width, screen_line_flags); // Pretend we have finished updating the window. Except when // 'cursorcolumn' is set. @@ -2859,7 +2859,7 @@ win_line( } #endif - screen_line(screen_row, wp->w_wincol, col, + screen_line(wp, screen_row, wp->w_wincol, col, wp->w_width, screen_line_flags); row++; @@ -3160,11 +3160,11 @@ win_line( ) { #ifdef FEAT_CONCEAL - screen_line(screen_row, wp->w_wincol, col - boguscols, + screen_line(wp, screen_row, wp->w_wincol, col - boguscols, wp->w_width, screen_line_flags); boguscols = 0; #else - screen_line(screen_row, wp->w_wincol, col, + screen_line(wp, screen_row, wp->w_wincol, col, wp->w_width, screen_line_flags); #endif ++row; diff --git a/src/drawscreen.c b/src/drawscreen.c --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -555,7 +555,7 @@ win_redr_status(win_T *wp, int ignore_pu if (stl_connected(wp)) fillchar = fillchar_status(&attr, wp); else - fillchar = fillchar_vsep(&attr); + fillchar = fillchar_vsep(&attr, wp); screen_putchar(fillchar, row, W_ENDCOL(wp), attr); } busy = FALSE; @@ -1038,7 +1038,7 @@ redraw_win_toolbar(win_T *wp) } wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker - screen_line(wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, 0); + screen_line(wp, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, 0); } #endif @@ -1246,7 +1246,8 @@ fold_line( txtcol = col; // remember where text starts - // 5. move the text to current_ScreenLine. Fill up with "fill_fold". + // 5. move the text to current_ScreenLine. Fill up with "fold" from + // 'fillchars'. // Right-left text is put in columns 0 - number-col, normal text is put // in columns number-col - window-width. col = text_to_screenline(wp, text, col); @@ -1262,23 +1263,25 @@ fold_line( #endif ) { + int c = wp->w_fill_chars.fold; + if (enc_utf8) { - if (fill_fold >= 0x80) + if (c >= 0x80) { - ScreenLinesUC[off + col] = fill_fold; + ScreenLinesUC[off + col] = c; ScreenLinesC[0][off + col] = 0; ScreenLines[off + col] = 0x80; // avoid storing zero } else { ScreenLinesUC[off + col] = 0; - ScreenLines[off + col] = fill_fold; + ScreenLines[off + col] = c; } col++; } else - ScreenLines[off + col++] = fill_fold; + ScreenLines[off + col++] = c; } if (text != buf) @@ -1371,7 +1374,8 @@ fold_line( } #endif - screen_line(row + W_WINROW(wp), wp->w_wincol, wp->w_width, wp->w_width, 0); + screen_line(wp, row + W_WINROW(wp), wp->w_wincol, + wp->w_width, wp->w_width, 0); // Update w_cline_height and w_cline_folded if the cursor line was // updated (saves a call to plines() later). @@ -2669,10 +2673,10 @@ win_update(win_T *wp) if (j > 0 && !wp->w_botfill) { // Display filler lines at the end of the file. - if (char2cells(fill_diff) > 1) + if (char2cells(wp->w_fill_chars.diff) > 1) i = '-'; else - i = fill_diff; + i = wp->w_fill_chars.diff; if (row + j > wp->w_height) j = wp->w_height - row; win_draw_end(wp, i, i, TRUE, row, row + (int)j, HLF_DED); @@ -2683,12 +2687,14 @@ win_update(win_T *wp) else if (dollar_vcol == -1) wp->w_botline = lnum; - // Make sure the rest of the screen is blank - // write the 'fill_eob' character to rows that aren't part of the file + // Make sure the rest of the screen is blank. + // write the "eob" character from 'fillchars' to rows that aren't part + // of the file. if (WIN_IS_POPUP(wp)) win_draw_end(wp, ' ', ' ', FALSE, row, wp->w_height, HLF_AT); else - win_draw_end(wp, fill_eob, ' ', FALSE, row, wp->w_height, HLF_EOB); + win_draw_end(wp, wp->w_fill_chars.eob, ' ', FALSE, + row, wp->w_height, HLF_EOB); } #ifdef SYN_TIME_LIMIT @@ -3026,7 +3032,7 @@ redraw_asap(int type) mch_memmove(ScreenLines2 + off, screenline2 + r * cols, (size_t)cols * sizeof(schar_T)); - screen_line(cmdline_row + r, 0, cols, cols, 0); + screen_line(curwin, cmdline_row + r, 0, cols, cols, 0); } ret = 4; } diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1380,17 +1380,6 @@ EXTERN char_u *homedir INIT(= NULL); // directory is not a local directory, globaldir is NULL. EXTERN char_u *globaldir INIT(= NULL); -// Characters from 'fillchars' option -EXTERN int fill_stl INIT(= ' '); -EXTERN int fill_stlnc INIT(= ' '); -EXTERN int fill_vert INIT(= ' '); -EXTERN int fill_fold INIT(= '-'); -EXTERN int fill_foldopen INIT(= '-'); -EXTERN int fill_foldclosed INIT(= '+'); -EXTERN int fill_foldsep INIT(= '|'); -EXTERN int fill_diff INIT(= '-'); -EXTERN int fill_eob INIT(= '~'); - #ifdef FEAT_FOLDING EXTERN int disable_fold_update INIT(= 0); #endif diff --git a/src/mbyte.c b/src/mbyte.c --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4229,8 +4229,7 @@ theend: #if defined(FEAT_GUI_GTK) || defined(FEAT_SPELL) || defined(PROTO) /* * Return TRUE if string "s" is a valid utf-8 string. - * When "end" is NULL stop at the first NUL. - * When "end" is positive stop there. + * When "end" is NULL stop at the first NUL. Otherwise stop at "end". */ int utf_valid_string(char_u *s, char_u *end) @@ -5529,6 +5528,7 @@ f_setcellwidths(typval_T *argvars, typva cw_interval_T *table; cw_interval_T *cw_table_save; size_t cw_table_size_save; + char *error = NULL; if (in_vim9script() && check_for_list_arg(argvars, 0) == FAIL) return; @@ -5648,30 +5648,36 @@ f_setcellwidths(typval_T *argvars, typva // Check that the new value does not conflict with 'fillchars' or // 'listchars'. if (set_chars_option(curwin, &p_fcs) != NULL) - { - emsg(_(e_conflicts_with_value_of_fillchars)); - cw_table = cw_table_save; - cw_table_size = cw_table_size_save; - vim_free(table); - return; - } + error = e_conflicts_with_value_of_fillchars; + else if (set_chars_option(curwin, &p_lcs) != NULL) + error = e_conflicts_with_value_of_listchars; else { - tabpage_T *tp; - win_T *wp; + tabpage_T *tp; + win_T *wp; FOR_ALL_TAB_WINDOWS(tp, wp) { if (set_chars_option(wp, &wp->w_p_lcs) != NULL) { - emsg((e_conflicts_with_value_of_listchars)); - cw_table = cw_table_save; - cw_table_size = cw_table_size_save; - vim_free(table); - return; + error = e_conflicts_with_value_of_listchars; + break; + } + if (set_chars_option(wp, &wp->w_p_fcs) != NULL) + { + error = e_conflicts_with_value_of_fillchars; + break; } } } + if (error != NULL) + { + emsg(_(error)); + cw_table = cw_table_save; + cw_table_size = cw_table_size_save; + vim_free(table); + return; + } vim_free(cw_table_save); } diff --git a/src/mouse.c b/src/mouse.c --- a/src/mouse.c +++ b/src/mouse.c @@ -2018,7 +2018,7 @@ retnomove: count |= CURSOR_MOVED; // Cursor has moved # ifdef FEAT_FOLDING - if (mouse_char == fill_foldclosed) + if (mouse_char == curwin->w_fill_chars.foldclosed) count |= MOUSE_FOLD_OPEN; else if (mouse_char != ' ') count |= MOUSE_FOLD_CLOSE; diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -2436,7 +2436,7 @@ didset_options2(void) (void)set_chars_option(curwin, &curwin->w_p_lcs); // Parse default for 'fillchars'. - (void)set_chars_option(curwin, &p_fcs); + (void)set_chars_option(curwin, &curwin->w_p_fcs); #ifdef FEAT_CLIPBOARD // Parse default for 'clipboard' @@ -5207,6 +5207,11 @@ unset_global_local_option(char_u *name, set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs); redraw_later(NOT_VALID); break; + case PV_FCS: + clear_string_option(&((win_T *)from)->w_p_fcs); + set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs); + redraw_later(NOT_VALID); + break; case PV_VE: clear_string_option(&((win_T *)from)->w_p_ve); ((win_T *)from)->w_ve_flags = 0; @@ -5272,6 +5277,7 @@ get_varp_scope(struct vimoption *p, int case PV_BKC: return (char_u *)&(curbuf->b_p_bkc); case PV_MENC: return (char_u *)&(curbuf->b_p_menc); case PV_LCS: return (char_u *)&(curwin->w_p_lcs); + case PV_FCS: return (char_u *)&(curwin->w_p_fcs); case PV_VE: return (char_u *)&(curwin->w_p_ve); } @@ -5375,6 +5381,8 @@ get_varp(struct vimoption *p) case PV_LIST: return (char_u *)&(curwin->w_p_list); case PV_LCS: return *curwin->w_p_lcs != NUL ? (char_u *)&(curwin->w_p_lcs) : p->var; + case PV_FCS: return *curwin->w_p_fcs != NUL + ? (char_u *)&(curwin->w_p_fcs) : p->var; case PV_VE: return *curwin->w_p_ve != NUL ? (char_u *)&(curwin->w_p_ve) : p->var; #ifdef FEAT_SPELL @@ -5600,6 +5608,15 @@ after_copy_winopt(win_T *wp) check_colorcolumn(wp); #endif set_chars_option(wp, &wp->w_p_lcs); + set_chars_option(wp, &wp->w_p_fcs); +} + + static char_u * +copy_option_val(char_u *val) +{ + if (val == empty_option) + return empty_option; // no need to allocate memory + return vim_strsave(val); } /* @@ -5615,23 +5632,24 @@ copy_winopt(winopt_T *from, winopt_T *to to->wo_arab = from->wo_arab; #endif to->wo_list = from->wo_list; - to->wo_lcs = vim_strsave(from->wo_lcs); + to->wo_lcs = copy_option_val(from->wo_lcs); + to->wo_fcs = copy_option_val(from->wo_fcs); to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; - to->wo_ve = vim_strsave(from->wo_ve); + to->wo_ve = copy_option_val(from->wo_ve); to->wo_ve_flags = from->wo_ve_flags; #ifdef FEAT_LINEBREAK to->wo_nuw = from->wo_nuw; #endif #ifdef FEAT_RIGHTLEFT to->wo_rl = from->wo_rl; - to->wo_rlc = vim_strsave(from->wo_rlc); + to->wo_rlc = copy_option_val(from->wo_rlc); #endif #ifdef FEAT_LINEBREAK - to->wo_sbr = vim_strsave(from->wo_sbr); + to->wo_sbr = copy_option_val(from->wo_sbr); #endif #ifdef FEAT_STL_OPT - to->wo_stl = vim_strsave(from->wo_stl); + to->wo_stl = copy_option_val(from->wo_stl); #endif to->wo_wrap = from->wo_wrap; #ifdef FEAT_DIFF @@ -5640,9 +5658,9 @@ copy_winopt(winopt_T *from, winopt_T *to #ifdef FEAT_LINEBREAK to->wo_lbr = from->wo_lbr; to->wo_bri = from->wo_bri; - to->wo_briopt = vim_strsave(from->wo_briopt); -#endif - to->wo_wcr = vim_strsave(from->wo_wcr); + to->wo_briopt = copy_option_val(from->wo_briopt); +#endif + to->wo_wcr = copy_option_val(from->wo_wcr); to->wo_scb = from->wo_scb; to->wo_scb_save = from->wo_scb_save; to->wo_crb = from->wo_crb; @@ -5653,42 +5671,42 @@ copy_winopt(winopt_T *from, winopt_T *to #ifdef FEAT_SYN_HL to->wo_cuc = from->wo_cuc; to->wo_cul = from->wo_cul; - to->wo_culopt = vim_strsave(from->wo_culopt); - to->wo_cc = vim_strsave(from->wo_cc); + to->wo_culopt = copy_option_val(from->wo_culopt); + to->wo_cc = copy_option_val(from->wo_cc); #endif #ifdef FEAT_DIFF to->wo_diff = from->wo_diff; to->wo_diff_saved = from->wo_diff_saved; #endif #ifdef FEAT_CONCEAL - to->wo_cocu = vim_strsave(from->wo_cocu); + to->wo_cocu = copy_option_val(from->wo_cocu); to->wo_cole = from->wo_cole; #endif #ifdef FEAT_TERMINAL - to->wo_twk = vim_strsave(from->wo_twk); - to->wo_tws = vim_strsave(from->wo_tws); + to->wo_twk = copy_option_val(from->wo_twk); + to->wo_tws = copy_option_val(from->wo_tws); #endif #ifdef FEAT_FOLDING to->wo_fdc = from->wo_fdc; to->wo_fdc_save = from->wo_fdc_save; to->wo_fen = from->wo_fen; to->wo_fen_save = from->wo_fen_save; - to->wo_fdi = vim_strsave(from->wo_fdi); + to->wo_fdi = copy_option_val(from->wo_fdi); to->wo_fml = from->wo_fml; to->wo_fdl = from->wo_fdl; to->wo_fdl_save = from->wo_fdl_save; - to->wo_fdm = vim_strsave(from->wo_fdm); + to->wo_fdm = copy_option_val(from->wo_fdm); to->wo_fdm_save = from->wo_diff_saved - ? vim_strsave(from->wo_fdm_save) : empty_option; + ? vim_strsave(from->wo_fdm_save) : empty_option; to->wo_fdn = from->wo_fdn; # ifdef FEAT_EVAL - to->wo_fde = vim_strsave(from->wo_fde); - to->wo_fdt = vim_strsave(from->wo_fdt); + to->wo_fde = copy_option_val(from->wo_fde); + to->wo_fdt = copy_option_val(from->wo_fdt); # endif - to->wo_fmr = vim_strsave(from->wo_fmr); + to->wo_fmr = copy_option_val(from->wo_fmr); #endif #ifdef FEAT_SIGNS - to->wo_scl = vim_strsave(from->wo_scl); + to->wo_scl = copy_option_val(from->wo_scl); #endif #ifdef FEAT_EVAL @@ -5753,6 +5771,7 @@ check_winopt(winopt_T *wop UNUSED) #endif check_string_option(&wop->wo_wcr); check_string_option(&wop->wo_lcs); + check_string_option(&wop->wo_fcs); check_string_option(&wop->wo_ve); } @@ -5800,6 +5819,7 @@ clear_winopt(winopt_T *wop UNUSED) clear_string_option(&wop->wo_tws); #endif clear_string_option(&wop->wo_lcs); + clear_string_option(&wop->wo_fcs); clear_string_option(&wop->wo_ve); } diff --git a/src/option.h b/src/option.h --- a/src/option.h +++ b/src/option.h @@ -1238,6 +1238,7 @@ enum { WV_LIST = 0 , WV_LCS + , WV_FCS #ifdef FEAT_ARABIC , WV_ARAB #endif diff --git a/src/optiondefs.h b/src/optiondefs.h --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -182,6 +182,7 @@ # define PV_LBR OPT_WIN(WV_LBR) #endif #define PV_LCS OPT_BOTH(OPT_WIN(WV_LCS)) +#define PV_FCS OPT_BOTH(OPT_WIN(WV_FCS)) #define PV_NU OPT_WIN(WV_NU) #define PV_RNU OPT_WIN(WV_RNU) #define PV_VE OPT_BOTH(OPT_WIN(WV_VE)) @@ -947,7 +948,7 @@ static struct vimoption options[] = {(char_u *)"", (char_u *)0L} SCTX_INIT}, {"fillchars", "fcs", P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP, - (char_u *)&p_fcs, PV_NONE, + (char_u *)&p_fcs, PV_FCS, {(char_u *)"vert:|,fold:-,eob:~", (char_u *)0L} SCTX_INIT}, {"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT, diff --git a/src/optionstr.c b/src/optionstr.c --- a/src/optionstr.c +++ b/src/optionstr.c @@ -1311,7 +1311,7 @@ ambw_end: if (errmsg == NULL) { tabpage_T *tp; - win_T *wp; + win_T *wp; // The current window is set to use the global 'listchars' value. // So clear the window-local value. @@ -1320,12 +1320,12 @@ ambw_end: FOR_ALL_TAB_WINDOWS(tp, wp) // If no error was returned above, we don't expect an error // here, so ignore the return value. - (void)set_chars_option(wp, &wp->w_p_lcs); + if (*wp->w_p_lcs == NUL) + (void)set_chars_option(wp, &wp->w_p_lcs); redraw_all_later(NOT_VALID); } } - // local 'listchars' else if (varp == &curwin->w_p_lcs) errmsg = set_chars_option(curwin, varp); @@ -1334,6 +1334,28 @@ ambw_end: else if (varp == &p_fcs) { errmsg = set_chars_option(curwin, varp); + if (errmsg == NULL) + { + tabpage_T *tp; + win_T *wp; + + // The current window is set to use the global 'fillchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) + clear_string_option(&curwin->w_p_fcs); + FOR_ALL_TAB_WINDOWS(tp, wp) + // If no error was returned above, we don't expect an error + // here, so ignore the return value. + if (*wp->w_p_fcs == NUL) + (void)set_chars_option(wp, &wp->w_p_fcs); + + redraw_all_later(NOT_VALID); + } + } + // local 'fillchars' + else if (varp == &curwin->w_p_fcs) + { + errmsg = set_chars_option(curwin, varp); } #ifdef FEAT_CMDWIN diff --git a/src/proto/screen.pro b/src/proto/screen.pro --- a/src/proto/screen.pro +++ b/src/proto/screen.pro @@ -7,7 +7,7 @@ int compute_foldcolumn(win_T *wp, int co size_t fill_foldcolumn(char_u *p, win_T *wp, int closed, linenr_T lnum); int screen_get_current_line_off(void); void reset_screen_attr(void); -void screen_line(int row, int coloff, int endcol, int clear_width, int flags); +void screen_line(win_T *wp, int row, int coloff, int endcol, int clear_width, int flags); void rl_mirror(char_u *str); void draw_vsep_win(win_T *wp, int row); void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match, int showtail); @@ -48,7 +48,7 @@ void clearmode(void); void draw_tabline(void); void get_trans_bufname(buf_T *buf); int fillchar_status(int *attr, win_T *wp); -int fillchar_vsep(int *attr); +int fillchar_vsep(int *attr, win_T *wp); int redrawing(void); int messaging(void); void comp_col(void); diff --git a/src/screen.c b/src/screen.c --- a/src/screen.c +++ b/src/screen.c @@ -285,9 +285,9 @@ fill_foldcolumn( { if (win_foldinfo.fi_lnum == lnum && first_level + i >= win_foldinfo.fi_low_level) - symbol = fill_foldopen; + symbol = wp->w_fill_chars.foldopen; else if (first_level == 1) - symbol = fill_foldsep; + symbol = wp->w_fill_chars.foldsep; else if (first_level + i <= 9) symbol = '0' + first_level + i; else @@ -312,7 +312,7 @@ fill_foldcolumn( // for a multibyte character, erase all the bytes vim_memset(p + byte_counter, ' ', len); } - symbol = fill_foldclosed; + symbol = wp->w_fill_chars.foldclosed; len = utf_char2bytes(symbol, &p[byte_counter]); byte_counter += len; } @@ -430,11 +430,12 @@ reset_screen_attr(void) */ void screen_line( - int row, - int coloff, - int endcol, - int clear_width, - int flags UNUSED) + win_T *wp, + int row, + int coloff, + int endcol, + int clear_width, + int flags UNUSED) { unsigned off_from; unsigned off_to; @@ -794,7 +795,7 @@ screen_line( { int c; - c = fillchar_vsep(&hl); + c = fillchar_vsep(&hl, wp); if (ScreenLines[off_to] != (schar_T)c || (enc_utf8 && (int)ScreenLinesUC[off_to] != (c >= 0x80 ? c : 0)) @@ -853,7 +854,7 @@ draw_vsep_win(win_T *wp, int row) if (wp->w_vsep_width) { // draw the vertical separator right of this window - c = fillchar_vsep(&hl); + c = fillchar_vsep(&hl, wp); screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height, W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl); @@ -4619,12 +4620,12 @@ fillchar_status(int *attr, win_T *wp) if (wp == curwin) { *attr = HL_ATTR(HLF_ST); - fill = fill_stl; + fill = wp->w_fill_chars.stl; } else { *attr = HL_ATTR(HLF_STNC); - fill = fill_stlnc; + fill = wp->w_fill_chars.stlnc; } } else @@ -4632,19 +4633,19 @@ fillchar_status(int *attr, win_T *wp) if (wp == curwin) { *attr = HL_ATTR(HLF_S); - fill = fill_stl; + fill = wp->w_fill_chars.stl; } else { *attr = HL_ATTR(HLF_SNC); - fill = fill_stlnc; + fill = wp->w_fill_chars.stlnc; } // Use fill when there is highlighting, and highlighting of current // window differs, or the fillchars differ, or this is not the // current window if (*attr != 0 && ((HL_ATTR(HLF_S) != HL_ATTR(HLF_SNC) || wp != curwin || ONE_WINDOW) - || (fill_stl != fill_stlnc))) + || (wp->w_fill_chars.stl != wp->w_fill_chars.stlnc))) return fill; if (wp == curwin) return '^'; @@ -4656,13 +4657,13 @@ fillchar_status(int *attr, win_T *wp) * Get its attributes in "*attr". */ int -fillchar_vsep(int *attr) +fillchar_vsep(int *attr, win_T *wp) { *attr = HL_ATTR(HLF_C); - if (*attr == 0 && fill_vert == ' ') + if (*attr == 0 && wp->w_fill_chars.vert == ' ') return '|'; else - return fill_vert; + return wp->w_fill_chars.vert; } /* @@ -4848,29 +4849,30 @@ get_encoded_char_adv(char_u **p) char * set_chars_option(win_T *wp, char_u **varp) { - int round, i, len, len2, entries; - char_u *p, *s; - int c1 = 0, c2 = 0, c3 = 0; - char_u *last_multispace = NULL; // Last occurrence of "multispace:" - char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" - int multispace_len = 0; // Length of lcs-multispace string - int lead_multispace_len = 0; // Length of lcs-leadmultispace string + int round, i, len, len2, entries; + char_u *p, *s; + int c1 = 0, c2 = 0, c3 = 0; + char_u *last_multispace = NULL; // Last occurrence of "multispace:" + char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" + int multispace_len = 0; // Length of lcs-multispace string + int lead_multispace_len = 0; // Length of lcs-leadmultispace string struct charstab { int *cp; char *name; }; + static fill_chars_T fill_chars; static struct charstab filltab[] = { - {&fill_stl, "stl"}, - {&fill_stlnc, "stlnc"}, - {&fill_vert, "vert"}, - {&fill_fold, "fold"}, - {&fill_foldopen, "foldopen"}, - {&fill_foldclosed, "foldclose"}, - {&fill_foldsep, "foldsep"}, - {&fill_diff, "diff"}, - {&fill_eob, "eob"}, + {&fill_chars.stl, "stl"}, + {&fill_chars.stlnc, "stlnc"}, + {&fill_chars.vert, "vert"}, + {&fill_chars.fold, "fold"}, + {&fill_chars.foldopen, "foldopen"}, + {&fill_chars.foldclosed, "foldclose"}, + {&fill_chars.foldsep, "foldsep"}, + {&fill_chars.diff, "diff"}, + {&fill_chars.eob, "eob"}, }; static lcs_chars_T lcs_chars; struct charstab lcstab[] = @@ -4903,6 +4905,8 @@ set_chars_option(win_T *wp, char_u **var { tab = filltab; entries = ARRAY_LENGTH(filltab); + if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) + varp = &p_fcs; } // first round: check for valid value, second round: assign values @@ -4910,15 +4914,12 @@ set_chars_option(win_T *wp, char_u **var { if (round > 0) { - // After checking that the value is valid: set defaults: space for - // 'fillchars', NUL for 'listchars' - for (i = 0; i < entries; ++i) - if (tab[i].cp != NULL) - *(tab[i].cp) = - ((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' '); - + // After checking that the value is valid: set defaults. if (varp == &p_lcs || varp == &wp->w_p_lcs) { + for (i = 0; i < entries; ++i) + if (tab[i].cp != NULL) + *(tab[i].cp) = NUL; lcs_chars.tab1 = NUL; lcs_chars.tab3 = NUL; @@ -4932,7 +4933,8 @@ set_chars_option(win_T *wp, char_u **var if (lead_multispace_len > 0) { - lcs_chars.leadmultispace = ALLOC_MULT(int, lead_multispace_len + 1); + lcs_chars.leadmultispace = + ALLOC_MULT(int, lead_multispace_len + 1); lcs_chars.leadmultispace[lead_multispace_len] = NUL; } else @@ -4940,11 +4942,15 @@ set_chars_option(win_T *wp, char_u **var } else { - fill_diff = '-'; - fill_foldopen = '-'; - fill_foldclosed = '+'; - fill_foldsep = '|'; - fill_eob = '~'; + fill_chars.stl = ' '; + fill_chars.stlnc = ' '; + fill_chars.vert = ' '; + fill_chars.fold = '-'; + fill_chars.foldopen = '-'; + fill_chars.foldclosed = '+'; + fill_chars.foldsep = '|'; + fill_chars.diff = '-'; + fill_chars.eob = '~'; } } p = *varp; @@ -5083,12 +5089,17 @@ set_chars_option(win_T *wp, char_u **var ++p; } } + if (tab == lcstab) { vim_free(wp->w_lcs_chars.multispace); vim_free(wp->w_lcs_chars.leadmultispace); wp->w_lcs_chars = lcs_chars; } + else + { + wp->w_fill_chars = fill_chars; + } return NULL; // no error } diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -232,6 +232,8 @@ typedef struct #define w_p_list w_onebuf_opt.wo_list // 'list' char_u *wo_lcs; #define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars' + char_u *wo_fcs; +#define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars' int wo_nu; #define w_p_nu w_onebuf_opt.wo_nu // 'number' int wo_rnu; @@ -3419,6 +3421,22 @@ typedef struct } lcs_chars_T; /* + * Characters from the 'fillchars' option + */ +typedef struct +{ + int stl; + int stlnc; + int vert; + int fold; + int foldopen; + int foldclosed; + int foldsep; + int diff; + int eob; +} fill_chars_T; + +/* * Structure which contains all information that belongs to a window * * All row numbers are relative to the start of the window, except w_winrow. @@ -3470,6 +3488,7 @@ struct window_S // redrawn lcs_chars_T w_lcs_chars; // 'listchars' characters + fill_chars_T w_fill_chars; // 'fillchars' characters /* * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for diff --git a/src/testdir/dumps/Test_display_fillchars_1.dump b/src/testdir/dumps/Test_display_fillchars_1.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_display_fillchars_1.dump @@ -0,0 +1,12 @@ +|w+0&#ffffff0|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|w|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|w|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|y+0#4040ff13&| @35|++1#0000000&|x+0#4040ff13&| @35 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]|b@5|1|,|1|b@11|A|l@1|b|[|N|o| |N|a|m|e|]| |[|+|]|a@5|1|,|1|a@11|A|l@1 +>w+0&&|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|w|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|w|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|o+0#4040ff13&| @35|>+1#0000000&|z+0#4040ff13&| @35 +|o| @35|>+1#0000000&|z+0#4040ff13&| @35 +|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]|4@5|1|,|1|4@11|A|l@1|4|[+1&&|N|o| |N|a|m|e|]| |[|+|]|c@5|1|,|1|c@11|A|l@1 +| +0&&@74 diff --git a/src/testdir/dumps/Test_display_fillchars_2.dump b/src/testdir/dumps/Test_display_fillchars_2.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_display_fillchars_2.dump @@ -0,0 +1,12 @@ +>w+0&#ffffff0|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|w|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|w|i|n|d|o|w| |2| @28|++1&&|w+0&&|i|n|d|o|w| |1| @28 +|y+0#4040ff13&| @35|++1#0000000&|x+0#4040ff13&| @35 +|[+3#0000000&|N|o| |N|a|m|e|]| |[|+|]|2@5|1|,|1|2@11|A|l@1|2|[+1&&|N|o| |N|a|m|e|]| |[|+|]|a@5|1|,|1|a@11|A|l@1 +|w+0&&|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|w|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|w|i|n|d|o|w| |4| @28|>+1&&|w+0&&|i|n|d|o|w| |3| @28 +|o+0#4040ff13&| @35|>+1#0000000&|z+0#4040ff13&| @35 +|o| @35|>+1#0000000&|z+0#4040ff13&| @35 +|[+1#0000000&|N|o| |N|a|m|e|]| |[|+|]|d@5|1|,|1|d@11|A|l@1|d|[|N|o| |N|a|m|e|]| |[|+|]|c@5|1|,|1|c@11|A|l@1 +|:+0&&|w|i|n|c|m|d| |k| @65 diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -481,7 +481,7 @@ for g:testfunc in sort(s:tests) call add(total_errors, 'Run ' . g:run_nr . ':') call extend(total_errors, v:errors) - if g:run_nr == 5 || prev_error == v:errors[0] + if g:run_nr >= 5 || prev_error == v:errors[0] call add(total_errors, 'Flaky test failed too often, giving up') let v:errors = total_errors break diff --git a/src/testdir/screendump.vim b/src/testdir/screendump.vim --- a/src/testdir/screendump.vim +++ b/src/testdir/screendump.vim @@ -75,6 +75,8 @@ func VerifyScreenDump(buf, filename, opt endif else let msg = 'See new dump file: call term_dumpload("testdir/' .. testfile .. '")' + " no point in retrying + let g:run_nr = 10 endif for i in range(len(refdump)) if i >= len(testdump) diff --git a/src/testdir/test_display.vim b/src/testdir/test_display.vim --- a/src/testdir/test_display.vim +++ b/src/testdir/test_display.vim @@ -356,6 +356,34 @@ func Test_fold_fillchars() set fillchars& fdc& foldmethod& foldenable& endfunc +func Test_local_fillchars() + CheckScreendump + + let lines =<< trim END + call setline(1, ['window 1']->repeat(3)) + setlocal fillchars=stl:1,stlnc:a,vert:=,eob:x + vnew + call setline(1, ['window 2']->repeat(3)) + setlocal fillchars=stl:2,stlnc:b,vert:+,eob:y + new + wincmd J + call setline(1, ['window 3']->repeat(3)) + setlocal fillchars=stl:3,stlnc:c,vert:<,eob:z + vnew + call setline(1, ['window 4']->repeat(3)) + setlocal fillchars=stl:4,stlnc:d,vert:>,eob:o + END + call writefile(lines, 'Xdisplayfillchars') + let buf = RunVimInTerminal('-S Xdisplayfillchars', #{rows: 12}) + call VerifyScreenDump(buf, 'Test_display_fillchars_1', {}) + + call term_sendkeys(buf, ":wincmd k\r") + call VerifyScreenDump(buf, 'Test_display_fillchars_2', {}) + + call StopVimInTerminal(buf) + call delete('Xdisplayfillchars') +endfunc + func Test_display_linebreak_breakat() new vert resize 25 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -736,6 +736,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 36, +/**/ 35, /**/ 34,