aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/option.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/option.c')
-rw-r--r--src/nvim/option.c140
1 files changed, 87 insertions, 53 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 22897d4f7e..ff0c0e2acf 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -44,6 +44,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
@@ -87,6 +88,7 @@
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmenu.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
@@ -208,39 +210,53 @@ static void set_init_default_backupskip(void)
OptIndex opt_idx = kOptBackupskip;
ga_init(&ga, 1, 100);
- for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
+ for (size_t i = 0; i < ARRAY_SIZE(names); i++) {
bool mustfree = true;
char *p;
+ size_t plen;
#ifdef UNIX
- if (*names[n] == NUL) {
+ if (*names[i] == NUL) {
# ifdef __APPLE__
p = "/private/tmp";
+ plen = STRLEN_LITERAL("/private/tmp");
# else
p = "/tmp";
+ plen = STRLEN_LITERAL("/tmp");
# endif
mustfree = false;
} else
#endif
{
- p = vim_getenv(names[n]);
+ p = vim_getenv(names[i]);
+ plen = 0; // will be calcuated below
}
if (p != NULL && *p != NUL) {
- // First time count the NUL, otherwise count the ','.
- const size_t len = strlen(p) + 3;
- char *item = xmalloc(len);
- xstrlcpy(item, p, len);
- add_pathsep(item);
- xstrlcat(item, "*", len);
- if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
- == NULL) {
- ga_grow(&ga, (int)len);
- if (!GA_EMPTY(&ga)) {
- STRCAT(ga.ga_data, ",");
+ bool has_trailing_path_sep = false;
+
+ if (plen == 0) {
+ // the value was retrieved from the environment
+ plen = strlen(p);
+ // does the value include a trailing path separator?
+ if (after_pathsep(p, p + plen)) {
+ has_trailing_path_sep = true;
}
- STRCAT(ga.ga_data, p);
- add_pathsep(ga.ga_data);
- STRCAT(ga.ga_data, "*");
- ga.ga_len += (int)len;
+ }
+
+ // item size needs to be large enough to include "/*" and a trailing NUL
+ // note: the value (and therefore plen) may already include a path separator
+ size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2;
+ char *item = xmalloc(itemsize);
+ // add a preceding comma as a separator after the first item
+ size_t itemseplen = (ga.ga_len == 0) ? 0 : 1;
+
+ size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p,
+ has_trailing_path_sep ? "" : PATHSEPSTR);
+
+ if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) {
+ ga_grow(&ga, (int)(itemseplen + itemlen + 1));
+ ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len,
+ itemseplen + itemlen + 1,
+ "%s%s", (itemseplen > 0) ? "," : "", item);
}
xfree(item);
}
@@ -524,7 +540,8 @@ static void set_string_default(OptIndex opt_idx, char *val, bool allocated)
/// For an option value that contains comma separated items, find "newval" in
/// "origval". Return NULL if not found.
-static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
+static char *find_dup_item(char *origval, const char *newval, const size_t newvallen,
+ uint32_t flags)
FUNC_ATTR_NONNULL_ARG(2)
{
if (origval == NULL) {
@@ -533,11 +550,10 @@ static char *find_dup_item(char *origval, const char *newval, uint32_t flags)
int bs = 0;
- const size_t newlen = strlen(newval);
for (char *s = origval; *s != NUL; s++) {
if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
- && strncmp(s, newval, newlen) == 0
- && (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
+ && strncmp(s, newval, newvallen) == 0
+ && (!(flags & P_COMMA) || s[newvallen] == ',' || s[newvallen] == NUL)) {
return s;
}
// Count backslashes. Only a comma with an even number of backslashes
@@ -695,10 +711,10 @@ void set_helplang_default(const char *lang)
}
p_hlg = xmemdupz(lang, lang_len);
// zh_CN becomes "cn", zh_TW becomes "tw".
- if (STRNICMP(p_hlg, "zh_", 3) == 0 && strlen(p_hlg) >= 5) {
+ if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) {
p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]);
p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]);
- } else if (strlen(p_hlg) >= 1 && *p_hlg == 'C') {
+ } else if (lang_len && *p_hlg == 'C') {
// any C like setting, such as C.UTF-8, becomes "en"
p_hlg[0] = 'e';
p_hlg[1] = 'n';
@@ -948,7 +964,7 @@ static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void
int len = 0;
if (op == OP_REMOVING || (flags & P_NODUP)) {
len = (int)strlen(newval);
- s = find_dup_item(origval, newval, flags);
+ s = find_dup_item(origval, newval, (size_t)len, flags);
// do not add if already there
if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) {
@@ -1200,8 +1216,9 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
// Different ways to set a number option:
// & set to default value
// < set to global value
- // <xx> accept special key codes for 'wildchar'
- // c accept any non-digit for 'wildchar'
+ // <xx> accept special key codes for 'wildchar' or 'wildcharm'
+ // ^x accept ctrl key codes for 'wildchar' or 'wildcharm'
+ // c accept any non-digit for 'wildchar' or 'wildcharm'
// [-]0-9 set number
// other error
arg++;
@@ -1223,7 +1240,7 @@ static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T pr
|| (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1]))
&& !ascii_isdigit(*arg)))) {
newval_num = string_to_key(arg);
- if (newval_num == 0 && (OptInt *)varp != &p_wcm) {
+ if (newval_num == 0) {
*errmsg = e_invarg;
return newval;
}
@@ -1462,11 +1479,10 @@ int do_set(char *arg, int opt_flags)
}
if (errmsg != NULL) {
- xstrlcpy(IObuff, _(errmsg), IOSIZE);
- int i = (int)strlen(IObuff) + 2;
+ int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2;
if (i + (arg - startarg) < IOSIZE) {
// append the argument with the error
- xstrlcat(IObuff, ": ", IOSIZE);
+ xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2));
assert(arg >= startarg);
memmove(IObuff + i, startarg, (size_t)(arg - startarg));
IObuff[i + (arg - startarg)] = NUL;
@@ -1509,7 +1525,9 @@ static int find_key_len(const char *arg_arg, size_t len, bool has_lt)
// Don't use get_special_key_code() for t_xx, we don't want it to call
// add_termcap_entry().
if (len >= 4 && arg[0] == 't' && arg[1] == '_') {
- key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]);
+ if (!has_lt || arg[4] == '>') {
+ key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]);
+ }
} else if (has_lt) {
arg--; // put arg at the '<'
int modifiers = 0;
@@ -1523,14 +1541,18 @@ static int find_key_len(const char *arg_arg, size_t len, bool has_lt)
}
/// Convert a key name or string into a key value.
-/// Used for 'wildchar' and 'cedit' options.
+/// Used for 'cedit', 'wildchar' and 'wildcharm' options.
int string_to_key(char *arg)
{
- if (*arg == '<') {
+ if (*arg == '<' && arg[1]) {
return find_key_len(arg + 1, strlen(arg), true);
}
- if (*arg == '^') {
- return CTRL_CHR((uint8_t)arg[1]);
+ if (*arg == '^' && arg[1]) {
+ int key = CTRL_CHR((uint8_t)arg[1]);
+ if (key == 0) { // ^@ is <Nul>
+ key = K_ZERO;
+ }
+ return key;
}
return (uint8_t)(*arg);
}
@@ -2473,7 +2495,7 @@ static const char *did_set_scrollbind(optset_T *args)
return NULL;
}
do_check_scrollbind(false);
- win->w_scbind_pos = win->w_topline;
+ win->w_scbind_pos = get_vtopline(win);
return NULL;
}
@@ -4569,6 +4591,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
return &(buf->b_p_def);
case PV_INC:
return &(buf->b_p_inc);
+ case PV_COT:
+ return &(buf->b_p_cot);
case PV_DICT:
return &(buf->b_p_dict);
case PV_TSR:
@@ -4652,6 +4676,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var;
case PV_INC:
return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var;
+ case PV_COT:
+ return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var;
case PV_DICT:
return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var;
case PV_TSR:
@@ -5078,6 +5104,12 @@ void clear_winopt(winopt_T *wop)
void didset_window_options(win_T *wp, bool valid_cursor)
{
+ // Set w_leftcol or w_skipcol to zero.
+ if (wp->w_p_wrap) {
+ wp->w_leftcol = 0;
+ } else {
+ wp->w_skipcol = 0;
+ }
check_colorcolumn(wp);
briopt_check(wp);
fill_culopt_flags(NULL, wp);
@@ -5335,6 +5367,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inc = empty_string_option;
buf->b_p_inex = xstrdup(p_inex);
COPY_OPT_SCTX(buf, BV_INEX);
+ buf->b_p_cot = empty_string_option;
+ buf->b_cot_flags = 0;
buf->b_p_dict = empty_string_option;
buf->b_p_tsr = empty_string_option;
buf->b_p_tsrfu = empty_string_option;
@@ -5427,7 +5461,8 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
xp->xp_pattern = arg;
return;
}
- char *p = arg + strlen(arg) - 1;
+ char *const argend = arg + strlen(arg);
+ char *p = argend - 1;
if (*p == ' ' && *(p - 1) != '\\') {
xp->xp_pattern = p + 1;
return;
@@ -5614,7 +5649,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// Triple-backslashed escaped file names (e.g. 'path') can also be
// delimited by space.
if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON)) {
- for (p = arg + strlen(arg) - 1; p > xp->xp_pattern; p--) {
+ for (p = argend - 1; p > xp->xp_pattern; p--) {
// count number of backslashes before ' ' or ','
if (*p == ' ' || *p == ',' || (*p == ':' && (flags & P_COLON))) {
char *s = p;
@@ -5638,7 +5673,7 @@ void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags)
// An option that is a list of single-character flags should always start
// at the end as we don't complete words.
if (flags & P_FLAGLIST) {
- xp->xp_pattern = arg + strlen(arg);
+ xp->xp_pattern = argend;
}
// Some options can either be using file/dir expansions, or custom value
@@ -5948,7 +5983,7 @@ int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, c
int count = 0;
- (*matches)[count++] = xstrdup(option_val);
+ (*matches)[count++] = xmemdupz(option_val, num_flags);
if (num_flags > 1) {
// If more than one flags, split the flags up and expose each
@@ -6189,10 +6224,10 @@ bool can_bs(int what)
return vim_strchr(p_bs, what) != NULL;
}
-/// Get the local or global value of 'backupcopy'.
+/// Get the local or global value of 'backupcopy' flags.
///
/// @param buf The buffer.
-unsigned get_bkc_value(buf_T *buf)
+unsigned get_bkc_flags(buf_T *buf)
{
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
}
@@ -6208,7 +6243,7 @@ char *get_flp_value(buf_T *buf)
return buf->b_p_flp;
}
-/// Get the local or global value of the 'virtualedit' flags.
+/// Get the local or global value of 'virtualedit' flags.
unsigned get_ve_flags(win_T *wp)
{
return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU);
@@ -6420,30 +6455,29 @@ int get_sidescrolloff_value(win_T *wp)
return (int)(wp->w_p_siso < 0 ? p_siso : wp->w_p_siso);
}
-Dictionary get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena, Error *err)
+Dict get_vimoption(String name, int scope, buf_T *buf, win_T *win, Arena *arena, Error *err)
{
OptIndex opt_idx = find_option_len(name.data, name.size);
VALIDATE_S(opt_idx != kOptInvalid, "option (not found)", name.data, {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
});
return vimoption2dict(&options[opt_idx], scope, buf, win, arena);
}
-Dictionary get_all_vimoptions(Arena *arena)
+Dict get_all_vimoptions(Arena *arena)
{
- Dictionary retval = arena_dict(arena, kOptIndexCount);
+ Dict retval = arena_dict(arena, kOptIndexCount);
for (OptIndex opt_idx = 0; opt_idx < kOptIndexCount; opt_idx++) {
- Dictionary opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena);
- PUT_C(retval, options[opt_idx].fullname, DICTIONARY_OBJ(opt_dict));
+ Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena);
+ PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict));
}
return retval;
}
-static Dictionary vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win,
- Arena *arena)
+static Dict vimoption2dict(vimoption_T *opt, int req_scope, buf_T *buf, win_T *win, Arena *arena)
{
- Dictionary dict = arena_dict(arena, 13);
+ Dict dict = arena_dict(arena, 13);
PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname));
PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname));