aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/optionstr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/optionstr.c')
-rw-r--r--src/nvim/optionstr.c432
1 files changed, 244 insertions, 188 deletions
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 281ec86171..4be08b28f5 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -19,9 +19,9 @@
#include "nvim/eval/vars.h"
#include "nvim/ex_getln.h"
#include "nvim/fold.h"
-#include "nvim/func_attr.h"
-#include "nvim/gettext.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
+#include "nvim/grid.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
@@ -39,6 +39,7 @@
#include "nvim/os/os.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
+#include "nvim/regexp_defs.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/spellsuggest.h"
@@ -61,6 +62,10 @@ static const char e_backupext_and_patchmode_are_equal[]
= N_("E589: 'backupext' and 'patchmode' are equal");
static const char e_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_bg_values[]) = { "light", "dark", NULL };
@@ -117,7 +122,7 @@ static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
"syntax", "diff", NULL };
static char *(p_fcl_values[]) = { "all", NULL };
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview", "noinsert", "noselect",
- NULL };
+ "popup", NULL };
#ifdef BACKSLASH_IN_FILENAME
static char *(p_csl_values[]) = { "slash", "backslash", NULL };
#endif
@@ -149,21 +154,21 @@ static char SHM_ALL[] = { SHM_RO, SHM_MOD, SHM_LINES,
/// option values.
void didset_string_options(void)
{
- (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true);
- (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true);
- (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, true);
- (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true);
- (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
- (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
- (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
- (void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, true);
- (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
- (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
- (void)opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true);
- (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
- (void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, true);
- (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
- (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
+ opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true);
+ opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true);
+ opt_strings_flags(p_bo, p_bo_values, &bo_flags, true);
+ opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true);
+ opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
+ opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
+ opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ opt_strings_flags(p_jop, p_jop_values, &jop_flags, true);
+ opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
+ opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
+ opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true);
+ opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
+ opt_strings_flags(p_swb, p_swb_values, &swb_flags, true);
+ opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
+ opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
}
char *illegal_char(char *errbuf, size_t errbuflen, int c)
@@ -284,30 +289,17 @@ static void set_string_option_global(vimoption_T *opt, char **varp)
/// Set a string option to a new value (without checking the effect).
/// The string is copied into allocated memory.
-/// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
+/// if ("opt_idx" == kOptInvalid) "name" is used, otherwise "opt_idx" is used.
/// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
/// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
/// "set_sid".
///
-/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL.
+/// @param opt_flags Option flags.
///
/// TODO(famiu): Remove this and its win/buf variants.
-void set_string_option_direct(const char *name, int opt_idx, const char *val, int opt_flags,
- int set_sid)
+void set_string_option_direct(OptIndex opt_idx, const char *val, int opt_flags, scid_T set_sid)
{
- int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
- int idx = opt_idx;
-
- if (idx == -1) { // Use name.
- idx = findoption(name);
- if (idx < 0) { // Not found (should not happen).
- internal_error("set_string_option_direct()");
- siemsg(_("For option %s"), name);
- return;
- }
- }
-
- vimoption_T *opt = get_option(idx);
+ vimoption_T *opt = get_option(opt_idx);
if (opt->var == NULL) { // can't set hidden option
return;
@@ -315,53 +307,53 @@ void set_string_option_direct(const char *name, int opt_idx, const char *val, in
assert(opt->var != &p_shada);
+ bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
char *s = xstrdup(val);
- {
- char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags);
- if ((opt_flags & OPT_FREE) && (opt->flags & P_ALLOCED)) {
- free_string_option(*varp);
- }
- *varp = s;
+ char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags);
- // For buffer/window local option may also set the global value.
- if (both) {
- set_string_option_global(opt, varp);
- }
+ if (opt->flags & P_ALLOCED) {
+ free_string_option(*varp);
+ }
+ *varp = s;
- opt->flags |= P_ALLOCED;
+ // For buffer/window local option may also set the global value.
+ if (both) {
+ set_string_option_global(opt, varp);
+ }
- // When setting both values of a global option with a local value,
- // make the local value empty, so that the global value is used.
- if ((opt->indir & PV_BOTH) && both) {
- free_string_option(*varp);
- *varp = empty_string_option;
- }
- if (set_sid != SID_NONE) {
- sctx_T script_ctx;
+ opt->flags |= P_ALLOCED;
- if (set_sid == 0) {
- script_ctx = current_sctx;
- } else {
- script_ctx.sc_sid = set_sid;
- script_ctx.sc_seq = 0;
- script_ctx.sc_lnum = 0;
- }
- set_option_sctx_idx(idx, opt_flags, script_ctx);
+ // When setting both values of a global option with a local value,
+ // make the local value empty, so that the global value is used.
+ if ((opt->indir & PV_BOTH) && both) {
+ free_string_option(*varp);
+ *varp = empty_string_option;
+ }
+ if (set_sid != SID_NONE) {
+ sctx_T script_ctx;
+
+ if (set_sid == 0) {
+ script_ctx = current_sctx;
+ } else {
+ script_ctx.sc_sid = set_sid;
+ script_ctx.sc_seq = 0;
+ script_ctx.sc_lnum = 0;
}
+ set_option_sctx(opt_idx, opt_flags, script_ctx);
}
}
/// Like set_string_option_direct(), but for a window-local option in "wp".
/// Blocks autocommands to avoid the old curwin becoming invalid.
-void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, const char *val,
- int opt_flags, int set_sid)
+void set_string_option_direct_in_win(win_T *wp, OptIndex opt_idx, const char *val, int opt_flags,
+ int set_sid)
{
win_T *save_curwin = curwin;
block_autocmds();
curwin = wp;
curbuf = curwin->w_buffer;
- set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
+ set_string_option_direct(opt_idx, val, opt_flags, set_sid);
curwin = save_curwin;
curbuf = curwin->w_buffer;
unblock_autocmds();
@@ -369,14 +361,14 @@ void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, c
/// Like set_string_option_direct(), but for a buffer-local option in "buf".
/// Blocks autocommands to avoid the old curwin becoming invalid.
-void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx, const char *val,
- int opt_flags, int set_sid)
+void set_string_option_direct_in_buf(buf_T *buf, OptIndex opt_idx, const char *val, int opt_flags,
+ int set_sid)
{
buf_T *save_curbuf = curbuf;
block_autocmds();
curbuf = buf;
- set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
+ set_string_option_direct(opt_idx, val, opt_flags, set_sid);
curbuf = save_curbuf;
unblock_autocmds();
}
@@ -443,7 +435,7 @@ int check_signcolumn(win_T *wp)
const char *check_stl_option(char *s)
{
int groupdepth = 0;
- static char errbuf[80];
+ static char errbuf[ERR_BUFLEN];
while (*s) {
// Check for valid keys after % sequences
@@ -677,12 +669,17 @@ int expand_set_ambiwidth(optexpand_T *args, int *numMatches, char ***matches)
}
/// The 'background' option is changed.
-const char *did_set_background(optset_T *args FUNC_ATTR_UNUSED)
+const char *did_set_background(optset_T *args)
{
if (check_opt_strings(p_bg, p_bg_values, false) != OK) {
return e_invarg;
}
+ if (args->os_oldval.string.data[0] == *p_bg) {
+ // Value was not changed
+ return NULL;
+ }
+
int dark = (*p_bg == 'd');
init_highlight(false, false);
@@ -757,7 +754,7 @@ const char *did_set_backupcopy(optset_T *args)
+ ((*flags & BKC_YES) != 0)
+ ((*flags & BKC_NO) != 0) != 1) {
// Must have exactly one of "auto", "yes" and "no".
- (void)opt_strings_flags(oldval, p_bkc_values, flags, true);
+ opt_strings_flags(oldval, p_bkc_values, flags, true);
return e_invarg;
}
}
@@ -800,6 +797,22 @@ int expand_set_belloff(optexpand_T *args, int *numMatches, char ***matches)
matches);
}
+/// The 'breakat' option is changed.
+const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED)
+{
+ for (int i = 0; i < 256; i++) {
+ breakat_flags[i] = false;
+ }
+
+ if (p_breakat != NULL) {
+ for (char *p = p_breakat; *p; p++) {
+ breakat_flags[(uint8_t)(*p)] = true;
+ }
+ }
+
+ return NULL;
+}
+
/// The 'breakindentopt' option is changed.
const char *did_set_breakindentopt(optset_T *args)
{
@@ -885,18 +898,17 @@ int expand_set_casemap(optexpand_T *args, int *numMatches, char ***matches)
}
/// The global 'listchars' or 'fillchars' option is changed.
-static const char *did_set_global_listfillchars(win_T *win, char *val, bool opt_lcs, int opt_flags)
+static const char *did_set_global_chars_option(win_T *win, char *val, CharsOption what,
+ int opt_flags, char *errbuf, size_t errbuflen)
{
const char *errmsg = NULL;
- char **local_ptr = opt_lcs ? &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
// local value
- if (opt_lcs) {
- errmsg = set_listchars_option(win, val, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
- } else {
- errmsg = set_fillchars_option(win, val, **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) {
return errmsg;
}
@@ -912,14 +924,9 @@ static const char *did_set_global_listfillchars(win_T *win, char *val, bool opt_
// again, it was changed when setting the global value.
// If no error was returned above, we don't expect an error
// here, so ignore the return value.
- if (opt_lcs) {
- if (*wp->w_p_lcs == NUL) {
- (void)set_listchars_option(wp, wp->w_p_lcs, true);
- }
- } else {
- if (*wp->w_p_fcs == NUL) {
- (void)set_fillchars_option(wp, wp->w_p_fcs, true);
- }
+ char *opt = (what == kListchars) ? wp->w_p_lcs : wp->w_p_fcs;
+ if (*opt == NUL) {
+ set_chars_option(wp, opt, what, true, errbuf, errbuflen);
}
}
@@ -935,13 +942,18 @@ const char *did_set_chars_option(optset_T *args)
char **varp = (char **)args->os_varp;
const char *errmsg = NULL;
- if (varp == &p_lcs // global 'listchars'
- || varp == &p_fcs) { // global 'fillchars'
- errmsg = did_set_global_listfillchars(win, *varp, varp == &p_lcs, args->os_flags);
+ if (varp == &p_lcs) { // global 'listchars'
+ 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'
+ 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'
- errmsg = set_listchars_option(win, *varp, true);
+ errmsg = set_chars_option(win, *varp, kListchars, true,
+ args->os_errbuf, args->os_errbuflen);
} else if (varp == &win->w_p_fcs) { // local 'fillchars'
- errmsg = set_fillchars_option(win, *varp, true);
+ errmsg = set_chars_option(win, *varp, kFillchars, true,
+ args->os_errbuf, args->os_errbuflen);
}
return errmsg;
@@ -1229,7 +1241,7 @@ const char *did_set_display(optset_T *args FUNC_ATTR_UNUSED)
if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) {
return e_invarg;
}
- (void)init_chartab();
+ init_chartab();
msg_grid_validate();
return NULL;
}
@@ -1434,7 +1446,7 @@ int expand_set_foldcolumn(optexpand_T *args, int *numMatches, char ***matches)
const char *did_set_foldexpr(optset_T *args)
{
win_T *win = (win_T *)args->os_win;
- (void)did_set_optexpr(args);
+ did_set_optexpr(args);
if (foldmethodIsExpr(win)) {
foldUpdateAll(win);
}
@@ -1529,7 +1541,15 @@ int expand_set_formatoptions(optexpand_T *args, int *numMatches, char ***matches
/// The 'guicursor' option is changed.
const char *did_set_guicursor(optset_T *args FUNC_ATTR_UNUSED)
{
- return parse_shape_opt(SHAPE_CURSOR);
+ const char *errmsg = parse_shape_opt(SHAPE_CURSOR);
+ if (errmsg != NULL) {
+ return errmsg;
+ }
+ if (VIsual_active) {
+ // In Visual mode cursor may be drawn differently.
+ redrawWinline(curwin, curwin->w_cursor.lnum);
+ }
+ return NULL;
}
/// The 'helpfile' option is changed.
@@ -1946,6 +1966,10 @@ const char *did_set_selection(optset_T *args FUNC_ATTR_UNUSED)
if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) {
return e_invarg;
}
+ if (VIsual_active) {
+ // Visual selection may be drawn differently.
+ redraw_curbuf_later(UPD_INVERTED);
+ }
return NULL;
}
@@ -1982,7 +2006,7 @@ const char *did_set_sessionoptions(optset_T *args)
if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
// Don't allow both "sesdir" and "curdir".
const char *oldval = args->os_oldval.string.data;
- (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
+ opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
return e_invarg;
}
return NULL;
@@ -2076,7 +2100,13 @@ const char *did_set_showbreak(optset_T *args)
/// The 'showcmdloc' option is changed.
const char *did_set_showcmdloc(optset_T *args FUNC_ATTR_UNUSED)
{
- return did_set_opt_strings(p_sloc, p_sloc_values, true);
+ const char *errmsg = did_set_opt_strings(p_sloc, p_sloc_values, false);
+
+ if (errmsg == NULL) {
+ comp_col();
+ }
+
+ return errmsg;
}
int expand_set_showcmdloc(optexpand_T *args, int *numMatches, char ***matches)
@@ -2096,6 +2126,8 @@ const char *did_set_signcolumn(optset_T *args)
if (check_signcolumn(win) != OK) {
return e_invarg;
}
+ int scwidth = win->w_minscwidth <= 0 ? 0 : MIN(win->w_maxscwidth, win->w_scwidth);
+ win->w_scwidth = MAX(win->w_minscwidth, scwidth);
// When changing the 'signcolumn' to or from 'number', recompute the
// width of the number column if 'number' or 'relativenumber' is set.
if ((*oldval == 'n' && *(oldval + 1) == 'u') || win->w_minscwidth == SCL_NUM) {
@@ -2610,7 +2642,7 @@ static const char e_conflicts_with_value_of_fillchars[]
/// Calls mb_cptr2char_adv(p) and returns the character.
/// 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.
-static int get_encoded_char_adv(const char **p)
+static schar_T get_encoded_char_adv(const char **p)
{
const char *s = *p;
@@ -2625,71 +2657,82 @@ static int get_encoded_char_adv(const char **p)
num = num * 256 + n;
}
*p += 2;
- return (int)num;
+ return (char2cells((int)num) > 1) ? 0 : schar_from_char((int)num);
}
- // TODO(bfredl): use schar_T representation and utfc_ptr2len
- int clen = utf_ptr2len(s);
- int c = mb_cptr2char_adv(p);
- if (clen == 1 && c > 127) { // Invalid UTF-8 byte
- return 0;
- }
- return c;
+ int clen = utfc_ptr2len(s);
+ int firstc;
+ schar_T c = utfc_ptr2schar(s, &firstc);
+ *p += clen;
+ // Invalid UTF-8 byte or doublewidth not allowed
+ return ((clen == 1 && firstc > 127) || char2cells(firstc) > 1) ? 0 : c;
}
struct chars_tab {
- int *cp; ///< char value
+ schar_T *cp; ///< char value
const char *name; ///< char id
- int def; ///< default value
- int fallback; ///< default value when "def" isn't single-width
+ const char *def; ///< default value
+ const char *fallback; ///< default value when "def" isn't single-width
};
static fcs_chars_T fcs_chars;
static const struct chars_tab fcs_tab[] = {
- { &fcs_chars.stl, "stl", ' ', NUL },
- { &fcs_chars.stlnc, "stlnc", ' ', NUL },
- { &fcs_chars.wbr, "wbr", ' ', NUL },
- { &fcs_chars.horiz, "horiz", 0x2500, '-' }, // ─
- { &fcs_chars.horizup, "horizup", 0x2534, '-' }, // ┴
- { &fcs_chars.horizdown, "horizdown", 0x252c, '-' }, // ┬
- { &fcs_chars.vert, "vert", 0x2502, '|' }, // │
- { &fcs_chars.vertleft, "vertleft", 0x2524, '|' }, // ┤
- { &fcs_chars.vertright, "vertright", 0x251c, '|' }, // ├
- { &fcs_chars.verthoriz, "verthoriz", 0x253c, '+' }, // ┼
- { &fcs_chars.fold, "fold", 0x00b7, '-' }, // ·
- { &fcs_chars.foldopen, "foldopen", '-', NUL },
- { &fcs_chars.foldclosed, "foldclose", '+', NUL },
- { &fcs_chars.foldsep, "foldsep", 0x2502, '|' }, // │
- { &fcs_chars.diff, "diff", '-', NUL },
- { &fcs_chars.msgsep, "msgsep", ' ', NUL },
- { &fcs_chars.eob, "eob", '~', NUL },
- { &fcs_chars.lastline, "lastline", '@', NUL },
+ { &fcs_chars.stl, "stl", " ", NULL },
+ { &fcs_chars.stlnc, "stlnc", " ", NULL },
+ { &fcs_chars.wbr, "wbr", " ", NULL },
+ { &fcs_chars.horiz, "horiz", "─", "-" },
+ { &fcs_chars.horizup, "horizup", "┴", "-" },
+ { &fcs_chars.horizdown, "horizdown", "┬", "-" },
+ { &fcs_chars.vert, "vert", "│", "|" },
+ { &fcs_chars.vertleft, "vertleft", "┤", "|" },
+ { &fcs_chars.vertright, "vertright", "├", "|" },
+ { &fcs_chars.verthoriz, "verthoriz", "┼", "+" },
+ { &fcs_chars.fold, "fold", "·", "-" },
+ { &fcs_chars.foldopen, "foldopen", "-", NULL },
+ { &fcs_chars.foldclosed, "foldclose", "+", NULL },
+ { &fcs_chars.foldsep, "foldsep", "│", "|" },
+ { &fcs_chars.diff, "diff", "-", NULL },
+ { &fcs_chars.msgsep, "msgsep", " ", NULL },
+ { &fcs_chars.eob, "eob", "~", NULL },
+ { &fcs_chars.lastline, "lastline", "@", NULL },
};
static lcs_chars_T lcs_chars;
static const struct chars_tab lcs_tab[] = {
- { &lcs_chars.eol, "eol", NUL, NUL },
- { &lcs_chars.ext, "extends", NUL, NUL },
- { &lcs_chars.nbsp, "nbsp", NUL, NUL },
- { &lcs_chars.prec, "precedes", NUL, NUL },
- { &lcs_chars.space, "space", NUL, NUL },
- { &lcs_chars.tab2, "tab", NUL, NUL },
- { &lcs_chars.lead, "lead", NUL, NUL },
- { &lcs_chars.trail, "trail", NUL, NUL },
- { &lcs_chars.conceal, "conceal", NUL, NUL },
- { NULL, "multispace", NUL, NUL },
- { NULL, "leadmultispace", NUL, NUL },
+ { &lcs_chars.eol, "eol", NULL, NULL },
+ { &lcs_chars.ext, "extends", NULL, NULL },
+ { &lcs_chars.nbsp, "nbsp", NULL, NULL },
+ { &lcs_chars.prec, "precedes", NULL, NULL },
+ { &lcs_chars.space, "space", NULL, NULL },
+ { &lcs_chars.tab2, "tab", NULL, NULL },
+ { &lcs_chars.lead, "lead", NULL, NULL },
+ { &lcs_chars.trail, "trail", NULL, NULL },
+ { &lcs_chars.conceal, "conceal", NULL, NULL },
+ { NULL, "multispace", 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'.
/// Assume monocell characters
///
-/// @param value points to either the global or the window-local value.
-/// @param is_listchars is true for "listchars" and false for "fillchars".
-/// @param apply if false, do not store the flags, only check for errors.
+/// @param value points to either the global or the window-local value.
+/// @param what kListchars or kFillchars
+/// @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.
-static const char *set_chars_option(win_T *wp, const char *value, const bool is_listchars,
- const 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_lmultispace = NULL; // Last occurrence of "leadmultispace:"
@@ -2698,7 +2741,7 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
const struct chars_tab *tab;
int entries;
- if (is_listchars) {
+ if (what == kListchars) {
tab = lcs_tab;
entries = ARRAY_SIZE(lcs_tab);
if (wp->w_p_lcs[0] == NUL) {
@@ -2720,23 +2763,24 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
if (tab[i].cp != NULL) {
// XXX: Characters taking 2 columns is forbidden (TUI limitation?).
// Set old defaults in this case.
- *(tab[i].cp) = char2cells(tab[i].def) == 1 ? tab[i].def : tab[i].fallback;
+ *(tab[i].cp) = schar_from_str((tab[i].def && ptr2cells(tab[i].def) == 1)
+ ? tab[i].def : tab[i].fallback);
}
}
- if (is_listchars) {
+ if (what == kListchars) {
lcs_chars.tab1 = NUL;
lcs_chars.tab3 = NUL;
if (multispace_len > 0) {
- lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
+ lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(schar_T));
lcs_chars.multispace[multispace_len] = NUL;
} else {
lcs_chars.multispace = NULL;
}
if (lead_multispace_len > 0) {
- lcs_chars.leadmultispace = xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
+ lcs_chars.leadmultispace = xmalloc(((size_t)lead_multispace_len + 1) * sizeof(schar_T));
lcs_chars.leadmultispace[lead_multispace_len] = NUL;
} else {
lcs_chars.leadmultispace = NULL;
@@ -2749,34 +2793,36 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
int i;
for (i = 0; i < entries; i++) {
const size_t len = strlen(tab[i].name);
- if (!(strncmp(p, tab[i].name, len) == 0
- && p[len] == ':'
- && p[len + 1] != NUL)) {
+ if (!(strncmp(p, tab[i].name, len) == 0 && p[len] == ':')) {
continue;
}
- if (is_listchars && strcmp(tab[i].name, "multispace") == 0) {
+ if (what == kListchars && strcmp(tab[i].name, "multispace") == 0) {
const char *s = p + len + 1;
if (round == 0) {
// Get length of lcs-multispace string in the first round
last_multispace = p;
multispace_len = 0;
while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
+ schar_T c1 = get_encoded_char_adv(&s);
+ if (c1 == 0) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
multispace_len++;
}
if (multispace_len == 0) {
// 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;
} else {
int multispace_pos = 0;
while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
+ schar_T c1 = get_encoded_char_adv(&s);
if (p == last_multispace) {
lcs_chars.multispace[multispace_pos++] = c1;
}
@@ -2786,28 +2832,32 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
break;
}
- if (is_listchars && strcmp(tab[i].name, "leadmultispace") == 0) {
+ if (what == kListchars && strcmp(tab[i].name, "leadmultispace") == 0) {
const char *s = p + len + 1;
if (round == 0) {
// get length of lcs-leadmultispace string in first round
last_lmultispace = p;
lead_multispace_len = 0;
while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
+ schar_T c1 = get_encoded_char_adv(&s);
+ if (c1 == 0) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
lead_multispace_len++;
}
if (lead_multispace_len == 0) {
// 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;
} else {
int multispace_pos = 0;
while (*s != NUL && *s != ',') {
- int c1 = get_encoded_char_adv(&s);
+ schar_T c1 = get_encoded_char_adv(&s);
if (p == last_lmultispace) {
lcs_chars.leadmultispace[multispace_pos++] = c1;
}
@@ -2818,23 +2868,37 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
}
const char *s = p + len + 1;
- int c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || char2cells(c1) > 1) {
- return e_invarg;
+ 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);
+ if (c1 == 0) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
- int c2 = 0, c3 = 0;
+ schar_T c2 = 0;
+ schar_T c3 = 0;
if (tab[i].cp == &lcs_chars.tab2) {
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);
- if (c2 == 0 || char2cells(c2) > 1) {
- return e_invarg;
+ if (c2 == 0) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
if (!(*s == ',' || *s == NUL)) {
c3 = get_encoded_char_adv(&s);
- if (c3 == 0 || char2cells(c3) > 1) {
- return e_invarg;
+ if (c3 == 0) {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_character_width_for_field_str,
+ tab[i].name);
}
}
}
@@ -2851,6 +2915,10 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
}
p = s;
break;
+ } else {
+ return field_value_err(errbuf, errbuflen,
+ e_wrong_number_of_characters_for_field_str,
+ tab[i].name);
}
}
@@ -2865,7 +2933,7 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
}
if (apply) {
- if (is_listchars) {
+ if (what == kListchars) {
xfree(wp->w_p_lcs_chars.multispace);
xfree(wp->w_p_lcs_chars.leadmultispace);
wp->w_p_lcs_chars = lcs_chars;
@@ -2877,18 +2945,6 @@ static const char *set_chars_option(win_T *wp, const char *value, const bool is_
return NULL; // no error
}
-/// Handle the new value of 'fillchars'.
-const char *set_fillchars_option(win_T *wp, char *val, bool apply)
-{
- return set_chars_option(wp, val, false, apply);
-}
-
-/// Handle the new value of 'listchars'.
-const char *set_listchars_option(win_T *wp, char *val, bool apply)
-{
- return set_chars_option(wp, val, true, apply);
-}
-
/// Function given to ExpandGeneric() to obtain possible arguments of the
/// 'fillchars' option.
char *get_fillchars_name(expand_T *xp FUNC_ATTR_UNUSED, int idx)
@@ -2917,17 +2973,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.
const char *check_chars_options(void)
{
- if (set_listchars_option(curwin, p_lcs, false) != NULL) {
+ if (set_chars_option(curwin, p_lcs, kListchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_fillchars_option(curwin, p_fcs, false) != NULL) {
+ if (set_chars_option(curwin, p_fcs, kFillchars, false, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (set_listchars_option(wp, wp->w_p_lcs, true) != NULL) {
+ if (set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_fillchars_option(wp, wp->w_p_fcs, true) != NULL) {
+ if (set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
}