Merge pull request #19953 from zeertzjq/vim-9.0.0036

vim-patch:8.2.2524,9.0.(0036,0037,0038,0040}
This commit is contained in:
zeertzjq 2022-08-26 10:46:18 +08:00 committed by GitHub
commit 946c0aa66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 213 additions and 129 deletions

View File

@ -2454,28 +2454,30 @@ A jump table for the options with a short description can be found at |Q_op|.
*'fillchars'* *'fcs'* *'fillchars'* *'fcs'*
'fillchars' 'fcs' string (default "") 'fillchars' 'fcs' string (default "")
global or local to window |global-local| global or local to window |global-local|
Characters to fill the statuslines and vertical separators. Characters to fill the statuslines, vertical separators and special
It is a comma-separated list of items: 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 default Used for ~ item default Used for ~
stl:c ' ' or '^' statusline of the current window stl ' ' or '^' statusline of the current window
stlnc:c ' ' or '=' statusline of the non-current windows stlnc ' ' or '=' statusline of the non-current windows
wbr:c ' ' window bar wbr ' ' window bar
horiz:c '─' or '-' horizontal separators |:split| horiz '─' or '-' horizontal separators |:split|
horizup:c '┴' or '-' upwards facing horizontal separator horizup '┴' or '-' upwards facing horizontal separator
horizdown:c '┬' or '-' downwards facing horizontal separator horizdown '┬' or '-' downwards facing horizontal separator
vert:c '│' or '|' vertical separators |:vsplit| vert '│' or '|' vertical separators |:vsplit|
vertleft:c '┤' or '|' left facing vertical separator vertleft '┤' or '|' left facing vertical separator
vertright:c '├' or '|' right facing vertical separator vertright '├' or '|' right facing vertical separator
verthoriz:c '┼' or '+' overlapping vertical and horizontal verthoriz '┼' or '+' overlapping vertical and horizontal
separator separator
fold:c '·' or '-' filling 'foldtext' fold '·' or '-' filling 'foldtext'
foldopen:c '-' mark the beginning of a fold foldopen '-' mark the beginning of a fold
foldclose:c '+' show a closed fold foldclose '+' show a closed fold
foldsep:c '│' or '|' open fold middle marker foldsep '│' or '|' open fold middle marker
diff:c '-' deleted lines of the 'diff' option diff '-' deleted lines of the 'diff' option
msgsep:c ' ' message separator 'display' msgsep ' ' message separator 'display'
eob:c '~' empty lines at the end of a buffer eob '~' empty lines at the end of a buffer
Any one that is omitted will fall back to the default. For "stl" and 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 '=' "stlnc" the space will be used when there is highlighting, '^' or '='
@ -2500,19 +2502,19 @@ A jump table for the options with a short description can be found at |Q_op|.
The highlighting used for these items: The highlighting used for these items:
item highlight group ~ item highlight group ~
stl:c StatusLine |hl-StatusLine| stl StatusLine |hl-StatusLine|
stlnc:c StatusLineNC |hl-StatusLineNC| stlnc StatusLineNC |hl-StatusLineNC|
wbr:c WinBar |hl-WinBar| or |hl-WinBarNC| wbr WinBar |hl-WinBar| or |hl-WinBarNC|
horiz:c WinSeparator |hl-WinSeparator| horiz WinSeparator |hl-WinSeparator|
horizup:c WinSeparator |hl-WinSeparator| horizup WinSeparator |hl-WinSeparator|
horizdown:c WinSeparator |hl-WinSeparator| horizdown WinSeparator |hl-WinSeparator|
vert:c WinSeparator |hl-WinSeparator| vert WinSeparator |hl-WinSeparator|
vertleft:c WinSeparator |hl-WinSeparator| vertleft WinSeparator |hl-WinSeparator|
vertright:c WinSeparator |hl-WinSeparator| vertright WinSeparator |hl-WinSeparator|
verthoriz:c WinSeparator |hl-WinSeparator| verthoriz WinSeparator |hl-WinSeparator|
fold:c Folded |hl-Folded| fold Folded |hl-Folded|
diff:c DiffDelete |hl-DiffDelete| diff DiffDelete |hl-DiffDelete|
eob:c EndOfBuffer |hl-EndOfBuffer| eob EndOfBuffer |hl-EndOfBuffer|
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'* *'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on) 'fixendofline' 'fixeol' boolean (default on)

View File

@ -257,10 +257,10 @@ typedef struct {
#define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn' #define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn'
char *wo_winhl; char *wo_winhl;
#define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight' #define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight'
char *wo_fcs;
#define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars'
char *wo_lcs; char *wo_lcs;
#define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars' #define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars'
char *wo_fcs;
#define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars'
long wo_winbl; long wo_winbl;
#define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend' #define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'

View File

@ -1655,7 +1655,7 @@ int hex2nr(int c)
/// Convert two hex characters to a byte. /// Convert two hex characters to a byte.
/// Return -1 if one of the characters is not hex. /// Return -1 if one of the characters is not hex.
int hexhex2nr(char_u *p) int hexhex2nr(const char_u *p)
FUNC_ATTR_PURE FUNC_ATTR_PURE
{ {
if (!ascii_isxdigit(p[0]) || !ascii_isxdigit(p[1])) { if (!ascii_isxdigit(p[0]) || !ascii_isxdigit(p[1])) {

View File

@ -1247,7 +1247,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
} }
char_attr = 0; char_attr = 0;
} else if (filler_todo > 0) { } else if (filler_todo > 0) {
// draw "deleted" diff line(s) // Draw "deleted" diff line(s)
if (char2cells(wp->w_p_fcs_chars.diff) > 1) { if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
c_extra = '-'; c_extra = '-';
c_final = NUL; c_final = NUL;

View File

@ -1920,8 +1920,9 @@ win_update_start:
wp->w_botline = lnum; wp->w_botline = lnum;
} }
// make sure the rest of the screen is blank // Make sure the rest of the screen is blank.
// write the 'eob' character to rows that aren't part of the file. // write the "eob" character from 'fillchars' to rows that aren't part
// of the file.
win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows, win_draw_end(wp, wp->w_p_fcs_chars.eob, ' ', false, row, wp->w_grid.rows,
HLF_EOB); HLF_EOB);
} }

View File

