vim-patch:9.1.0039: too vague errors for 'listchars'/'fillchars' (#27070)

Problem:  too vague errors for 'listchars'/'fillchars'
Solution: Include the field name in error message.
          (zeertzjq)

related: #27050
closes: vim/vim#13877

6a8d2e1634

Co-authored-by: Cole Frankenhoff <cole.nhf@gmail.com>
This commit is contained in:
zeertzjq 2024-01-18 07:14:12 +08:00 committed by GitHub
parent 5aa14e1231
commit 780dd88b68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 154 additions and 99 deletions

View File

@ -2485,7 +2485,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Characters to fill the statuslines, vertical separators and special Characters to fill the statuslines, vertical separators and special
lines in the window. lines in the window.
It is a comma-separated list of items. Each item has a name, a colon It is a comma-separated list of items. Each item has a name, a colon
and the value of that item: and the value of that item: |E1511|
item default Used for ~ item default Used for ~
stl ' ' statusline of the current window stl ' ' statusline of the current window
@ -2523,7 +2523,7 @@ A jump table for the options with a short description can be found at |Q_op|.
< <
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width single-byte and multibyte characters are supported. But double-width
characters are not supported. characters are not supported. |E1512|
The highlighting used for these items: The highlighting used for these items:
item highlight group ~ item highlight group ~
@ -3823,7 +3823,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'listchars' 'lcs' string (default "tab:> ,trail:-,nbsp:+") 'listchars' 'lcs' string (default "tab:> ,trail:-,nbsp:+")
global or local to window |global-local| global or local to window |global-local|
Strings to use in 'list' mode and for the |:list| command. It is a Strings to use in 'list' mode and for the |:list| command. It is a
comma-separated list of string settings. comma-separated list of string settings. *E1511*
*lcs-eol* *lcs-eol*
eol:c Character to show at the end of each line. When eol:c Character to show at the end of each line. When
@ -3902,7 +3902,7 @@ A jump table for the options with a short description can be found at |Q_op|.
omitted. omitted.
The characters ':' and ',' should not be used. UTF-8 characters can The characters ':' and ',' should not be used. UTF-8 characters can
be used. All characters must be single width. be used. All characters must be single width. *E1512*
Each character can be specified as hex: >vim Each character can be specified as hex: >vim
set listchars=eol:\\x24 set listchars=eol:\\x24

View File

@ -2197,7 +2197,7 @@ vim.bo.ft = vim.bo.filetype
--- Characters to fill the statuslines, vertical separators and special --- Characters to fill the statuslines, vertical separators and special
--- lines in the window. --- lines in the window.
--- It is a comma-separated list of items. Each item has a name, a colon --- It is a comma-separated list of items. Each item has a name, a colon
--- and the value of that item: --- and the value of that item: `E1511`
--- ---
--- item default Used for ~ --- item default Used for ~
--- stl ' ' statusline of the current window --- stl ' ' statusline of the current window
@ -2238,7 +2238,7 @@ vim.bo.ft = vim.bo.filetype
--- ---
--- For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items --- For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
--- single-byte and multibyte characters are supported. But double-width --- single-byte and multibyte characters are supported. But double-width
--- characters are not supported. --- characters are not supported. `E1512`
--- ---
--- The highlighting used for these items: --- The highlighting used for these items:
--- item highlight group ~ --- item highlight group ~
@ -3829,7 +3829,7 @@ vim.o.list = false
vim.wo.list = vim.o.list vim.wo.list = vim.o.list
--- Strings to use in 'list' mode and for the `:list` command. It is a --- Strings to use in 'list' mode and for the `:list` command. It is a
--- comma-separated list of string settings. --- comma-separated list of string settings. *E1511*
--- ---
--- *lcs-eol* --- *lcs-eol*
--- eol:c Character to show at the end of each line. When --- eol:c Character to show at the end of each line. When
@ -3921,7 +3921,7 @@ vim.wo.list = vim.o.list
--- omitted. --- omitted.
--- ---
--- The characters ':' and ',' should not be used. UTF-8 characters can --- The characters ':' and ',' should not be used. UTF-8 characters can
--- be used. All characters must be single width. --- be used. All characters must be single width. *E1512*
--- ---
--- Each character can be specified as hex: --- Each character can be specified as hex:
--- ---

View File

@ -1703,10 +1703,10 @@ static void didset_options2(void)
highlight_changed(); highlight_changed();
// Parse default for 'fillchars'. // Parse default for 'fillchars'.
set_chars_option(curwin, curwin->w_p_fcs, kFillchars, true); set_chars_option(curwin, curwin->w_p_fcs, kFillchars, true, NULL, 0);
// Parse default for 'listchars'. // Parse default for 'listchars'.
set_chars_option(curwin, curwin->w_p_lcs, kListchars, true); set_chars_option(curwin, curwin->w_p_lcs, kListchars, true, NULL, 0);
// Parse default for 'wildmode'. // Parse default for 'wildmode'.
check_opt_wim(); check_opt_wim();
@ -4998,8 +4998,8 @@ void didset_window_options(win_T *wp, bool valid_cursor)
check_colorcolumn(wp); check_colorcolumn(wp);
briopt_check(wp); briopt_check(wp);
fill_culopt_flags(NULL, wp); fill_culopt_flags(NULL, wp);
set_chars_option(wp, wp->w_p_fcs, kFillchars, true); set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0);
set_chars_option(wp, wp->w_p_lcs, kListchars, true); set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0);
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp); check_blending(wp);
set_winbar_win(wp, false, valid_cursor); set_winbar_win(wp, false, valid_cursor);

View File

@ -2818,7 +2818,7 @@ return {
Characters to fill the statuslines, vertical separators and special Characters to fill the statuslines, vertical separators and special
lines in the window. lines in the window.
It is a comma-separated list of items. Each item has a name, a colon It is a comma-separated list of items. Each item has a name, a colon
and the value of that item: and the value of that item: |E1511|
item default Used for ~ item default Used for ~
stl ' ' statusline of the current window stl ' ' statusline of the current window
@ -2856,7 +2856,7 @@ return {
< <
For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items For the "stl", "stlnc", "foldopen", "foldclose" and "foldsep" items
single-byte and multibyte characters are supported. But double-width single-byte and multibyte characters are supported. But double-width
characters are not supported. characters are not supported. |E1512|
The highlighting used for these items: The highlighting used for these items:
item highlight group ~ item highlight group ~
@ -4879,7 +4879,7 @@ return {
deny_duplicates = true, deny_duplicates = true,
desc = [=[ desc = [=[
Strings to use in 'list' mode and for the |:list| command. It is a Strings to use in 'list' mode and for the |:list| command. It is a
comma-separated list of string settings. comma-separated list of string settings. *E1511*
*lcs-eol* *lcs-eol*
eol:c Character to show at the end of each line. When eol:c Character to show at the end of each line. When
@ -4958,7 +4958,7 @@ return {
omitted. omitted.
The characters ':' and ',' should not be used. UTF-8 characters can The characters ':' and ',' should not be used. UTF-8 characters can
be used. All characters must be single width. be used. All characters must be single width. *E1512*
Each character can be specified as hex: >vim Each character can be specified as hex: >vim
set listchars=eol:\\x24 set listchars=eol:\\x24

View File

@ -62,6 +62,10 @@ static const char e_backupext_and_patchmode_are_equal[]
= N_("E589: 'backupext' and 'patchmode' are equal"); = N_("E589: 'backupext' and 'patchmode' are equal");
static const char e_showbreak_contains_unprintable_or_wide_character[] static const char e_showbreak_contains_unprintable_or_wide_character[]
= N_("E595: 'showbreak' contains unprintable or wide character"); = N_("E595: 'showbreak' contains unprintable or wide character");
static const char e_wrong_number_of_characters_for_field_str[]
= N_("E1511: Wrong number of characters for field \"%s\"");
static const char e_wrong_character_width_for_field_str[]
= N_("E1512: Wrong character width for field \"%s\"");
static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_ambw_values[]) = { "single", "double", NULL };
static char *(p_bg_values[]) = { "light", "dark", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL };
@ -879,14 +883,16 @@ int expand_set_casemap(optexpand_T *args, int *numMatches, char ***matches)
/// The global 'listchars' or 'fillchars' option is changed. /// The global 'listchars' or 'fillchars' option is changed.
static const char *did_set_global_chars_option(win_T *win, char *val, CharsOption what, static const char *did_set_global_chars_option(win_T *win, char *val, CharsOption what,
int opt_flags) int opt_flags, char *errbuf, size_t errbuflen)
{ {
const char *errmsg = NULL; const char *errmsg = NULL;
char **local_ptr = (what == kListchars) ? &win->w_p_lcs : &win->w_p_fcs; char **local_ptr = (what == kListchars) ? &win->w_p_lcs : &win->w_p_fcs;
// only apply the global value to "win" when it does not have a // only apply the global value to "win" when it does not have a
// local value // local value
errmsg = set_chars_option(win, val, what, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL)); errmsg = set_chars_option(win, val, what,
**local_ptr == NUL || !(opt_flags & OPT_GLOBAL),
errbuf, errbuflen);
if (errmsg != NULL) { if (errmsg != NULL) {
return errmsg; return errmsg;
} }
@ -904,7 +910,7 @@ static const char *did_set_global_chars_option(win_T *win, char *val, CharsOptio
// here, so ignore the return value. // here, so ignore the return value.
char *opt = (what == kListchars) ? wp->w_p_lcs : wp->w_p_fcs; char *opt = (what == kListchars) ? wp->w_p_lcs : wp->w_p_fcs;
if (*opt == NUL) { if (*opt == NUL) {
set_chars_option(wp, opt, what, true); set_chars_option(wp, opt, what, true, errbuf, errbuflen);
} }
} }
@ -921,13 +927,17 @@ const char *did_set_chars_option(optset_T *args)
const char *errmsg = NULL; const char *errmsg = NULL;
if (varp == &p_lcs) { // global 'listchars' if (varp == &p_lcs) { // global 'listchars'
errmsg = did_set_global_chars_option(win, *varp, kListchars, args->os_flags); errmsg = did_set_global_chars_option(win, *varp, kListchars, args->os_flags,
args->os_errbuf, args->os_errbuflen);
} else if (varp == &p_fcs) { // global 'fillchars' } else if (varp == &p_fcs) { // global 'fillchars'
errmsg = did_set_global_chars_option(win, *varp, kFillchars, args->os_flags); errmsg = did_set_global_chars_option(win, *varp, kFillchars, args->os_flags,
args->os_errbuf, args->os_errbuflen);
} else if (varp == &win->w_p_lcs) { // local 'listchars' } else if (varp == &win->w_p_lcs) { // local 'listchars'
errmsg = set_chars_option(win, *varp, kListchars, true); errmsg = set_chars_option(win, *varp, kListchars, true,
args->os_errbuf, args->os_errbuflen);
} else if (varp == &win->w_p_fcs) { // local 'fillchars' } else if (varp == &win->w_p_fcs) { // local 'fillchars'
errmsg = set_chars_option(win, *varp, kFillchars, true); errmsg = set_chars_option(win, *varp, kFillchars, true,
args->os_errbuf, args->os_errbuflen);
} }
return errmsg; return errmsg;
@ -2668,14 +2678,27 @@ static const struct chars_tab lcs_tab[] = {
{ NULL, "leadmultispace", NULL, NULL }, { NULL, "leadmultispace", NULL, NULL },
}; };
static char *field_value_err(char *errbuf, size_t errbuflen, const char *fmt, const char *field)
{
if (errbuf == NULL) {
return "";
}
vim_snprintf(errbuf, errbuflen, _(fmt), field);
return errbuf;
}
/// Handle setting 'listchars' or 'fillchars'. /// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters /// Assume monocell characters
/// ///
/// @param value points to either the global or the window-local value. /// @param value points to either the global or the window-local value.
/// @param what kListchars or kFillchars /// @param what kListchars or kFillchars
/// @param apply if false, do not store the flags, only check for errors. /// @param apply if false, do not store the flags, only check for errors.
/// @param errbuf buffer for error message, can be NULL if it won't be used.
/// @param errbuflen size of error buffer.
///
/// @return error message, NULL if it's OK. /// @return error message, NULL if it's OK.
const char *set_chars_option(win_T *wp, const char *value, CharsOption what, bool apply) const char *set_chars_option(win_T *wp, const char *value, CharsOption what, bool apply,
char *errbuf, size_t errbuflen)
{ {
const char *last_multispace = NULL; // Last occurrence of "multispace:" const char *last_multispace = NULL; // Last occurrence of "multispace:"
const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:" const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
@ -2736,9 +2759,7 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
int i; int i;
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
const size_t len = 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)) {
continue; continue;
} }
@ -2751,13 +2772,17 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
schar_T c1 = get_encoded_char_adv(&s); schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) { if (c1 == 0) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_character_width_for_field_str,
tab[i].name);
} }
multispace_len++; multispace_len++;
} }
if (multispace_len == 0) { if (multispace_len == 0) {
// lcs-multispace cannot be an empty string // lcs-multispace cannot be an empty string
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_number_of_characters_for_field_str,
tab[i].name);
} }
p = s; p = s;
} else { } else {
@ -2782,13 +2807,17 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
while (*s != NUL && *s != ',') { while (*s != NUL && *s != ',') {
schar_T c1 = get_encoded_char_adv(&s); schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) { if (c1 == 0) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_character_width_for_field_str,
tab[i].name);
} }
lead_multispace_len++; lead_multispace_len++;
} }
if (lead_multispace_len == 0) { if (lead_multispace_len == 0) {
// lcs-leadmultispace cannot be an empty string // lcs-leadmultispace cannot be an empty string
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_number_of_characters_for_field_str,
tab[i].name);
} }
p = s; p = s;
} else { } else {
@ -2805,24 +2834,37 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
} }
const char *s = p + len + 1; const char *s = p + len + 1;
if (*s == NUL) {
return field_value_err(errbuf, errbuflen,
e_wrong_number_of_characters_for_field_str,
tab[i].name);
}
schar_T c1 = get_encoded_char_adv(&s); schar_T c1 = get_encoded_char_adv(&s);
if (c1 == 0) { if (c1 == 0) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_character_width_for_field_str,
tab[i].name);
} }
schar_T c2 = 0; schar_T c2 = 0;
schar_T c3 = 0; schar_T c3 = 0;
if (tab[i].cp == &lcs_chars.tab2) { if (tab[i].cp == &lcs_chars.tab2) {
if (*s == NUL) { if (*s == NUL) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_number_of_characters_for_field_str,
tab[i].name);
} }
c2 = get_encoded_char_adv(&s); c2 = get_encoded_char_adv(&s);
if (c2 == 0) { if (c2 == 0) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_character_width_for_field_str,
tab[i].name);
} }
if (!(*s == ',' || *s == NUL)) { if (!(*s == ',' || *s == NUL)) {
c3 = get_encoded_char_adv(&s); c3 = get_encoded_char_adv(&s);
if (c3 == 0) { if (c3 == 0) {
return e_invarg; return field_value_err(errbuf, errbuflen,
e_wrong_character_width_for_field_str,
tab[i].name);
} }
} }
} }
@ -2839,6 +2881,10 @@ const char *set_chars_option(win_T *wp, const char *value, CharsOption what, boo
} }
p = s; p = s;
break; break;
} else {
return field_value_err(errbuf, errbuflen,
e_wrong_number_of_characters_for_field_str,
tab[i].name);
} }
} }
@ -2893,17 +2939,17 @@ char *get_listchars_name(expand_T *xp FUNC_ATTR_UNUSED, int idx)
/// @return an untranslated error message if any of them is invalid, NULL otherwise. /// @return an untranslated error message if any of them is invalid, NULL otherwise.
const char *check_chars_options(void) const char *check_chars_options(void)
{ {
if (set_chars_option(curwin, p_lcs, kListchars, false) != NULL) { if (set_chars_option(curwin, p_lcs, kListchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars; return e_conflicts_with_value_of_listchars;
} }
if (set_chars_option(curwin, p_fcs, kFillchars, false) != NULL) { if (set_chars_option(curwin, p_fcs, kFillchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars; return e_conflicts_with_value_of_fillchars;
} }
FOR_ALL_TAB_WINDOWS(tp, wp) { FOR_ALL_TAB_WINDOWS(tp, wp) {
if (set_chars_option(wp, wp->w_p_lcs, kListchars, true) != NULL) { if (set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars; return e_conflicts_with_value_of_listchars;
} }
if (set_chars_option(wp, wp->w_p_fcs, kFillchars, true) != NULL) { if (set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars; return e_conflicts_with_value_of_fillchars;
} }
} }

View File

@ -1,9 +1,9 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen') local Screen = require('test.functional.ui.screen')
local clear, command = helpers.clear, helpers.command local clear, command = helpers.clear, helpers.command
local pcall_err = helpers.pcall_err
local eval = helpers.eval local eval = helpers.eval
local eq = helpers.eq local eq = helpers.eq
local exc_exec = helpers.exc_exec
local insert = helpers.insert local insert = helpers.insert
local feed = helpers.feed local feed = helpers.feed
local api = helpers.api local api = helpers.api
@ -17,11 +17,6 @@ describe("'fillchars'", function()
screen:attach() screen:attach()
end) end)
local function shouldfail(val, errval)
errval = errval or val
eq('Vim(set):E474: Invalid argument: fillchars=' .. errval, exc_exec('set fillchars=' .. val))
end
describe('"eob" flag', function() describe('"eob" flag', function()
it("uses '~' by default", function() it("uses '~' by default", function()
eq('', eval('&fillchars')) eq('', eval('&fillchars'))
@ -64,10 +59,22 @@ describe("'fillchars'", function()
end) end)
it('handles invalid values', function() it('handles invalid values', function()
shouldfail('eob:') -- empty string eq(
shouldfail('eob:馬') -- doublewidth char 'Vim(set):E1511: Wrong number of characters for field "eob": fillchars=eob:',
shouldfail('eob:xy') -- two ascii chars pcall_err(command, 'set fillchars=eob:') -- empty string
shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8 )
eq(
'Vim(set):E1512: Wrong character width for field "eob": fillchars=eob:馬',
pcall_err(command, 'set fillchars=eob:馬') -- doublewidth char
)
eq(
'Vim(set):E1511: Wrong number of characters for field "eob": fillchars=eob:xy',
pcall_err(command, 'set fillchars=eob:xy') -- two ascii chars
)
eq(
'Vim(set):E1512: Wrong character width for field "eob": fillchars=eob:<ff>',
pcall_err(command, 'set fillchars=eob:\255') -- invalid UTF-8
)
end) end)
end) end)

View File

@ -253,12 +253,12 @@ func Test_eob_fillchars()
" default value " default value
" call assert_match('eob:\~', &fillchars) " call assert_match('eob:\~', &fillchars)
" invalid values " invalid values
call assert_fails(':set fillchars=eob:', 'E474:') call assert_fails(':set fillchars=eob:', 'E1511:')
call assert_fails(':set fillchars=eob:xy', 'E474:') call assert_fails(':set fillchars=eob:xy', 'E1511:')
call assert_fails(':set fillchars=eob:\255', 'E474:') call assert_fails(':set fillchars=eob:\255', 'E1511:')
call assert_fails(':set fillchars=eob:<ff>', 'E474:') call assert_fails(':set fillchars=eob:<ff>', 'E1511:')
call assert_fails(":set fillchars=eob:\x01", 'E474:') call assert_fails(":set fillchars=eob:\x01", 'E1512:')
call assert_fails(':set fillchars=eob:\\x01', 'E474:') call assert_fails(':set fillchars=eob:\\x01', 'E1512:')
" default is ~ " default is ~
new new
redraw redraw
@ -412,14 +412,16 @@ func Run_Test_display_lastline(euro)
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
func Test_display_lastline() func Test_display_lastline_dump()
CheckScreendump CheckScreendump
call Run_Test_display_lastline('') call Run_Test_display_lastline('')
call Run_Test_display_lastline('euro_') call Run_Test_display_lastline('euro_')
endfunc
call assert_fails(':set fillchars=lastline:', 'E474:') func Test_display_lastline_fails()
call assert_fails(':set fillchars=lastline:', 'E474:') call assert_fails(':set fillchars=lastline:', 'E1511:')
call assert_fails(':set fillchars=lastline:', 'E1512:')
endfunc endfunc
func Test_display_long_lastline() func Test_display_long_lastline()

View File

@ -429,52 +429,52 @@ func Test_listchars_invalid()
call assert_fails('set listchars=leadmultispace', 'E474:') call assert_fails('set listchars=leadmultispace', 'E474:')
" Too short " Too short
call assert_fails('set listchars=space:', 'E474:') call assert_fails('set listchars=space:', 'E1511:')
call assert_fails('set listchars=tab:x', 'E474:') call assert_fails('set listchars=tab:x', 'E1511:')
call assert_fails('set listchars=multispace:', 'E474:') call assert_fails('set listchars=multispace:', 'E1511:')
call assert_fails('set listchars=leadmultispace:', 'E474:') call assert_fails('set listchars=leadmultispace:', 'E1511:')
" One occurrence too short " One occurrence too short
call assert_fails('set listchars=space:,space:x', 'E474:') call assert_fails('set listchars=space:x,space:', 'E1511:')
call assert_fails('set listchars=space:x,space:', 'E474:') call assert_fails('set listchars=space:,space:x', 'E1511:')
call assert_fails('set listchars=tab:x,tab:xx', 'E474:') call assert_fails('set listchars=tab:xx,tab:x', 'E1511:')
call assert_fails('set listchars=tab:xx,tab:x', 'E474:') call assert_fails('set listchars=tab:x,tab:xx', 'E1511:')
call assert_fails('set listchars=multispace:,multispace:x', 'E474:') call assert_fails('set listchars=multispace:,multispace:x', 'E1511:')
call assert_fails('set listchars=multispace:x,multispace:', 'E474:') call assert_fails('set listchars=multispace:x,multispace:', 'E1511:')
call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E474:') call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E1511:')
call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E474:') call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E1511:')
" Too long " Too long
call assert_fails('set listchars=space:xx', 'E474:') call assert_fails('set listchars=space:xx', 'E1511:')
call assert_fails('set listchars=tab:xxxx', 'E474:') call assert_fails('set listchars=tab:xxxx', 'E1511:')
" Has double-width character " Has double-width character
call assert_fails('set listchars=space:·', 'E474:') call assert_fails('set listchars=space:·', 'E1512:')
call assert_fails('set listchars=tab:·x', 'E474:') call assert_fails('set listchars=tab:·x', 'E1512:')
call assert_fails('set listchars=tab:x·', 'E474:') call assert_fails('set listchars=tab:x·', 'E1512:')
call assert_fails('set listchars=tab:xx·', 'E474:') call assert_fails('set listchars=tab:xx·', 'E1512:')
call assert_fails('set listchars=multispace:·', 'E474:') call assert_fails('set listchars=multispace:·', 'E1512:')
call assert_fails('set listchars=multispace:xxx·', 'E474:') call assert_fails('set listchars=multispace:xxx·', 'E1512:')
call assert_fails('set listchars=leadmultispace:·', 'E474:') call assert_fails('set listchars=leadmultispace:·', 'E1512:')
call assert_fails('set listchars=leadmultispace:xxx·', 'E474:') call assert_fails('set listchars=leadmultispace:xxx·', 'E1512:')
" Has control character " Has control character
call assert_fails("set listchars=space:\x01", 'E474:') call assert_fails("set listchars=space:\x01", 'E1512:')
call assert_fails("set listchars=tab:\x01x", 'E474:') call assert_fails("set listchars=tab:\x01x", 'E1512:')
call assert_fails("set listchars=tab:x\x01", 'E474:') call assert_fails("set listchars=tab:x\x01", 'E1512:')
call assert_fails("set listchars=tab:xx\x01", 'E474:') call assert_fails("set listchars=tab:xx\x01", 'E1512:')
call assert_fails("set listchars=multispace:\x01", 'E474:') call assert_fails("set listchars=multispace:\x01", 'E1512:')
call assert_fails("set listchars=multispace:xxx\x01", 'E474:') call assert_fails("set listchars=multispace:xxx\x01", 'E1512:')
call assert_fails('set listchars=space:\\x01', 'E474:') call assert_fails('set listchars=space:\\x01', 'E1512:')
call assert_fails('set listchars=tab:\\x01x', 'E474:') call assert_fails('set listchars=tab:\\x01x', 'E1512:')
call assert_fails('set listchars=tab:x\\x01', 'E474:') call assert_fails('set listchars=tab:x\\x01', 'E1512:')
call assert_fails('set listchars=tab:xx\\x01', 'E474:') call assert_fails('set listchars=tab:xx\\x01', 'E1512:')
call assert_fails('set listchars=multispace:\\x01', 'E474:') call assert_fails('set listchars=multispace:\\x01', 'E1512:')
call assert_fails('set listchars=multispace:xxx\\x01', 'E474:') call assert_fails('set listchars=multispace:xxx\\x01', 'E1512:')
call assert_fails("set listchars=leadmultispace:\x01", 'E474:') call assert_fails("set listchars=leadmultispace:\x01", 'E1512:')
call assert_fails('set listchars=leadmultispace:\\x01', 'E474:') call assert_fails('set listchars=leadmultispace:\\x01', 'E1512:')
call assert_fails("set listchars=leadmultispace:xxx\x01", 'E474:') call assert_fails("set listchars=leadmultispace:xxx\x01", 'E1512:')
call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E474:') call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E1512:')
enew! enew!
set ambiwidth& listchars& ff& set ambiwidth& listchars& ff&