@ -1989,8 +1989,7 @@ theend:
} }
/// @return true if string "s" is a valid utf-8 string. /// @return true if string "s" is a valid utf-8 string.
/// When "end" is NULL stop at the first NUL. /// When "end" is NULL stop at the first NUL. Otherwise stop at "end".
/// When "end" is positive stop there.
bool utf_valid_string(const char_u *s, const char_u *end) bool utf_valid_string(const char_u *s, const char_u *end)
{ {
const char_u *p = s; const char_u *p = s;

View File

@ -4250,6 +4250,14 @@ void win_copy_options(win_T *wp_from, win_T *wp_to)
didset_window_options(wp_to, true); didset_window_options(wp_to, true);
} }
static char *copy_option_val(const char *val)
{
if (val == empty_option) {
return empty_option; // no need to allocate memory
}
return xstrdup(val);
}
/// Copy the options from one winopt_T to another. /// Copy the options from one winopt_T to another.
/// Doesn't free the old option values in "to", use clear_winopt() for that. /// Doesn't free the old option values in "to", use clear_winopt() for that.
/// The 'scroll' option is not copied, because it depends on the window height. /// The 'scroll' option is not copied, because it depends on the window height.
@ -4258,21 +4266,23 @@ void copy_winopt(winopt_T *from, winopt_T *to)
{ {
to->wo_arab = from->wo_arab; to->wo_arab = from->wo_arab;
to->wo_list = from->wo_list; to->wo_list = from->wo_list;
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_nu = from->wo_nu;
to->wo_rnu = from->wo_rnu; to->wo_rnu = from->wo_rnu;
to->wo_ve = xstrdup(from->wo_ve); to->wo_ve = copy_option_val(from->wo_ve);
to->wo_ve_flags = from->wo_ve_flags; to->wo_ve_flags = from->wo_ve_flags;
to->wo_nuw = from->wo_nuw; to->wo_nuw = from->wo_nuw;
to->wo_rl = from->wo_rl; to->wo_rl = from->wo_rl;
to->wo_rlc = xstrdup(from->wo_rlc); to->wo_rlc = copy_option_val(from->wo_rlc);
to->wo_sbr = xstrdup(from->wo_sbr); to->wo_sbr = copy_option_val(from->wo_sbr);
to->wo_stl = xstrdup(from->wo_stl); to->wo_stl = copy_option_val(from->wo_stl);
to->wo_wbr = xstrdup(from->wo_wbr); to->wo_wbr = copy_option_val(from->wo_wbr);
to->wo_wrap = from->wo_wrap; to->wo_wrap = from->wo_wrap;
to->wo_wrap_save = from->wo_wrap_save; to->wo_wrap_save = from->wo_wrap_save;
to->wo_lbr = from->wo_lbr; to->wo_lbr = from->wo_lbr;
to->wo_bri = from->wo_bri; to->wo_bri = from->wo_bri;
to->wo_briopt = xstrdup(from->wo_briopt); to->wo_briopt = copy_option_val(from->wo_briopt);
to->wo_scb = from->wo_scb; to->wo_scb = from->wo_scb;
to->wo_scb_save = from->wo_scb_save; to->wo_scb_save = from->wo_scb_save;
to->wo_crb = from->wo_crb; to->wo_crb = from->wo_crb;
@ -4280,30 +4290,28 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_spell = from->wo_spell; to->wo_spell = from->wo_spell;
to->wo_cuc = from->wo_cuc; to->wo_cuc = from->wo_cuc;
to->wo_cul = from->wo_cul; to->wo_cul = from->wo_cul;
to->wo_culopt = xstrdup(from->wo_culopt); to->wo_culopt = copy_option_val(from->wo_culopt);
to->wo_cc = xstrdup(from->wo_cc); to->wo_cc = copy_option_val(from->wo_cc);
to->wo_diff = from->wo_diff; to->wo_diff = from->wo_diff;
to->wo_diff_saved = from->wo_diff_saved; to->wo_diff_saved = from->wo_diff_saved;
to->wo_cocu = xstrdup(from->wo_cocu); to->wo_cocu = copy_option_val(from->wo_cocu);
to->wo_cole = from->wo_cole; to->wo_cole = from->wo_cole;
to->wo_fdc = xstrdup(from->wo_fdc); to->wo_fdc = copy_option_val(from->wo_fdc);
to->wo_fdc_save = from->wo_diff_saved ? xstrdup(from->wo_fdc_save) : empty_option; to->wo_fdc_save = from->wo_diff_saved ? xstrdup(from->wo_fdc_save) : empty_option;
to->wo_fen = from->wo_fen; to->wo_fen = from->wo_fen;
to->wo_fen_save = from->wo_fen_save; to->wo_fen_save = from->wo_fen_save;
to->wo_fdi = xstrdup(from->wo_fdi); to->wo_fdi = copy_option_val(from->wo_fdi);
to->wo_fml = from->wo_fml; to->wo_fml = from->wo_fml;
to->wo_fdl = from->wo_fdl; to->wo_fdl = from->wo_fdl;
to->wo_fdl_save = from->wo_fdl_save; to->wo_fdl_save = from->wo_fdl_save;
to->wo_fdm = xstrdup(from->wo_fdm); to->wo_fdm = copy_option_val(from->wo_fdm);
to->wo_fdm_save = from->wo_diff_saved ? xstrdup(from->wo_fdm_save) : empty_option; to->wo_fdm_save = from->wo_diff_saved ? xstrdup(from->wo_fdm_save) : empty_option;
to->wo_fdn = from->wo_fdn; to->wo_fdn = from->wo_fdn;
to->wo_fde = xstrdup(from->wo_fde); to->wo_fde = copy_option_val(from->wo_fde);
to->wo_fdt = xstrdup(from->wo_fdt); to->wo_fdt = copy_option_val(from->wo_fdt);
to->wo_fmr = xstrdup(from->wo_fmr); to->wo_fmr = copy_option_val(from->wo_fmr);
to->wo_scl = xstrdup(from->wo_scl); to->wo_scl = copy_option_val(from->wo_scl);
to->wo_winhl = xstrdup(from->wo_winhl); to->wo_winhl = copy_option_val(from->wo_winhl);
to->wo_fcs = xstrdup(from->wo_fcs);
to->wo_lcs = xstrdup(from->wo_lcs);
to->wo_winbl = from->wo_winbl; to->wo_winbl = from->wo_winbl;
// Copy the script context so that we know were the value was last set. // Copy the script context so that we know were the value was last set.
@ -4338,8 +4346,8 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_cocu); check_string_option(&wop->wo_cocu);
check_string_option(&wop->wo_briopt); check_string_option(&wop->wo_briopt);
check_string_option(&wop->wo_winhl); check_string_option(&wop->wo_winhl);
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_lcs); check_string_option(&wop->wo_lcs);
check_string_option(&wop->wo_fcs);
check_string_option(&wop->wo_ve); check_string_option(&wop->wo_ve);
check_string_option(&wop->wo_wbr); check_string_option(&wop->wo_wbr);
} }
@ -4364,8 +4372,8 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_cocu); clear_string_option(&wop->wo_cocu);
clear_string_option(&wop->wo_briopt); clear_string_option(&wop->wo_briopt);
clear_string_option(&wop->wo_winhl); clear_string_option(&wop->wo_winhl);
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_lcs); clear_string_option(&wop->wo_lcs);
clear_string_option(&wop->wo_fcs);
clear_string_option(&wop->wo_ve); clear_string_option(&wop->wo_ve);
clear_string_option(&wop->wo_wbr); clear_string_option(&wop->wo_wbr);
} }

View File

@ -972,8 +972,8 @@ enum {
WV_WRAP, WV_WRAP,
WV_SCL, WV_SCL,
WV_WINHL, WV_WINHL,
WV_FCS,
WV_LCS, WV_LCS,
WV_FCS,
WV_WINBL, WV_WINBL,
WV_WBR, WV_WBR,
WV_COUNT, // must be the last one WV_COUNT, // must be the last one

View File

@ -949,38 +949,30 @@ char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *er
} }
s = (char *)skip_to_option_part((char_u *)s); s = (char *)skip_to_option_part((char_u *)s);
} }
} else if (varp == &p_lcs) { // global 'listchars' } else if (varp == &p_lcs || varp == &p_fcs) { // global 'listchars' or 'fillchars'
errmsg = set_chars_option(curwin, varp, false); char **local_ptr = varp == &p_lcs ? &curwin->w_p_lcs : &curwin->w_p_fcs;
// only apply the global value to "curwin" when it does not have a local value
errmsg = set_chars_option(curwin, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
if (errmsg == NULL) { if (errmsg == NULL) {
// The current window is set to use the global 'listchars' value. // If the current window is set to use the global
// So clear the window-local value. // 'listchars'/'fillchars' value, clear the window-local value.
if (!(opt_flags & OPT_GLOBAL)) { if (!(opt_flags & OPT_GLOBAL)) {
clear_string_option(&curwin->w_p_lcs); clear_string_option(local_ptr);
} }
FOR_ALL_TAB_WINDOWS(tp, wp) { FOR_ALL_TAB_WINDOWS(tp, wp) {
// If the current window has a local value need to apply it
// again, it was changed when setting the global value.
// If no error was returned above, we don't expect an error // If no error was returned above, we don't expect an error
// here, so ignore the return value. // here, so ignore the return value.
(void)set_chars_option(wp, (char_u **)&wp->w_p_lcs, true); local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs;
if (**local_ptr == NUL) {
(void)set_chars_option(wp, (char_u **)local_ptr, true);
}
} }
redraw_all_later(UPD_NOT_VALID); redraw_all_later(UPD_NOT_VALID);
} }
} else if (varp == (char_u **)&curwin->w_p_lcs) { // local 'listchars' } else if (varp == (char_u **)&curwin->w_p_lcs) { // local 'listchars'
errmsg = set_chars_option(curwin, varp, true); errmsg = set_chars_option(curwin, varp, true);
} else if (varp == &p_fcs) { // global 'fillchars'
errmsg = set_chars_option(curwin, varp, false);
if (errmsg == NULL) {
// 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.
(void)set_chars_option(wp, (char_u **)&wp->w_p_fcs, true);
}
redraw_all_later(UPD_NOT_VALID);
}
} else if (varp == (char_u **)&curwin->w_p_fcs) { // local 'fillchars' } else if (varp == (char_u **)&curwin->w_p_fcs) { // local 'fillchars'
errmsg = set_chars_option(curwin, varp, true); errmsg = set_chars_option(curwin, varp, true);
} else if (varp == &p_cedit) { // 'cedit' } else if (varp == &p_cedit) { // 'cedit'

View File

@ -1262,17 +1262,15 @@ int number_width(win_T *wp)
/// Calls mb_cptr2char_adv(p) and returns the character. /// Calls mb_cptr2char_adv(p) and returns the character.
/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used. /// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
/// Returns 0 for invalid hex or invalid UTF-8 byte. /// Returns 0 for invalid hex or invalid UTF-8 byte.
static int get_encoded_char_adv(char_u **p) static int get_encoded_char_adv(const char_u **p)
{ {
char_u *s = *p; const char_u *s = *p;
if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) { if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
int64_t num = 0; int64_t num = 0;
int bytes; for (int bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
int n;
for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
*p += 2; *p += 2;
n = hexhex2nr(*p); int n = hexhex2nr(*p);
if (n < 0) { if (n < 0) {
return 0; return 0;
} }
@ -1283,8 +1281,8 @@ static int get_encoded_char_adv(char_u **p)
} }
// TODO(bfredl): use schar_T representation and utfc_ptr2len // TODO(bfredl): use schar_T representation and utfc_ptr2len
int clen = utf_ptr2len((char *)s); int clen = utf_ptr2len((const char *)s);
int c = mb_cptr2char_adv((const char_u **)p); int c = mb_cptr2char_adv(p);
if (clen == 1 && c > 127) { // Invalid UTF-8 byte if (clen == 1 && c > 127) { // Invalid UTF-8 byte
return 0; return 0;
} }
@ -1294,26 +1292,22 @@ static int get_encoded_char_adv(char_u **p)
/// Handle setting 'listchars' or 'fillchars'. /// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters /// Assume monocell characters
/// ///
/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs /// @param varp either the global or the window-local value.
/// @param apply if false, do not store the flags, only check for errors.
/// @return error message, NULL if it's OK. /// @return error message, NULL if it's OK.
char *set_chars_option(win_T *wp, char_u **varp, bool set) char *set_chars_option(win_T *wp, char_u **varp, bool apply)
{ {
int round, i, len, len2, entries; const char_u *last_multispace = NULL; // Last occurrence of "multispace:"
char_u *p, *s; const char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
int c1;
int c2 = 0;
int 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 multispace_len = 0; // Length of lcs-multispace string
int lead_multispace_len = 0; // Length of lcs-leadmultispace string int lead_multispace_len = 0; // Length of lcs-leadmultispace string
const bool is_listchars = (varp == &p_lcs || varp == (char_u **)&wp->w_p_lcs);
struct chars_tab { struct chars_tab {
int *cp; ///< char value int *cp; ///< char value
char *name; ///< char id char *name; ///< char id
int def; ///< default value int def; ///< default value
}; };
struct chars_tab *tab;
// XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case. // XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
struct chars_tab fcs_tab[] = { struct chars_tab fcs_tab[] = {
@ -1335,6 +1329,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' }, { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
{ &wp->w_p_fcs_chars.eob, "eob", '~' }, { &wp->w_p_fcs_chars.eob, "eob", '~' },
}; };
struct chars_tab lcs_tab[] = { struct chars_tab lcs_tab[] = {
{ &wp->w_p_lcs_chars.eol, "eol", NUL }, { &wp->w_p_lcs_chars.eol, "eol", NUL },
{ &wp->w_p_lcs_chars.ext, "extends", NUL }, { &wp->w_p_lcs_chars.ext, "extends", NUL },
@ -1347,30 +1342,33 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
{ &wp->w_p_lcs_chars.conceal, "conceal", NUL }, { &wp->w_p_lcs_chars.conceal, "conceal", NUL },
}; };
if (varp == &p_lcs || varp == (char_u **)&wp->w_p_lcs) { struct chars_tab *tab;
int entries;
const char_u *value = *varp;
if (is_listchars) {
tab = lcs_tab; tab = lcs_tab;
entries = ARRAY_SIZE(lcs_tab); entries = ARRAY_SIZE(lcs_tab);
if (varp == (char_u **)&wp->w_p_lcs && wp->w_p_lcs[0] == NUL) { if (varp == (char_u **)&wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
varp = &p_lcs; value = p_lcs; // local value is empty, use the global value
} }
} else { } else {
tab = fcs_tab; tab = fcs_tab;
entries = ARRAY_SIZE(fcs_tab); entries = ARRAY_SIZE(fcs_tab);
if (varp == (char_u **)&wp->w_p_fcs && wp->w_p_fcs[0] == NUL) { if (varp == (char_u **)&wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
varp = &p_fcs; value = p_fcs; // local value is empty, use the global value
} }
} }
// first round: check for valid value, second round: assign values // first round: check for valid value, second round: assign values
for (round = 0; round <= (set ? 1 : 0); round++) { for (int round = 0; round <= (apply ? 1 : 0); round++) {
if (round > 0) { if (round > 0) {
// After checking that the value is valid: set defaults // After checking that the value is valid: set defaults
for (i = 0; i < entries; i++) { for (int i = 0; i < entries; i++) {
if (tab[i].cp != NULL) { if (tab[i].cp != NULL) {
*(tab[i].cp) = tab[i].def; *(tab[i].cp) = tab[i].def;
} }
} }
if (varp == &p_lcs || varp == (char_u **)&wp->w_p_lcs) { if (is_listchars) {
wp->w_p_lcs_chars.tab1 = NUL; wp->w_p_lcs_chars.tab1 = NUL;
wp->w_p_lcs_chars.tab3 = NUL; wp->w_p_lcs_chars.tab3 = NUL;
@ -1392,19 +1390,20 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
} }
} }
} }
p = *varp; const char_u *p = value;
while (*p) { while (*p) {
int i;
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
len = (int)STRLEN(tab[i].name); const size_t len = STRLEN(tab[i].name);
if (STRNCMP(p, tab[i].name, len) == 0 if (STRNCMP(p, tab[i].name, len) == 0
&& p[len] == ':' && p[len] == ':'
&& p[len + 1] != NUL) { && p[len + 1] != NUL) {
c2 = c3 = 0; const char_u *s = p + len + 1;
s = p + len + 1; int c1 = get_encoded_char_adv(&s);
c1 = get_encoded_char_adv(&s);
if (c1 == 0 || char2cells(c1) > 1) { if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg; return e_invarg;
} }
int c2 = 0, c3 = 0;
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) { if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
if (*s == NUL) { if (*s == NUL) {
return e_invarg; return e_invarg;
@ -1437,19 +1436,19 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
} }
if (i == entries) { if (i == entries) {
len = (int)STRLEN("multispace"); const size_t len = STRLEN("multispace");
len2 = (int)STRLEN("leadmultispace"); const size_t len2 = STRLEN("leadmultispace");
if ((varp == &p_lcs || varp == (char_u **)&wp->w_p_lcs) if (is_listchars
&& STRNCMP(p, "multispace", len) == 0 && STRNCMP(p, "multispace", len) == 0
&& p[len] == ':' && p[len] == ':'
&& p[len + 1] != NUL) { && p[len + 1] != NUL) {
s = p + len + 1; const char_u *s = p + len + 1;
if (round == 0) { if (round == 0) {
// Get length of lcs-multispace string in the first round // Get length of lcs-multispace string in the first round
last_multispace = p; last_multispace = p;
multispace_len = 0; multispace_len = 0;
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s); int c1 = get_encoded_char_adv(&s);
if (c1 == 0 || char2cells(c1) > 1) { if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg; return e_invarg;
} }
@ -1463,24 +1462,24 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
} else { } else {
int multispace_pos = 0; int multispace_pos = 0;
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s); int c1 = get_encoded_char_adv(&s);
if (p == last_multispace) { if (p == last_multispace) {
wp->w_p_lcs_chars.multispace[multispace_pos++] = c1; wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
} }
} }
p = s; p = s;
} }
} else if ((varp == &p_lcs || varp == (char_u **)&wp->w_p_lcs) } else if (is_listchars
&& STRNCMP(p, "leadmultispace", len2) == 0 && STRNCMP(p, "leadmultispace", len2) == 0
&& p[len2] == ':' && p[len2] == ':'
&& p[len2 + 1] != NUL) { && p[len2 + 1] != NUL) {
s = p + len2 + 1; const char_u *s = p + len2 + 1;
if (round == 0) { if (round == 0) {
// get length of lcs-leadmultispace string in first round // get length of lcs-leadmultispace string in first round
last_lmultispace = p; last_lmultispace = p;
lead_multispace_len = 0; lead_multispace_len = 0;
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s); int c1 = get_encoded_char_adv(&s);
if (c1 == 0 || char2cells(c1) > 1) { if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg; return e_invarg;
} }
@ -1494,7 +1493,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
} else { } else {
int multispace_pos = 0; int multispace_pos = 0;
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s); int c1 = get_encoded_char_adv(&s);
if (p == last_lmultispace) { if (p == last_lmultispace) {
wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1; wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
} }
@ -1505,6 +1504,7 @@ char *set_chars_option(win_T *wp, char_u **varp, bool set)
return e_invarg; return e_invarg;
} }
} }
if (*p == ',') { if (*p == ',') {
p++; p++;
} }

View File

@ -425,7 +425,7 @@ for s:test in sort(s:tests)
set belloff=all set belloff=all
let prev_error = '' let prev_error = ''
let total_errors = [] let total_errors = []
let run_nr = 1 let g:run_nr = 1
" A test can set g:test_is_flaky to retry running the test. " A test can set g:test_is_flaky to retry running the test.
let g:test_is_flaky = 0 let g:test_is_flaky = 0
@ -444,10 +444,10 @@ for s:test in sort(s:tests)
call add(s:messages, 'Found errors in ' . s:test . ':') call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors) call extend(s:messages, v:errors)
call add(total_errors, 'Run ' . run_nr . ':') call add(total_errors, 'Run ' . g:run_nr . ':')
call extend(total_errors, v:errors) call extend(total_errors, v:errors)
if 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') call add(total_errors, 'Flaky test failed too often, giving up')
let v:errors = total_errors let v:errors = total_errors
break break
@ -462,7 +462,7 @@ for s:test in sort(s:tests)
let prev_error = v:errors[0] let prev_error = v:errors[0]
let v:errors = [] let v:errors = []
let run_nr += 1 let g:run_nr += 1
call RunTheTest(s:test) call RunTheTest(s:test)

View File

@ -5,7 +5,7 @@ if exists('s:did_load')
set directory& set directory&
set directory^=. set directory^=.
set display= set display=
set fillchars=vert:\|,fold:- set fillchars=vert:\|,foldsep:\|,fold:-
set formatoptions=tcq set formatoptions=tcq
set fsync set fsync
set laststatus=1 set laststatus=1

View File

@ -309,6 +309,88 @@ func Test_eob_fillchars()
close close
endfunc endfunc
" Test for 'foldopen', 'foldclose' and 'foldsep' in 'fillchars'
func Test_fold_fillchars()
new
set fdc=2 foldenable foldmethod=manual
call setline(1, ['one', 'two', 'three', 'four', 'five'])
2,4fold
" First check for the default setting for a closed fold
let lines = ScreenLines([1, 3], 8)
let expected = [
\ ' one ',
\ '+ +-- 3',
\ ' five '
\ ]
call assert_equal(expected, lines)
normal 2Gzo
" check the characters for an open fold
let lines = ScreenLines([1, 5], 8)
let expected = [
\ ' one ',
\ '- two ',
\ '| three ',
\ '| four ',
\ ' five '
\ ]
call assert_equal(expected, lines)
" change the setting
set fillchars=vert:\|,fold:-,eob:~,foldopen:[,foldclose:],foldsep:-
" check the characters for an open fold
let lines = ScreenLines([1, 5], 8)
let expected = [
\ ' one ',
\ '[ two ',
\ '- three ',
\ '- four ',
\ ' five '
\ ]
call assert_equal(expected, lines)
" check the characters for a closed fold
normal 2Gzc
let lines = ScreenLines([1, 3], 8)
let expected = [
\ ' one ',
\ '] +-- 3',
\ ' five '
\ ]
call assert_equal(expected, lines)
%bw!
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() func Test_display_linebreak_breakat()
new new
vert resize 25 vert resize 25