aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-08-20 17:26:44 +0800
committerGitHub <noreply@github.com>2022-08-20 17:26:44 +0800
commitff5cfcdeab2446459ab59d44ce173ef811902c49 (patch)
tree2cad932a46390cb0d5821f13aa39f30b5be11770
parent1cc4706e94489498b12c4844c1b3a2e9aa5cc921 (diff)
downloadrneovim-ff5cfcdeab2446459ab59d44ce173ef811902c49.tar.gz
rneovim-ff5cfcdeab2446459ab59d44ce173ef811902c49.tar.bz2
rneovim-ff5cfcdeab2446459ab59d44ce173ef811902c49.zip
vim-patch:8.1.2045: the option.c file is too big (#19854)
Problem: The option.c file is too big. Solution: Split off the code dealing with strings. (Yegappan Lakshmanan, closes vim/vim#4937) https://github.com/vim/vim/commit/dac1347b4d9c1a1aef6aa73fdea08a9d1077d6ea Cherry-pick set_string_option_direct_in_win() from patch 8.1.1405. Cherry-pick shift_line() comment change from patch 8.1.2096. Move 'clipboard' default parsing to didset_string_options(). Reorder option flags to put Nvim-only flags at the end.
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/autocmd.c2
-rw-r--r--src/nvim/buffer.c1
-rw-r--r--src/nvim/diff.c7
-rw-r--r--src/nvim/eval.c1
-rw-r--r--src/nvim/eval/funcs.c1
-rw-r--r--src/nvim/ex_cmds.c1
-rw-r--r--src/nvim/ex_docmd.c1
-rw-r--r--src/nvim/ex_getln.c1
-rw-r--r--src/nvim/fileio.c1
-rw-r--r--src/nvim/help.c1
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/ops.c39
-rw-r--r--src/nvim/option.c1827
-rw-r--r--src/nvim/option.h17
-rw-r--r--src/nvim/option_defs.h212
-rw-r--r--src/nvim/optionstr.c1665
-rw-r--r--src/nvim/optionstr.h10
-rw-r--r--src/nvim/quickfix.c1
-rw-r--r--src/nvim/screen.c1
-rw-r--r--src/nvim/statusline.c1
-rw-r--r--src/nvim/syntax.c1
-rw-r--r--src/nvim/tag.c1
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/window.c1
-rw-r--r--test/unit/optionstr_spec.lua (renamed from test/unit/option_spec.lua)2
26 files changed, 1933 insertions, 1865 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a9787787d1..ce91c1b4af 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -52,6 +52,7 @@
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/process.h"
#include "nvim/popupmenu.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index b5b2a73be1..579c6c029f 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -25,7 +25,7 @@
#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/map.h"
-#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 88b7cfc8ee..1ff0140162 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -66,6 +66,7 @@
#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index c1fdbc1b9a..5485d528f7 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -34,6 +34,7 @@
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
@@ -1407,8 +1408,6 @@ void diff_win_options(win_T *wp, int addbuf)
}
wp->w_p_wrap = false;
}
- curwin = wp; // -V519
- curbuf = curwin->w_buffer;
if (!wp->w_p_diff) {
if (wp->w_p_diff_saved) {
@@ -1416,9 +1415,7 @@ void diff_win_options(win_T *wp, int addbuf)
}
wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm);
}
- set_string_option_direct("fdm", -1, "diff", OPT_LOCAL | OPT_FREE, 0);
- curwin = old_curwin;
- curbuf = curwin->w_buffer;
+ set_string_option_direct_in_win(wp, "fdm", -1, "diff", OPT_LOCAL | OPT_FREE, 0);
if (!wp->w_p_diff) {
wp->w_p_fen_save = wp->w_p_fen;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index f2fe106224..c39fe44162 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -41,6 +41,7 @@
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1798d43c6c..940f245d53 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -56,6 +56,7 @@
#include "nvim/msgpack_rpc/server.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/dl.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 66176620a5..06a372bb93 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -56,6 +56,7 @@
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index afa8a276c8..6cd6e32e72 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -61,6 +61,7 @@
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 776bdd935b..4629cb98ea 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -63,6 +63,7 @@
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index d29a0f0a08..5dfcbb0668 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -42,6 +42,7 @@
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
diff --git a/src/nvim/help.c b/src/nvim/help.c
index 172d389e74..569f68e330 100644
--- a/src/nvim/help.c
+++ b/src/nvim/help.c
@@ -17,6 +17,7 @@
#include "nvim/help.h"
#include "nvim/memory.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/path.h"
#include "nvim/strings.h"
diff --git a/src/nvim/main.c b/src/nvim/main.c
index fd31ba6c66..d06b475934 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -52,6 +52,7 @@
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/fileio.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 50f9650a8a..3be4536f16 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -288,13 +288,13 @@ void shift_line(int left, int round, int amount, int call_changed_bytes)
{
int count;
int i, j;
- int p_sw = (int)get_sw_value_indent(curbuf);
+ const int sw_val = (int)get_sw_value_indent(curbuf);
count = get_indent(); // get current indent
if (round) { // round off indent
- i = count / p_sw; // number of p_sw rounded down
- j = count % p_sw; // extra spaces
+ i = count / sw_val; // number of 'shiftwidth' rounded down
+ j = count % sw_val; // extra spaces
if (j && left) { // first remove extra spaces
amount--;
}
@@ -306,15 +306,15 @@ void shift_line(int left, int round, int amount, int call_changed_bytes)
} else {
i += amount;
}
- count = i * p_sw;
+ count = i * sw_val;
} else { // original vi indent
if (left) {
- count -= p_sw * amount;
+ count -= sw_val * amount;
if (count < 0) {
count = 0;
}
} else {
- count += p_sw * amount;
+ count += sw_val * amount;
}
}
@@ -334,9 +334,8 @@ static void shift_block(oparg_T *oap, int amount)
const int oldstate = State;
char_u *newp;
const int oldcol = curwin->w_cursor.col;
- int p_sw = (int)get_sw_value_indent(curbuf);
- long *p_vts = curbuf->b_p_vts_array;
- const long p_ts = curbuf->b_p_ts;
+ const int sw_val = (int)get_sw_value_indent(curbuf);
+ const int ts_val = (int)curbuf->b_p_ts;
struct block_def bd;
int incr;
int i = 0, j = 0;
@@ -351,8 +350,8 @@ static void shift_block(oparg_T *oap, int amount)
}
// total is number of screen columns to be inserted/removed
- int total = (int)((unsigned)amount * (unsigned)p_sw);
- if ((total / p_sw) != amount) {
+ int total = (int)((unsigned)amount * (unsigned)sw_val);
+ if ((total / sw_val) != amount) {
return; // multiplication overflow
}
@@ -387,7 +386,7 @@ static void shift_block(oparg_T *oap, int amount)
// OK, now total=all the VWS reqd, and textstart points at the 1st
// non-ws char in the block.
if (!curbuf->b_p_et) {
- tabstop_fromto(ws_vcol, ws_vcol + total, p_ts, p_vts, &i, &j);
+ tabstop_fromto(ws_vcol, ws_vcol + total, ts_val, curbuf->b_p_vts_array, &i, &j);
} else {
j = total;
}
@@ -511,7 +510,7 @@ static void shift_block(oparg_T *oap, int amount)
/// Caller must prepare for undo.
static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def *bdp)
{
- int p_ts;
+ int ts_val;
int count = 0; // extra spaces to replace a cut TAB
int spaces = 0; // non-zero if cutting a TAB
colnr_T offset; // pointer along new line
@@ -530,18 +529,18 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
oldp = ml_get(lnum);
if (b_insert) {
- p_ts = bdp->start_char_vcols;
+ ts_val = bdp->start_char_vcols;
spaces = bdp->startspaces;
if (spaces != 0) {
- count = p_ts - 1; // we're cutting a TAB
+ count = ts_val - 1; // we're cutting a TAB
}
offset = bdp->textcol;
} else { // append
- p_ts = bdp->end_char_vcols;
+ ts_val = bdp->end_char_vcols;
if (!bdp->is_short) { // spaces = padding after block
- spaces = (bdp->endspaces ? p_ts - bdp->endspaces : 0);
+ spaces = (bdp->endspaces ? ts_val - bdp->endspaces : 0);
if (spaces != 0) {
- count = p_ts - 1; // we're cutting a TAB
+ count = ts_val - 1; // we're cutting a TAB
}
offset = bdp->textcol + bdp->textlen - (spaces != 0);
} else { // spaces = padding to block edge
@@ -565,7 +564,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
assert(count >= 0);
// Make sure the allocated size matches what is actually copied below.
newp = xmalloc(STRLEN(oldp) + (size_t)spaces + s_len
- + (spaces > 0 && !bdp->is_short ? (size_t)p_ts - (size_t)spaces : 0)
+ + (spaces > 0 && !bdp->is_short ? (size_t)ts_val - (size_t)spaces : 0)
+ (size_t)count + 1);
// copy up to shifted part
@@ -584,7 +583,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
if (spaces > 0 && !bdp->is_short) {
if (*oldp == TAB) {
// insert post-padding
- memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces));
+ memset(newp + offset + spaces, ' ', (size_t)(ts_val - spaces));
// We're splitting a TAB, don't copy it.
oldp++;
// We allowed for that TAB, remember this now
diff --git a/src/nvim/option.c b/src/nvim/option.c
index e85a0d9ee4..5c487a7c62 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -31,16 +31,13 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
-#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
#include "nvim/decoration_provider.h"
#include "nvim/diff.h"
-#include "nvim/digraph.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/vars.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -54,7 +51,6 @@
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
-#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/macros.h"
#include "nvim/mapping.h"
@@ -68,12 +64,12 @@
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/popupmenu.h"
#include "nvim/regexp.h"
-#include "nvim/runtime.h"
#include "nvim/screen.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
@@ -94,7 +90,6 @@
#include "nvim/lua/executor.h"
#include "nvim/os/input.h"
#include "nvim/os/lang.h"
-#include "nvim/quickfix.h"
/*
* The options that are local to a window or buffer have "indir" set to one of
@@ -127,73 +122,6 @@ typedef enum {
static char *p_term = NULL;
static char *p_ttytype = NULL;
-/*
- * These are the global values for options which are also local to a buffer.
- * Only to be used in option.c!
- */
-static int p_ai;
-static int p_bin;
-static int p_bomb;
-static char_u *p_bh;
-static char_u *p_bt;
-static int p_bl;
-static long p_channel;
-static int p_ci;
-static int p_cin;
-static char_u *p_cink;
-static char_u *p_cino;
-static char_u *p_cinw;
-static char_u *p_cinsd;
-static char_u *p_com;
-static char_u *p_cms;
-static char_u *p_cpt;
-static char_u *p_cfu;
-static char_u *p_ofu;
-static char_u *p_tfu;
-static int p_eol;
-static int p_fixeol;
-static int p_et;
-static char_u *p_fenc;
-static char_u *p_ff;
-static char_u *p_fo;
-static char_u *p_flp;
-static char_u *p_ft;
-static long p_iminsert;
-static long p_imsearch;
-static char_u *p_inex;
-static char_u *p_inde;
-static char_u *p_indk;
-static char_u *p_fex;
-static int p_inf;
-static char_u *p_isk;
-static int p_lisp;
-static int p_ml;
-static int p_ma;
-static int p_mod;
-static char_u *p_mps;
-static char_u *p_nf;
-static int p_pi;
-static char_u *p_qe;
-static int p_ro;
-static int p_si;
-static long p_sts;
-static char_u *p_sua;
-static long p_sw;
-static int p_swf;
-static long p_smc;
-static char_u *p_syn;
-static char_u *p_spc;
-static char_u *p_spf;
-static char_u *p_spl;
-static char_u *p_spo;
-static long p_ts;
-static long p_tw;
-static int p_udf;
-static long p_wm;
-static char_u *p_vsts;
-static char_u *p_vts;
-static char_u *p_keymap;
-
// Saved values for when 'bin' is set.
static int p_et_nobin;
static int p_ml_nobin;
@@ -222,64 +150,6 @@ typedef struct vimoption {
} vimoption_T;
/*
- * Flags
- */
-#define P_BOOL 0x01U // the option is boolean
-#define P_NUM 0x02U // the option is numeric
-#define P_STRING 0x04U // the option is a string
-#define P_ALLOCED 0x08U // the string option is in allocated memory,
- // must use free_string_option() when
- // assigning new value. Not set if default is
- // the same.
-#define P_EXPAND 0x10U // environment expansion. NOTE: P_EXPAND can
- // never be used for local or hidden options
-#define P_NODEFAULT 0x40U // don't set to default value
-#define P_DEF_ALLOCED 0x80U // default value is in allocated memory, must
- // use free() when assigning new value
-#define P_WAS_SET 0x100U // option has been set/reset
-#define P_NO_MKRC 0x200U // don't include in :mkvimrc output
-
-// when option changed, what to display:
-#define P_RSTAT 0x1000U ///< redraw status lines
-#define P_RWIN 0x2000U ///< redraw current window and recompute text
-#define P_RBUF 0x4000U ///< redraw current buffer and recompute text
-#define P_RALL 0x6000U ///< redraw all windows
-#define P_RCLR 0x7000U ///< clear and redraw all
-
-#define P_COMMA 0x8000U ///< comma separated list
-#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive
- ///< commas
-#define P_NODUP 0x20000U ///< don't allow duplicate strings
-#define P_FLAGLIST 0x40000U ///< list of single-char flags
-
-#define P_SECURE 0x80000U ///< cannot change in modeline or secure mode
-#define P_GETTEXT 0x100000U ///< expand default value with _()
-#define P_NOGLOB 0x200000U ///< do not use local value for global vimrc
-#define P_NFNAME 0x400000U ///< only normal file name chars allowed
-#define P_INSECURE 0x800000U ///< option was set from a modeline
-#define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option
- ///< has side effects)
-#define P_NO_ML 0x2000000U ///< not allowed in modeline
-#define P_CURSWANT 0x4000000U ///< update curswant required; not needed
- ///< when there is a redraw flag
-#define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value.
-
-#define P_RWINONLY 0x10000000U ///< only redraw current window
-#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed
-#define P_UI_OPTION 0x40000000U ///< send option to remote ui
-#define P_MLE 0x80000000U ///< under control of 'modelineexpr'
-
-#define HIGHLIGHT_INIT \
- "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
- "i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \
- "N:CursorLineNr,G:CursorLineSign,O:CursorLineFold" \
- "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \
- "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \
- "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \
- "X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \
- "q:QuickFixLine,0:Whitespace,I:NormalNC"
-
-/*
* options[] is initialized here.
* The order of the options MUST be alphabetic for ":set all" and findoption().
* All option names MUST start with a lowercase letter (for findoption()).
@@ -294,59 +164,6 @@ typedef struct vimoption {
#define OPTION_COUNT ARRAY_SIZE(options)
-static char *(p_ambw_values[]) = { "single", "double", NULL };
-static char *(p_bg_values[]) = { "light", "dark", NULL };
-static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha",
- "unsigned", NULL };
-static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
-static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
-static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",
- "mac", NULL };
-static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
-static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
-static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
-static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
-static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
-static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
-static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
- "help", "acwrite", "terminal",
- "prompt", NULL };
-
-static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
- "wipe", NULL };
-static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL };
-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 };
-#ifdef BACKSLASH_IN_FILENAME
-static char *(p_csl_values[]) = { "slash", "backslash", NULL };
-#endif
-static char *(p_icm_values[]) = { "nosplit", "split", NULL };
-static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
- "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8",
- "auto:9",
- "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6",
- "yes:7", "yes:8",
- "yes:9", "number", NULL };
-static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2",
- "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8",
- "auto:9",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
-
-/// All possible flags for 'shm'.
-static char_u SHM_ALL[] = {
- SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI,
- SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER,
- SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU,
- SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT,
- 0,
-};
-
-static char e_unclosed_expression_sequence[] = N_("E540: Unclosed expression sequence");
-static char e_unbalanced_groups[] = N_("E542: unbalanced groups");
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.c.generated.h"
#endif
@@ -1751,7 +1568,7 @@ theend:
/// @param opt_flags possibly with OPT_MODELINE
/// @param new_value value was replaced completely
/// @param value_checked value was checked to be safe, no need to set P_INSECURE
-static void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked)
+void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked)
{
options[opt_idx].flags |= P_WAS_SET;
@@ -1768,16 +1585,6 @@ static void did_set_option(int opt_idx, int opt_flags, int new_value, int value_
}
}
-static char *illegal_char(char *errbuf, size_t errbuflen, int c)
-{
- if (errbuf == NULL) {
- return "";
- }
- vim_snprintf(errbuf, errbuflen, _("E539: Illegal character <%s>"),
- (char *)transchar(c));
- return errbuf;
-}
-
/// Convert a key name or string into a key value.
/// Used for 'wildchar' and 'cedit' options.
static int string_to_key(char_u *arg)
@@ -1793,7 +1600,7 @@ static int string_to_key(char_u *arg)
/// Check value of 'cedit' and set cedit_key.
/// Returns NULL if value is OK, error message otherwise.
-static char *check_cedit(void)
+char *check_cedit(void)
{
int n;
@@ -1813,7 +1620,7 @@ static char *check_cedit(void)
// maketitle() to create and display it.
// When switching the title or icon off, call ui_set_{icon,title}(NULL) to get
// the old value back.
-static void did_set_title(void)
+void did_set_title(void)
{
if (starting != NO_SCREEN) {
maketitle();
@@ -1952,26 +1759,6 @@ static char_u *option_expand(int opt_idx, char_u *val)
/// After setting various option values: recompute variables that depend on
/// option values.
-static 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_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_jop, p_jop_values, &jop_flags, true);
-}
-
-/// After setting various option values: recompute variables that depend on
-/// option values.
static void didset_options(void)
{
// initialize the table for 'iskeyword' et.al.
@@ -1996,9 +1783,6 @@ static void didset_options2(void)
// Initialize the highlight_attr[] table.
highlight_changed();
- // Parse default for 'clipboard'.
- (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
-
// Parse default for 'fillchars'.
(void)set_chars_option(curwin, &curwin->w_p_fcs, true);
@@ -2025,91 +1809,6 @@ void check_options(void)
}
}
-/// Check string options in a buffer for NULL value.
-void check_buf_options(buf_T *buf)
-{
- check_string_option(&buf->b_p_bh);
- check_string_option(&buf->b_p_bt);
- check_string_option(&buf->b_p_fenc);
- check_string_option(&buf->b_p_ff);
- check_string_option(&buf->b_p_def);
- check_string_option(&buf->b_p_inc);
- check_string_option(&buf->b_p_inex);
- check_string_option(&buf->b_p_inde);
- check_string_option(&buf->b_p_indk);
- check_string_option(&buf->b_p_fp);
- check_string_option(&buf->b_p_fex);
- check_string_option(&buf->b_p_kp);
- check_string_option(&buf->b_p_mps);
- check_string_option(&buf->b_p_fo);
- check_string_option(&buf->b_p_flp);
- check_string_option(&buf->b_p_isk);
- check_string_option(&buf->b_p_com);
- check_string_option(&buf->b_p_cms);
- check_string_option(&buf->b_p_nf);
- check_string_option(&buf->b_p_qe);
- check_string_option(&buf->b_p_syn);
- check_string_option(&buf->b_s.b_syn_isk);
- check_string_option(&buf->b_s.b_p_spc);
- check_string_option(&buf->b_s.b_p_spf);
- check_string_option(&buf->b_s.b_p_spl);
- check_string_option(&buf->b_s.b_p_spo);
- check_string_option(&buf->b_p_sua);
- check_string_option(&buf->b_p_cink);
- check_string_option(&buf->b_p_cino);
- parse_cino(buf);
- check_string_option(&buf->b_p_ft);
- check_string_option(&buf->b_p_cinw);
- check_string_option(&buf->b_p_cinsd);
- check_string_option(&buf->b_p_cpt);
- check_string_option(&buf->b_p_cfu);
- check_string_option(&buf->b_p_ofu);
- check_string_option(&buf->b_p_keymap);
- check_string_option(&buf->b_p_gp);
- check_string_option(&buf->b_p_mp);
- check_string_option(&buf->b_p_efm);
- check_string_option(&buf->b_p_ep);
- check_string_option(&buf->b_p_path);
- check_string_option(&buf->b_p_tags);
- check_string_option(&buf->b_p_tfu);
- check_string_option(&buf->b_p_tc);
- check_string_option(&buf->b_p_dict);
- check_string_option(&buf->b_p_tsr);
- check_string_option(&buf->b_p_tsrfu);
- check_string_option(&buf->b_p_lw);
- check_string_option(&buf->b_p_bkc);
- check_string_option(&buf->b_p_menc);
- check_string_option(&buf->b_p_vsts);
- check_string_option(&buf->b_p_vts);
-}
-
-/// Free the string allocated for an option.
-/// Checks for the string being empty_option. This may happen if we're out of
-/// memory, vim_strsave() returned NULL, which was replaced by empty_option by
-/// check_options().
-/// Does NOT check for P_ALLOCED flag!
-void free_string_option(char_u *p)
-{
- if (p != empty_option) {
- xfree(p);
- }
-}
-
-void clear_string_option(char_u **pp)
-{
- if (*pp != empty_option) {
- xfree(*pp);
- }
- *pp = empty_option;
-}
-
-static void check_string_option(char_u **pp)
-{
- if (*pp == NULL) {
- *pp = empty_option;
- }
-}
-
/// Return true when option "opt" was set from a modeline or in secure mode.
/// Return false when it wasn't.
/// Return -1 for an unknown option.
@@ -2156,166 +1855,12 @@ static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
}
/// Redraw the window title and/or tab page text later.
-static void redraw_titles(void)
+void redraw_titles(void)
{
need_maketitle = true;
redraw_tabline = true;
}
-static int shada_idx = -1;
-
-/// 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.
-/// 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
-void set_string_option_direct(const char *name, int opt_idx, const char *val, int opt_flags,
- int set_sid)
-{
- char *s;
- char **varp;
- 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;
- }
- }
-
- if (options[idx].var == NULL) { // can't set hidden option
- return;
- }
-
- assert((void *)options[idx].var != (void *)&p_shada);
-
- s = xstrdup(val);
- {
- varp = (char **)get_varp_scope(&(options[idx]), both ? OPT_LOCAL : opt_flags);
- if ((opt_flags & OPT_FREE) && (options[idx].flags & P_ALLOCED)) {
- free_string_option((char_u *)(*varp));
- }
- *varp = s;
-
- // For buffer/window local option may also set the global value.
- if (both) {
- set_string_option_global(idx, (char_u **)varp);
- }
-
- options[idx].flags |= P_ALLOCED;
-
- /* 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 (((int)options[idx].indir & PV_BOTH) && both) {
- free_string_option((char_u *)(*varp));
- *varp = (char *)empty_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_idx(idx, opt_flags, script_ctx);
- }
- }
-}
-
-/// Set global value for string option when it's a local option.
-///
-/// @param opt_idx option index
-/// @param varp pointer to option variable
-static void set_string_option_global(int opt_idx, char_u **varp)
-{
- char_u **p, *s;
-
- // the global value is always allocated
- if (options[opt_idx].var == VAR_WIN) {
- p = (char_u **)GLOBAL_WO(varp);
- } else {
- p = (char_u **)options[opt_idx].var;
- }
- if (options[opt_idx].indir != PV_NONE && p != varp) {
- s = vim_strsave(*varp);
- free_string_option(*p);
- *p = s;
- }
-}
-
-/// Set a string option to a new value, handling the effects
-///
-/// @param[in] opt_idx Option to set.
-/// @param[in] value New value.
-/// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or
-/// #OPT_GLOBAL.
-///
-/// @return NULL on success, error message on error.
-static char *set_string_option(const int opt_idx, const char *const value, const int opt_flags)
- FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (options[opt_idx].var == NULL) { // don't set hidden option
- return NULL;
- }
-
- char *const s = xstrdup(value);
- char **const varp = (char **)get_varp_scope(&(options[opt_idx]),
- ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
- ? (((int)options[opt_idx].indir & PV_BOTH)
- ? OPT_GLOBAL : OPT_LOCAL)
- : opt_flags));
- char *const oldval = *varp;
- char *oldval_l = NULL;
- char *oldval_g = NULL;
-
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- oldval_l = *(char **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
- oldval_g = *(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
- }
-
- *varp = s;
-
- char *const saved_oldval = xstrdup(oldval);
- char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup(oldval_l) : 0;
- char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup(oldval_g) : 0;
- char *const saved_newval = xstrdup(s);
-
- int value_checked = false;
- char *const r = did_set_string_option(opt_idx, (char_u **)varp, (char_u *)oldval,
- NULL, 0,
- opt_flags, &value_checked);
- if (r == NULL) {
- did_set_option(opt_idx, opt_flags, true, value_checked);
- }
-
- // call autocommand after handling side effects
- if (r == NULL) {
- if (!starting) {
- trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g,
- saved_newval);
- }
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- STRING_OBJ(cstr_as_string(saved_newval)));
- }
- }
- xfree(saved_oldval);
- xfree(saved_oldval_l);
- xfree(saved_oldval_g);
- xfree(saved_newval);
-
- return r;
-}
-
/// Return true if "val" is a valid name: only consists of alphanumeric ASCII
/// characters or characters in "allowed".
bool valid_name(const char_u *val, const char *allowed)
@@ -2330,1200 +1875,12 @@ bool valid_name(const char_u *val, const char *allowed)
return true;
}
-/// Return true if "val" is a valid 'filetype' name.
-/// Also used for 'syntax' and 'keymap'.
-static bool valid_filetype(const char_u *val)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- return valid_name(val, ".-_");
-}
-
-/// Handle setting 'mousescroll'.
-/// @return error message, NULL if it's OK.
-static char *check_mousescroll(char *string)
-{
- long vertical = -1;
- long horizontal = -1;
-
- for (;;) {
- char *end = vim_strchr(string, ',');
- size_t length = end ? (size_t)(end - string) : STRLEN(string);
-
- // Both "ver:" and "hor:" are 4 bytes long.
- // They should be followed by at least one digit.
- if (length <= 4) {
- return e_invarg;
- }
-
- long *direction;
-
- if (memcmp(string, "ver:", 4) == 0) {
- direction = &vertical;
- } else if (memcmp(string, "hor:", 4) == 0) {
- direction = &horizontal;
- } else {
- return e_invarg;
- }
-
- // If the direction has already been set, this is a duplicate.
- if (*direction != -1) {
- return e_invarg;
- }
-
- // Verify that only digits follow the colon.
- for (size_t i = 4; i < length; i++) {
- if (!ascii_isdigit(string[i])) {
- return N_("E548: digit expected");
- }
- }
-
- string += 4;
- *direction = getdigits_int(&string, false, -1);
-
- // Num options are generally kept within the signed int range.
- // We know this number won't be negative because we've already checked for
- // a minus sign. We'll allow 0 as a means of disabling mouse scrolling.
- if (*direction == -1) {
- return e_invarg;
- }
-
- if (!end) {
- break;
- }
-
- string = end + 1;
- }
-
- // If a direction wasn't set, fallback to the default value.
- p_mousescroll_vert = (vertical == -1) ? MOUSESCROLL_VERT_DFLT : vertical;
- p_mousescroll_hor = (horizontal == -1) ? MOUSESCROLL_HOR_DFLT : horizontal;
-
- return NULL;
-}
-
-/// Handle string options that need some action to perform when changed.
-/// The new value must be allocated.
-/// Returns NULL for success, or an error message for an error.
-///
-/// @param opt_idx index in options[] table
-/// @param varp pointer to the option variable
-/// @param oldval previous value of the option
-/// @param errbuf buffer for errors, or NULL
-/// @param errbuflen length of errors buffer
-/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
-/// @param value_checked value was checked to be safe, no need to set P_INSECURE
-static char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *errbuf,
- size_t errbuflen, int opt_flags, int *value_checked)
-{
- char *errmsg = NULL;
- char *s, *p;
- int did_chartab = false;
- char_u **gvarp;
- bool free_oldval = (options[opt_idx].flags & P_ALLOCED);
- bool value_changed = false;
-
- /* Get the global option to compare with, otherwise we would have to check
- * two values for all local options. */
- gvarp = (char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
-
- // Disallow changing some options from secure mode
- if ((secure || sandbox != 0)
- && (options[opt_idx].flags & P_SECURE)) {
- errmsg = e_secure;
- } else if (((options[opt_idx].flags & P_NFNAME)
- && strpbrk((char *)(*varp),
- (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
- || ((options[opt_idx].flags & P_NDNAME)
- && strpbrk((char *)(*varp), "*?[|;&<>\r\n") != NULL)) {
- // Check for a "normal" directory or file name in some options. Disallow a
- // path separator (slash and/or backslash), wildcards and characters that
- // are often illegal in a file name. Be more permissive if "secure" is off.
- errmsg = e_invarg;
- } else if (gvarp == &p_bkc) { // 'backupcopy'
- char_u *bkc = p_bkc;
- unsigned int *flags = &bkc_flags;
-
- if (opt_flags & OPT_LOCAL) {
- bkc = curbuf->b_p_bkc;
- flags = &curbuf->b_bkc_flags;
- }
-
- if ((opt_flags & OPT_LOCAL) && *bkc == NUL) {
- // make the local value empty: use the global value
- *flags = 0;
- } else {
- if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) {
- errmsg = e_invarg;
- }
-
- if (((*flags & BKC_AUTO) != 0)
- + ((*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);
- errmsg = e_invarg;
- }
- }
- } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode'
- if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
- *p_pm == '.' ? p_pm + 1 : p_pm) == 0) {
- errmsg = N_("E589: 'backupext' and 'patchmode' are equal");
- }
- } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt'
- if (briopt_check(curwin) == FAIL) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_isi
- || varp == &(curbuf->b_p_isk)
- || varp == &p_isp
- || varp == &p_isf) {
- // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
- // If the new option is invalid, use old value. 'lisp' option: refill
- // g_chartab[] for '-' char
- if (init_chartab() == FAIL) {
- did_chartab = true; // need to restore it below
- errmsg = e_invarg; // error in value
- }
- } else if (varp == &p_hf) { // 'helpfile'
- // May compute new values for $VIM and $VIMRUNTIME
- if (didset_vim) {
- os_setenv("VIM", "", 1);
- didset_vim = false;
- }
- if (didset_vimruntime) {
- os_setenv("VIMRUNTIME", "", 1);
- didset_vimruntime = false;
- }
- } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath'
- runtime_search_path_invalidate();
- } else if (varp == &curwin->w_p_culopt
- || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
- if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &curwin->w_p_cc) { // 'colorcolumn'
- errmsg = check_colorcolumn(curwin);
- } else if (varp == &p_hlg) { // 'helplang'
- // Check for "", "ab", "ab,cd", etc.
- for (s = (char *)p_hlg; *s != NUL; s += 3) {
- if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) {
- errmsg = e_invarg;
- break;
- }
- if (s[2] == NUL) {
- break;
- }
- }
- } else if (varp == &p_hl) {
- // 'highlight'
- if (STRCMP(*varp, HIGHLIGHT_INIT) != 0) {
- errmsg = e_unsupportedoption;
- }
- } else if (varp == &p_jop) { // 'jumpoptions'
- if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_nf) { // 'nrformats'
- if (check_opt_strings(*varp, p_nf_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_ssop) { // 'sessionoptions'
- if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) {
- errmsg = e_invarg;
- }
- if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
- // Don't allow both "sesdir" and "curdir".
- (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
- errmsg = e_invarg;
- }
- } else if (varp == &p_vop) { // 'viewoptions'
- if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_rdb) { // 'redrawdebug'
- if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == (char_u **)&p_sbo) { // 'scrollopt'
- if (check_opt_strings((char_u *)p_sbo, p_scbopt_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_ambw || (int *)varp == &p_emoji) {
- // 'ambiwidth'
- if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) {
- errmsg = e_invarg;
- } else {
- errmsg = check_chars_options();
- }
- } else if (varp == &p_bg) { // 'background'
- if (check_opt_strings(p_bg, p_bg_values, false) == OK) {
- int dark = (*p_bg == 'd');
-
- init_highlight(false, false);
-
- if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) {
- // The color scheme must have set 'background' back to another
- // value, that's not what we want here. Disable the color
- // scheme and set the colors again.
- do_unlet(S_LEN("g:colors_name"), true);
- free_string_option(p_bg);
- p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
- check_string_option(&p_bg);
- init_highlight(false, false);
- }
- } else {
- errmsg = e_invarg;
- }
- } else if (varp == &p_wim) { // 'wildmode'
- if (check_opt_wim() == FAIL) {
- errmsg = e_invarg;
- }
- // 'wildoptions'
- } else if (varp == &p_wop) {
- if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_wak) { // 'winaltkeys'
- if (*p_wak == NUL
- || check_opt_strings(p_wak, p_wak_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_ei) { // 'eventignore'
- if (check_ei() == FAIL) {
- errmsg = e_invarg;
- }
- // 'encoding', 'fileencoding' and 'makeencoding'
- } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) {
- if (gvarp == &p_fenc) {
- if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) {
- errmsg = e_modifiable;
- } else if (vim_strchr((char *)(*varp), ',') != NULL) {
- // No comma allowed in 'fileencoding'; catches confusing it
- // with 'fileencodings'.
- errmsg = e_invarg;
- } else {
- // May show a "+" in the title now.
- redraw_titles();
- // Add 'fileencoding' to the swap file.
- ml_setflags(curbuf);
- }
- }
-
- if (errmsg == NULL) {
- // canonize the value, so that STRCMP() can be used on it
- p = (char *)enc_canonize(*varp);
- xfree(*varp);
- *varp = (char_u *)p;
- if (varp == &p_enc) {
- // only encoding=utf-8 allowed
- if (STRCMP(p_enc, "utf-8") != 0) {
- errmsg = e_unsupportedoption;
- } else {
- spell_reload();
- }
- }
- }
- } else if (varp == &p_penc) {
- // Canonize printencoding if VIM standard one
- p = (char *)enc_canonize(p_penc);
- xfree(p_penc);
- p_penc = (char_u *)p;
- } else if (varp == &curbuf->b_p_keymap) {
- if (!valid_filetype(*varp)) {
- errmsg = e_invarg;
- } else {
- int secure_save = secure;
-
- // Reset the secure flag, since the value of 'keymap' has
- // been checked to be safe.
- secure = 0;
-
- // load or unload key mapping tables
- errmsg = keymap_init();
-
- secure = secure_save;
-
- // Since we check the value, there is no need to set P_INSECURE,
- // even when the value comes from a modeline.
- *value_checked = true;
- }
-
- if (errmsg == NULL) {
- if (*curbuf->b_p_keymap != NUL) {
- // Installed a new keymap, switch on using it.
- curbuf->b_p_iminsert = B_IMODE_LMAP;
- if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) {
- curbuf->b_p_imsearch = B_IMODE_LMAP;
- }
- } else {
- // Cleared the keymap, may reset 'iminsert' and 'imsearch'.
- if (curbuf->b_p_iminsert == B_IMODE_LMAP) {
- curbuf->b_p_iminsert = B_IMODE_NONE;
- }
- if (curbuf->b_p_imsearch == B_IMODE_LMAP) {
- curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
- }
- }
- if ((opt_flags & OPT_LOCAL) == 0) {
- set_iminsert_global();
- set_imsearch_global();
- }
- status_redraw_curbuf();
- }
- } else if (gvarp == &p_ff) { // 'fileformat'
- if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) {
- errmsg = e_modifiable;
- } else if (check_opt_strings(*varp, p_ff_values, false) != OK) {
- errmsg = e_invarg;
- } else {
- redraw_titles();
- // update flag in swap file
- ml_setflags(curbuf);
- /* Redraw needed when switching to/from "mac": a CR in the text
- * will be displayed differently. */
- if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') {
- redraw_curbuf_later(NOT_VALID);
- }
- }
- } else if (varp == (char_u **)&p_ffs) { // 'fileformats'
- if (check_opt_strings((char_u *)p_ffs, p_ff_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_mps) { // 'matchpairs'
- for (p = (char *)(*varp); *p != NUL; p++) {
- int x2 = -1;
- int x3 = -1;
-
- p += utfc_ptr2len(p);
- if (*p != NUL) {
- x2 = (unsigned char)(*p++);
- }
- if (*p != NUL) {
- x3 = utf_ptr2char(p);
- p += utfc_ptr2len(p);
- }
- if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) {
- errmsg = e_invarg;
- break;
- }
- if (*p == NUL) {
- break;
- }
- }
- } else if (gvarp == &p_com) { // 'comments'
- for (s = (char *)(*varp); *s;) {
- while (*s && *s != ':') {
- if (vim_strchr(COM_ALL, *s) == NULL
- && !ascii_isdigit(*s) && *s != '-') {
- errmsg = illegal_char(errbuf, errbuflen, *s);
- break;
- }
- s++;
- }
- if (*s++ == NUL) {
- errmsg = N_("E524: Missing colon");
- } else if (*s == ',' || *s == NUL) {
- errmsg = N_("E525: Zero length string");
- }
- if (errmsg != NULL) {
- break;
- }
- while (*s && *s != ',') {
- if (*s == '\\' && s[1] != NUL) {
- s++;
- }
- s++;
- }
- s = (char *)skip_to_option_part((char_u *)s);
- }
- } else if (varp == &p_lcs) { // global 'listchars'
- errmsg = set_chars_option(curwin, varp, false);
- if (errmsg == NULL) {
- // The current window is set to use the global 'listchars' value.
- // So clear the window-local value.
- if (!(opt_flags & OPT_GLOBAL)) {
- clear_string_option(&curwin->w_p_lcs);
- }
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- // If no error was returned above, we don't expect an error
- // here, so ignore the return value.
- (void)set_chars_option(wp, &wp->w_p_lcs, true);
- }
- redraw_all_later(NOT_VALID);
- }
- } else if (varp == &curwin->w_p_lcs) { // local 'listchars'
- 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, &wp->w_p_fcs, true);
- }
- redraw_all_later(NOT_VALID);
- }
- } else if (varp == &curwin->w_p_fcs) { // local 'fillchars'
- errmsg = set_chars_option(curwin, varp, true);
- } else if (varp == &p_cedit) { // 'cedit'
- errmsg = check_cedit();
- } else if (varp == &p_vfile) { // 'verbosefile'
- verbose_stop();
- if (*p_vfile != NUL && verbose_open() == FAIL) {
- errmsg = e_invarg;
- }
- // 'shada'
- } else if (varp == &p_shada) {
- // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
- // option.
- opt_idx = ((options[opt_idx].fullname[0] == 'v')
- ? (shada_idx == -1
- ? ((shada_idx = findoption("shada")))
- : shada_idx)
- : opt_idx);
- // Update free_oldval now that we have the opt_idx for 'shada', otherwise
- // there would be a disconnect between the check for P_ALLOCED at the start
- // of the function and the set of P_ALLOCED at the end of the function.
- free_oldval = (options[opt_idx].flags & P_ALLOCED);
- for (s = (char *)p_shada; *s;) {
- // Check it's a valid character
- if (vim_strchr("!\"%'/:<@cfhnrs", *s) == NULL) {
- errmsg = illegal_char(errbuf, errbuflen, *s);
- break;
- }
- if (*s == 'n') { // name is always last one
- break;
- } else if (*s == 'r') { // skip until next ','
- while (*++s && *s != ',') {}
- } else if (*s == '%') {
- // optional number
- while (ascii_isdigit(*++s)) {}
- } else if (*s == '!' || *s == 'h' || *s == 'c') {
- s++; // no extra chars
- } else { // must have a number
- while (ascii_isdigit(*++s)) {}
-
- if (!ascii_isdigit(*(s - 1))) {
- if (errbuf != NULL) {
- vim_snprintf(errbuf, errbuflen,
- _("E526: Missing number after <%s>"),
- transchar_byte(*(s - 1)));
- errmsg = errbuf;
- } else {
- errmsg = "";
- }
- break;
- }
- }
- if (*s == ',') {
- s++;
- } else if (*s) {
- if (errbuf != NULL) {
- errmsg = N_("E527: Missing comma");
- } else {
- errmsg = "";
- }
- break;
- }
- }
- if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) {
- errmsg = N_("E528: Must specify a ' value");
- }
- } else if (gvarp == &p_sbr) { // 'showbreak'
- for (s = (char *)(*varp); *s;) {
- if (ptr2cells(s) != 1) {
- errmsg = N_("E595: 'showbreak' contains unprintable or wide character");
- }
- MB_PTR_ADV(s);
- }
- } else if (varp == &p_guicursor) { // 'guicursor'
- errmsg = parse_shape_opt(SHAPE_CURSOR);
- } else if (varp == &p_popt) {
- errmsg = parse_printoptions();
- } else if (varp == &p_pmfn) {
- errmsg = parse_printmbfont();
- } else if (varp == &p_langmap) { // 'langmap'
- langmap_set();
- } else if (varp == &p_breakat) { // 'breakat'
- fill_breakat_flags();
- } else if (varp == &p_titlestring || varp == &p_iconstring) {
- // 'titlestring' and 'iconstring'
- int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
-
- // NULL => statusline syntax
- if (vim_strchr((char *)(*varp), '%') && check_stl_option((char *)(*varp)) == NULL) {
- stl_syntax |= flagval;
- } else {
- stl_syntax &= ~flagval;
- }
- did_set_title();
- } else if (varp == &p_sel) { // 'selection'
- if (*p_sel == NUL
- || check_opt_strings(p_sel, p_sel_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_slm) { // 'selectmode'
- if (check_opt_strings(p_slm, p_slm_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_km) { // 'keymodel'
- if (check_opt_strings(p_km, p_km_values, true) != OK) {
- errmsg = e_invarg;
- } else {
- km_stopsel = (vim_strchr((char *)p_km, 'o') != NULL);
- km_startsel = (vim_strchr((char *)p_km, 'a') != NULL);
- }
- } else if (varp == &p_mousem) { // 'mousemodel'
- if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_mousescroll) { // 'mousescroll'
- errmsg = check_mousescroll((char *)p_mousescroll);
- } else if (varp == &p_swb) { // 'switchbuf'
- if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_debug) { // 'debug'
- if (check_opt_strings(p_debug, p_debug_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_dy) { // 'display'
- if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) {
- errmsg = e_invarg;
- } else {
- (void)init_chartab();
- msg_grid_validate();
- }
- } else if (varp == &p_ead) { // 'eadirection'
- if (check_opt_strings(p_ead, p_ead_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_cb) { // 'clipboard'
- if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &(curwin->w_s->b_p_spl) // 'spell'
- || varp == &(curwin->w_s->b_p_spf)) {
- // When 'spelllang' or 'spellfile' is set and there is a window for this
- // buffer in which 'spell' is set load the wordlists.
- const bool is_spellfile = varp == &(curwin->w_s->b_p_spf);
-
- if ((is_spellfile && !valid_spellfile(*varp))
- || (!is_spellfile && !valid_spelllang(*varp))) {
- errmsg = e_invarg;
- } else {
- errmsg = did_set_spell_option(is_spellfile);
- }
- } else if (varp == &(curwin->w_s->b_p_spc)) {
- // When 'spellcapcheck' is set compile the regexp program.
- errmsg = compile_cap_prog(curwin->w_s);
- } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions'
- if (**varp != NUL && STRCMP("camel", *varp) != 0) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_sps) { // 'spellsuggest'
- if (spell_check_sps() != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_msm) { // 'mkspellmem'
- if (spell_check_msm() != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_bh) {
- // When 'bufhidden' is set, check for valid value.
- if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_bt) {
- // When 'buftype' is set, check for valid value.
- if ((curbuf->terminal && curbuf->b_p_bt[0] != 't')
- || (!curbuf->terminal && curbuf->b_p_bt[0] == 't')
- || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) {
- errmsg = e_invarg;
- } else {
- if (curwin->w_status_height || global_stl_height()) {
- curwin->w_redr_status = true;
- redraw_later(curwin, VALID);
- }
- curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
- redraw_titles();
- }
- } else if (gvarp == &p_stl || gvarp == (char_u **)&p_wbr || varp == &p_tal || varp == &p_ruf) {
- // 'statusline', 'winbar', 'tabline' or 'rulerformat'
- int wid;
-
- if (varp == &p_ruf) { // reset ru_wid first
- ru_wid = 0;
- }
- s = (char *)(*varp);
- if (varp == &p_ruf && *s == '%') {
- // set ru_wid if 'ruf' starts with "%99("
- if (*++s == '-') { // ignore a '-'
- s++;
- }
- wid = getdigits_int(&s, true, 0);
- if (wid && *s == '(' && (errmsg = check_stl_option((char *)p_ruf)) == NULL) {
- ru_wid = wid;
- } else {
- errmsg = check_stl_option((char *)p_ruf);
- }
- } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
- // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!"
- errmsg = check_stl_option(s);
- }
- if (varp == &p_ruf && errmsg == NULL) {
- comp_col();
- }
- // add / remove window bars for 'winbar'
- if (gvarp == (char_u **)&p_wbr) {
- set_winbar(true);
- }
- } else if (gvarp == &p_cpt) {
- // check if it is a valid value for 'complete' -- Acevedo
- for (s = (char *)(*varp); *s;) {
- while (*s == ',' || *s == ' ') {
- s++;
- }
- if (!*s) {
- break;
- }
- if (vim_strchr(".wbuksid]tU", *s) == NULL) {
- errmsg = illegal_char(errbuf, errbuflen, *s);
- break;
- }
- if (*++s != NUL && *s != ',' && *s != ' ') {
- if (s[-1] == 'k' || s[-1] == 's') {
- // skip optional filename after 'k' and 's'
- while (*s && *s != ',' && *s != ' ') {
- if (*s == '\\' && s[1] != NUL) {
- s++;
- }
- s++;
- }
- } else {
- if (errbuf != NULL) {
- vim_snprintf(errbuf, errbuflen,
- _("E535: Illegal character after <%c>"),
- *--s);
- errmsg = errbuf;
- } else {
- errmsg = "";
- }
- break;
- }
- }
- }
- } else if (varp == &p_cot) { // 'completeopt'
- if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
- errmsg = e_invarg;
- } else {
- completeopt_was_set();
- }
-#ifdef BACKSLASH_IN_FILENAME
- } else if (gvarp == &p_csl) { // 'completeslash'
- if (check_opt_strings(p_csl, p_csl_values, false) != OK
- || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) {
- errmsg = e_invarg;
- }
-#endif
- } else if (varp == &curwin->w_p_scl) {
- // 'signcolumn'
- if (check_signcolumn(*varp) != OK) {
- errmsg = e_invarg;
- }
- // 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')
- || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u'))
- && (curwin->w_p_nu || curwin->w_p_rnu)) {
- curwin->w_nrwidth_line_count = 0;
- }
- } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) {
- // 'foldcolumn'
- if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_pt) {
- // 'pastetoggle': translate key codes like in a mapping
- if (*p_pt) {
- p = NULL;
- (void)replace_termcodes((char *)p_pt,
- STRLEN(p_pt),
- &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL,
- CPO_TO_CPO_FLAGS);
- if (p != NULL) {
- free_string_option(p_pt);
- p_pt = (char_u *)p;
- }
- }
- } else if (varp == &p_bs) { // 'backspace'
- if (ascii_isdigit(*p_bs)) {
- if (*p_bs > '3' || p_bs[1] != NUL) {
- errmsg = e_invarg;
- }
- } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_bo) {
- if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_tc) { // 'tagcase'
- unsigned int *flags;
-
- if (opt_flags & OPT_LOCAL) {
- p = (char *)curbuf->b_p_tc;
- flags = &curbuf->b_tc_flags;
- } else {
- p = (char *)p_tc;
- flags = &tc_flags;
- }
-
- if ((opt_flags & OPT_LOCAL) && *p == NUL) {
- // make the local value empty: use the global value
- *flags = 0;
- } else if (*p == NUL
- || opt_strings_flags((char_u *)p, p_tc_values, flags, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_cmp) { // 'casemap'
- if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_dip) { // 'diffopt'
- if (diffopt_changed() == FAIL) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod'
- if (check_opt_strings(*varp, p_fdm_values, false) != OK
- || *curwin->w_p_fdm == NUL) {
- errmsg = e_invarg;
- } else {
- foldUpdateAll(curwin);
- if (foldmethodIsDiff(curwin)) {
- newFoldLevel();
- }
- }
- } else if (varp == &curwin->w_p_fde) { // 'foldexpr'
- if (foldmethodIsExpr(curwin)) {
- foldUpdateAll(curwin);
- }
- } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker'
- p = vim_strchr((char *)(*varp), ',');
- if (p == NULL) {
- errmsg = N_("E536: comma required");
- } else if ((char_u *)p == *varp || p[1] == NUL) {
- errmsg = e_invarg;
- } else if (foldmethodIsMarker(curwin)) {
- foldUpdateAll(curwin);
- }
- } else if (gvarp == &p_cms) { // 'commentstring'
- if (**varp != NUL && strstr((char *)(*varp), "%s") == NULL) {
- errmsg = N_("E537: 'commentstring' must be empty or contain %s");
- }
- } else if (varp == &p_fdo) { // 'foldopen'
- if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_fcl) { // 'foldclose'
- if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore'
- if (foldmethodIsIndent(curwin)) {
- foldUpdateAll(curwin);
- }
- } else if (gvarp == &p_ve) { // 'virtualedit'
- char_u *ve = p_ve;
- unsigned int *flags = &ve_flags;
-
- if (opt_flags & OPT_LOCAL) {
- ve = curwin->w_p_ve;
- flags = &curwin->w_ve_flags;
- }
-
- if ((opt_flags & OPT_LOCAL) && *ve == NUL) {
- // make the local value empty: use the global value
- *flags = 0;
- } else {
- if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) {
- errmsg = e_invarg;
- } else if (STRCMP(p_ve, oldval) != 0) {
- // Recompute cursor position in case the new 've' setting
- // changes something.
- validate_virtcol();
- coladvance(curwin->w_virtcol);
- }
- }
- } else if (varp == &p_csqf) {
- if (p_csqf != NULL) {
- p = (char *)p_csqf;
- while (*p != NUL) {
- if (vim_strchr(CSQF_CMDS, *p) == NULL
- || p[1] == NUL
- || vim_strchr(CSQF_FLAGS, p[1]) == NULL
- || (p[2] != NUL && p[2] != ',')) {
- errmsg = e_invarg;
- break;
- } else if (p[2] == NUL) {
- break;
- } else {
- p += 3;
- }
- }
- }
- } else if (gvarp == &p_cino) { // 'cinoptions'
- // TODO(vim): recognize errors
- parse_cino(curbuf);
- // inccommand
- } else if (varp == &p_icm) {
- if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
- errmsg = e_invarg;
- }
- } else if (gvarp == &p_ft) {
- if (!valid_filetype(*varp)) {
- errmsg = e_invarg;
- } else {
- value_changed = STRCMP(oldval, *varp) != 0;
-
- // Since we check the value, there is no need to set P_INSECURE,
- // even when the value comes from a modeline.
- *value_checked = true;
- }
- } else if (gvarp == &p_syn) {
- if (!valid_filetype(*varp)) {
- errmsg = e_invarg;
- } else {
- value_changed = STRCMP(oldval, *varp) != 0;
-
- // Since we check the value, there is no need to set P_INSECURE,
- // even when the value comes from a modeline.
- *value_checked = true;
- }
- } else if (varp == &curwin->w_p_winhl) {
- if (!parse_winhl_opt(curwin)) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_tpf) {
- if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) {
- errmsg = e_invarg;
- }
- } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop'
- char_u *cp;
-
- if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
- XFREE_CLEAR(curbuf->b_p_vsts_array);
- } else {
- for (cp = *varp; *cp; cp++) {
- if (ascii_isdigit(*cp)) {
- continue;
- }
- if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
- continue;
- }
- errmsg = e_invarg;
- break;
- }
- if (errmsg == NULL) {
- long *oldarray = curbuf->b_p_vsts_array;
- if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) {
- xfree(oldarray);
- } else {
- errmsg = e_invarg;
- }
- }
- }
- } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop'
- char_u *cp;
-
- if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
- XFREE_CLEAR(curbuf->b_p_vts_array);
- } else {
- for (cp = *varp; *cp; cp++) {
- if (ascii_isdigit(*cp)) {
- continue;
- }
- if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
- continue;
- }
- errmsg = e_invarg;
- break;
- }
- if (errmsg == NULL) {
- long *oldarray = curbuf->b_p_vts_array;
- if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) {
- xfree(oldarray);
- if (foldmethodIsIndent(curwin)) {
- foldUpdateAll(curwin);
- }
- } else {
- errmsg = e_invarg;
- }
- }
- }
- } else if (varp == &p_opfunc) { // 'operatorfunc'
- if (set_operatorfunc_option() == FAIL) {
- errmsg = e_invarg;
- }
- } else if (varp == &p_qftf) { // 'quickfixtextfunc'
- if (qf_process_qftf_option() == FAIL) {
- errmsg = e_invarg;
- }
- } else {
- // Options that are a list of flags.
- p = NULL;
- if (varp == &p_ww) { // 'whichwrap'
- p = WW_ALL;
- }
- if (varp == &p_shm) { // 'shortmess'
- p = (char *)SHM_ALL;
- } else if (varp == (char_u **)&(p_cpo)) { // 'cpoptions'
- p = CPO_VI;
- } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions'
- p = FO_ALL;
- } else if (varp == &curwin->w_p_cocu) { // 'concealcursor'
- p = COCU_ALL;
- } else if (varp == &p_mouse) { // 'mouse'
- p = MOUSE_ALL;
- }
- if (p != NULL) {
- for (s = (char *)(*varp); *s; s++) {
- if (vim_strchr(p, *s) == NULL) {
- errmsg = illegal_char(errbuf, errbuflen, *s);
- break;
- }
- }
- }
- }
-
- /*
- * If error detected, restore the previous value.
- */
- if (errmsg != NULL) {
- free_string_option(*varp);
- *varp = oldval;
- /*
- * When resetting some values, need to act on it.
- */
- if (did_chartab) {
- (void)init_chartab();
- }
- } else {
- // Remember where the option was set.
- set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
- // Free string options that are in allocated memory.
- // Use "free_oldval", because recursiveness may change the flags under
- // our fingers (esp. init_highlight()).
- if (free_oldval) {
- free_string_option(oldval);
- }
- options[opt_idx].flags |= P_ALLOCED;
-
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
- && ((int)options[opt_idx].indir & PV_BOTH)) {
- /* global option with local value set to use global value; free
- * the local value and make it empty */
- p = (char *)get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
- free_string_option(*(char_u **)p);
- *(char_u **)p = empty_option;
- } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) {
- // May set global value for local option.
- set_string_option_global(opt_idx, varp);
- }
-
- /*
- * Trigger the autocommand only after setting the flags.
- */
- // When 'syntax' is set, load the syntax of that name
- if (varp == &(curbuf->b_p_syn)) {
- static int syn_recursive = 0;
-
- syn_recursive++;
- // Only pass true for "force" when the value changed or not used
- // recursively, to avoid endless recurrence.
- apply_autocmds(EVENT_SYNTAX, (char *)curbuf->b_p_syn, curbuf->b_fname,
- value_changed || syn_recursive == 1, curbuf);
- curbuf->b_flags |= BF_SYN_SET;
- syn_recursive--;
- } else if (varp == &(curbuf->b_p_ft)) {
- // 'filetype' is set, trigger the FileType autocommand
- // Skip this when called from a modeline and the filetype was
- // already set to this value.
- if (!(opt_flags & OPT_MODELINE) || value_changed) {
- static int ft_recursive = 0;
- int secure_save = secure;
-
- // Reset the secure flag, since the value of 'filetype' has
- // been checked to be safe.
- secure = 0;
-
- ft_recursive++;
- did_filetype = true;
- // Only pass true for "force" when the value changed or not
- // used recursively, to avoid endless recurrence.
- apply_autocmds(EVENT_FILETYPE, (char *)curbuf->b_p_ft, curbuf->b_fname,
- value_changed || ft_recursive == 1, curbuf);
- ft_recursive--;
- // Just in case the old "curbuf" is now invalid
- if (varp != &(curbuf->b_p_ft)) {
- varp = NULL;
- }
- secure = secure_save;
- }
- }
- if (varp == &(curwin->w_s->b_p_spl)) {
- char_u fname[200];
- char_u *q = curwin->w_s->b_p_spl;
-
- // Skip the first name if it is "cjk".
- if (STRNCMP(q, "cjk,", 4) == 0) {
- q += 4;
- }
-
- /*
- * Source the spell/LANG.vim in 'runtimepath'.
- * They could set 'spellcapcheck' depending on the language.
- * Use the first name in 'spelllang' up to '_region' or
- * '.encoding'.
- */
- for (p = (char *)q; *p != NUL; p++) {
- if (!ASCII_ISALNUM(*p) && *p != '-') {
- break;
- }
- }
- if (p > (char *)q) {
- vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim",
- (int)(p - (char *)q), q);
- source_runtime((char *)fname, DIP_ALL);
- }
- }
- }
-
- if (varp == &p_mouse) {
- setmouse(); // in case 'mouse' changed
- }
-
- if (curwin->w_curswant != MAXCOL
- && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
- curwin->w_set_curswant = true;
- }
-
- check_redraw(options[opt_idx].flags);
-
- return errmsg;
-}
-
-/// Handle setting 'signcolumn' for value 'val'
-///
-/// @return OK when the value is valid, FAIL otherwise
-int check_signcolumn(char_u *val)
-{
- if (*val == NUL) {
- return FAIL;
- }
- // check for basic match
- if (check_opt_strings(val, p_scl_values, false) == OK) {
- return OK;
- }
-
- // check for 'auto:<NUMBER>-<NUMBER>'
- if (STRLEN(val) == 8
- && !STRNCMP(val, "auto:", 5)
- && ascii_isdigit(val[5])
- && val[6] == '-'
- && ascii_isdigit(val[7])) {
- int min = val[5] - '0';
- int max = val[7] - '0';
- if (min < 1 || max < 2 || min > 8 || max > 9 || min >= max) {
- return FAIL;
- }
- return OK;
- }
-
- return FAIL;
-}
-
void check_blending(win_T *wp)
{
wp->w_grid_alloc.blending =
wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow);
}
-/// Check validity of options with the 'statusline' format.
-/// Return an untranslated error message or NULL.
-char *check_stl_option(char *s)
-{
- int groupdepth = 0;
- static char errbuf[80];
-
- while (*s) {
- // Check for valid keys after % sequences
- while (*s && *s != '%') {
- s++;
- }
- if (!*s) {
- break;
- }
- s++;
- if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) {
- s++;
- continue;
- }
- if (*s == ')') {
- s++;
- if (--groupdepth < 0) {
- break;
- }
- continue;
- }
- if (*s == '-') {
- s++;
- }
- while (ascii_isdigit(*s)) {
- s++;
- }
- if (*s == STL_USER_HL) {
- continue;
- }
- if (*s == '.') {
- s++;
- while (*s && ascii_isdigit(*s)) {
- s++;
- }
- }
- if (*s == '(') {
- groupdepth++;
- continue;
- }
- if (vim_strchr(STL_ALL, *s) == NULL) {
- return illegal_char(errbuf, sizeof(errbuf), *s);
- }
- if (*s == '{') {
- bool reevaluate = (*++s == '%');
-
- if (reevaluate && *++s == '}') {
- // "}" is not allowed immediately after "%{%"
- return illegal_char(errbuf, sizeof(errbuf), '}');
- }
- while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s) {
- s++;
- }
- if (*s != '}') {
- return e_unclosed_expression_sequence;
- }
- }
- }
- if (groupdepth != 0) {
- return e_unbalanced_groups;
- }
- return NULL;
-}
-
/// Handle setting `winhighlight' in window "wp"
bool parse_winhl_opt(win_T *wp)
{
@@ -3571,9 +1928,9 @@ bool parse_winhl_opt(win_T *wp)
return true;
}
-// Set the script_ctx for an option, taking care of setting the buffer- or
-// window-local value.
-static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
+/// Set the script_ctx for an option, taking care of setting the buffer- or
+/// window-local value.
+void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int indir = (int)options[opt_idx].indir;
@@ -4358,51 +2715,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
return errmsg;
}
-/// Trigger the OptionSet autocommand.
-/// "opt_idx" is the index of the option being set.
-/// "opt_flags" can be OPT_LOCAL etc.
-/// "oldval" the old value
-/// "oldval_l" the old local value (only non-NULL if global and local value are set)
-/// "oldval_g" the old global value (only non-NULL if global and local value are set)
-/// "newval" the new value
-static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l,
- char *oldval_g, char *newval)
-{
- // Don't do this recursively.
- if (oldval != NULL
- && newval != NULL
- && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
- char buf_type[7];
-
- vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
- (opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_OLD, oldval, -1);
- set_vim_var_string(VV_OPTION_NEW, newval, -1);
- set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- if (opt_flags & OPT_LOCAL) {
- set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
- set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
- }
- if (opt_flags & OPT_GLOBAL) {
- set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1);
- set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1);
- }
- if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
- set_vim_var_string(VV_OPTION_COMMAND, "set", -1);
- set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1);
- set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1);
- }
- if (opt_flags & OPT_MODELINE) {
- set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1);
- set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
- }
- apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL);
- reset_v_option_vars();
- }
-}
-
/// Called after an option changed: check if something needs to be redrawn.
-static void check_redraw(uint32_t flags)
+void check_redraw(uint32_t flags)
{
// Careful: P_RCLR and P_RALL are a combination of other P_ flags
bool doclear = (flags & P_RCLR) == P_RCLR;
@@ -4594,7 +2908,7 @@ void set_tty_background(const char *value)
/// @param[in] arg Option name.
///
/// @return Option index or -1 if option was not found.
-static int findoption(const char *const arg)
+int findoption(const char *const arg)
FUNC_ATTR_NONNULL_ALL
{
return findoption_len(arg, strlen(arg));
@@ -4780,6 +3094,49 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
return rv;
}
+/// Return the flags for the option at 'opt_idx'.
+uint32_t get_option_flags(int opt_idx)
+{
+ return options[opt_idx].flags;
+}
+
+/// Set a flag for the option at 'opt_idx'.
+void set_option_flag(int opt_idx, uint32_t flag)
+{
+ options[opt_idx].flags |= flag;
+}
+
+/// Clear a flag for the option at 'opt_idx'.
+void clear_option_flag(int opt_idx, uint32_t flag)
+{
+ options[opt_idx].flags &= ~flag;
+}
+
+/// Returns true if the option at 'opt_idx' is a global option
+bool is_global_option(int opt_idx)
+{
+ return options[opt_idx].indir == PV_NONE;
+}
+
+/// Returns true if the option at 'opt_idx' is a global option which also has a
+/// local value.
+int is_global_local_option(int opt_idx)
+{
+ return options[opt_idx].indir & PV_BOTH;
+}
+
+/// Returns true if the option at 'opt_idx' is a window-local option
+bool is_window_local_option(int opt_idx)
+{
+ return options[opt_idx].var == VAR_WIN;
+}
+
+/// Returns true if the option at 'opt_idx' is a hidden option
+bool is_hidden_option(int opt_idx)
+{
+ return options[opt_idx].var == NULL;
+}
+
/// Set the value of an option
///
/// @param[in] name Option name.
@@ -5524,6 +3881,13 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
return get_varp(p);
}
+/// Get pointer to option variable at 'opt_idx', depending on local or global
+/// scope.
+char_u *get_option_varp_scope(int opt_idx, int opt_flags)
+{
+ return get_varp_scope(&(options[opt_idx]), opt_flags);
+}
+
/// Get pointer to option variable.
static char_u *get_varp(vimoption_T *p)
{
@@ -5833,6 +4197,18 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curbuf->b_p_wm);
}
+/// Return a pointer to the variable for option at 'opt_idx'
+char_u *get_option_var(int opt_idx)
+{
+ return options[opt_idx].var;
+}
+
+/// Return the full name of the option at 'opt_idx'
+char *get_option_fullname(int opt_idx)
+{
+ return options[opt_idx].fullname;
+}
+
/// Get the value of 'equalprg', either the buffer-local one or the global one.
char_u *get_equalprg(void)
{
@@ -6864,7 +5240,7 @@ void reset_option_was_set(const char *name)
}
/// fill_breakat_flags() -- called when 'breakat' changes value.
-static void fill_breakat_flags(void)
+void fill_breakat_flags(void)
{
char_u *p;
int i;
@@ -6881,7 +5257,7 @@ static void fill_breakat_flags(void)
}
/// fill_culopt_flags() -- called when 'culopt' changes value
-static int fill_culopt_flags(char_u *val, win_T *wp)
+int fill_culopt_flags(char_u *val, win_T *wp)
{
char_u *p;
char_u culopt_flags_new = 0;
@@ -6961,53 +5337,8 @@ int option_set_callback_func(char_u *optval, Callback *optcb)
return OK;
}
-/// Check an option that can be a range of string values.
-///
-/// @param list when true: accept a list of values
-///
-/// @return OK for correct value, FAIL otherwise. Empty is always OK.
-static int check_opt_strings(char_u *val, char **values, int list)
-{
- return opt_strings_flags(val, values, NULL, list);
-}
-
-/// Handle an option that can be a range of string values.
-/// Set a flag in "*flagp" for each string present.
-///
-/// @param val new value
-/// @param values array of valid string values
-/// @param list when true: accept a list of values
-///
-/// @return OK for correct value, FAIL otherwise. Empty is always OK.
-static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool list)
-{
- unsigned int new_flags = 0;
-
- while (*val) {
- for (unsigned int i = 0;; i++) {
- if (values[i] == NULL) { // val not found in values[]
- return FAIL;
- }
-
- size_t len = STRLEN(values[i]);
- if (STRNCMP(values[i], val, len) == 0
- && ((list && val[len] == ',') || val[len] == NUL)) {
- val += len + (val[len] == ',');
- assert(i < sizeof(1U) * 8);
- new_flags |= (1U << i);
- break; // check next item in val list
- }
- }
- }
- if (flagp != NULL) {
- *flagp = new_flags;
- }
-
- return OK;
-}
-
/// Read the 'wildmode' option, fill wim_flags[].
-static int check_opt_wim(void)
+int check_opt_wim(void)
{
char_u new_wim_flags[4];
char_u *p;
@@ -7130,15 +5461,9 @@ bool file_ff_differs(buf_T *buf, bool ignore_empty)
return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0;
}
-/// return OK if "p" is a valid fileformat name, FAIL otherwise.
-int check_ff_value(char_u *p)
-{
- return check_opt_strings(p, p_ff_values, false);
-}
-
/// This is called when 'breakindentopt' is changed and when a window is
/// initialized
-static bool briopt_check(win_T *wp)
+bool briopt_check(win_T *wp)
{
int bri_shift = 0;
int bri_min = 20;
diff --git a/src/nvim/option.h b/src/nvim/option.h
index a5a57cc66d..c65d2ee182 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -19,23 +19,6 @@ typedef enum {
#define BCO_ALWAYS 2 // always copy the options
#define BCO_NOHELP 4 // don't touch the help related options
-/// Flags for option-setting functions
-///
-/// When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global
-/// values, get local value.
-typedef enum {
- OPT_FREE = 0x01, ///< Free old value if it was allocated.
- OPT_GLOBAL = 0x02, ///< Use global value.
- OPT_LOCAL = 0x04, ///< Use local value.
- OPT_MODELINE = 0x08, ///< Option in modeline.
- OPT_WINONLY = 0x10, ///< Only set window-local options.
- OPT_NOWIN = 0x20, ///< Don’t set window-local options.
- OPT_ONECOLUMN = 0x40, ///< list options one per line
- OPT_NO_REDRAW = 0x80, ///< ignore redraw flags on option
- OPT_SKIPRTP = 0x100, ///< "skiprtp" in 'sessionoptions'
- OPT_CLEAR = 0x200, ///< Clear local value of an option.
-} OptionFlags;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.h.generated.h"
#endif
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 237288fbad..ad8092add2 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -7,6 +7,69 @@
// option_defs.h: definition of global variables for settable options
+// Flags
+#define P_BOOL 0x01U ///< the option is boolean
+#define P_NUM 0x02U ///< the option is numeric
+#define P_STRING 0x04U ///< the option is a string
+#define P_ALLOCED 0x08U ///< the string option is in allocated memory,
+ ///< must use free_string_option() when
+ ///< assigning new value. Not set if default is
+ ///< the same.
+#define P_EXPAND 0x10U ///< environment expansion. NOTE: P_EXPAND can
+ ///< never be used for local or hidden options
+#define P_NODEFAULT 0x40U ///< don't set to default value
+#define P_DEF_ALLOCED 0x80U ///< default value is in allocated memory, must
+ ///< use free() when assigning new value
+#define P_WAS_SET 0x100U ///< option has been set/reset
+#define P_NO_MKRC 0x200U ///< don't include in :mkvimrc output
+
+// when option changed, what to display:
+#define P_RSTAT 0x1000U ///< redraw status lines
+#define P_RWIN 0x2000U ///< redraw current window and recompute text
+#define P_RBUF 0x4000U ///< redraw current buffer and recompute text
+#define P_RALL 0x6000U ///< redraw all windows
+#define P_RCLR 0x7000U ///< clear and redraw all
+
+#define P_COMMA 0x8000U ///< comma separated list
+#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive
+ ///< commas
+#define P_NODUP 0x20000U ///< don't allow duplicate strings
+#define P_FLAGLIST 0x40000U ///< list of single-char flags
+
+#define P_SECURE 0x80000U ///< cannot change in modeline or secure mode
+#define P_GETTEXT 0x100000U ///< expand default value with _()
+#define P_NOGLOB 0x200000U ///< do not use local value for global vimrc
+#define P_NFNAME 0x400000U ///< only normal file name chars allowed
+#define P_INSECURE 0x800000U ///< option was set from a modeline
+#define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option
+ ///< has side effects)
+#define P_NO_ML 0x2000000U ///< not allowed in modeline
+#define P_CURSWANT 0x4000000U ///< update curswant required; not needed
+ ///< when there is a redraw flag
+#define P_NDNAME 0x8000000U ///< only normal dir name chars allowed
+#define P_RWINONLY 0x10000000U ///< only redraw current window
+#define P_MLE 0x20000000U ///< under control of 'modelineexpr'
+
+#define P_NO_DEF_EXP 0x40000000U ///< Do not expand default value.
+#define P_UI_OPTION 0x80000000U ///< send option to remote ui
+
+/// Flags for option-setting functions
+///
+/// When OPT_GLOBAL and OPT_LOCAL are both missing, set both local and global
+/// values, get local value.
+typedef enum {
+ OPT_FREE = 0x01, ///< Free old value if it was allocated.
+ OPT_GLOBAL = 0x02, ///< Use global value.
+ OPT_LOCAL = 0x04, ///< Use local value.
+ OPT_MODELINE = 0x08, ///< Option in modeline.
+ OPT_WINONLY = 0x10, ///< Only set window-local options.
+ OPT_NOWIN = 0x20, ///< Don’t set window-local options.
+ OPT_ONECOLUMN = 0x40, ///< list options one per line
+ OPT_NO_REDRAW = 0x80, ///< ignore redraw flags on option
+ OPT_SKIPRTP = 0x100, ///< "skiprtp" in 'sessionoptions'
+ OPT_CLEAR = 0x200, ///< Clear local value of an option.
+} OptionFlags;
+
// Return value from get_option_value_strict
#define SOPT_BOOL 0x01 // Boolean option
#define SOPT_NUM 0x02 // Number option
@@ -21,6 +84,16 @@
#define SREQ_WIN 1 // Request window-local option value
#define SREQ_BUF 2 // Request buffer-local option value
+#define HIGHLIGHT_INIT \
+ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
+ "i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow," \
+ "N:CursorLineNr,G:CursorLineSign,O:CursorLineFold" \
+ "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \
+ "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \
+ "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \
+ "X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \
+ "q:QuickFixLine,0:Whitespace,I:NormalNC"
+
// Default values for 'errorformat'.
// The "%f|%l| %m" one is used for when the contents of the quickfix window is
// written to a file.
@@ -311,8 +384,21 @@ enum {
*/
EXTERN long p_aleph; // 'aleph'
-EXTERN int p_acd; // 'autochdir'
-EXTERN char_u *p_ambw; // 'ambiwidth'
+EXTERN char_u *p_ambw; ///< 'ambiwidth'
+EXTERN int p_acd; ///< 'autochdir'
+EXTERN int p_ai; ///< 'autoindent'
+EXTERN int p_bin; ///< 'binary'
+EXTERN int p_bomb; ///< 'bomb'
+EXTERN int p_bl; ///< 'buflisted'
+EXTERN int p_cin; ///< 'cindent'
+EXTERN long p_channel; ///< 'channel'
+EXTERN char_u *p_cink; ///< 'cinkeys'
+EXTERN char_u *p_cinsd; ///< 'cinscopedecls'
+EXTERN char_u *p_cinw; ///< 'cinwords'
+EXTERN char_u *p_cfu; ///< 'completefunc'
+EXTERN char_u *p_ofu; ///< 'omnifunc'
+EXTERN char_u *p_tsrfu; ///< 'thesaurusfunc'
+EXTERN int p_ci; ///< 'copyindent'
EXTERN int p_ar; // 'autoread'
EXTERN int p_aw; // 'autowrite'
EXTERN int p_awa; // 'autowriteall'
@@ -321,10 +407,6 @@ EXTERN char_u *p_bg; // 'background'
EXTERN int p_bk; // 'backup'
EXTERN char_u *p_bkc; // 'backupcopy'
EXTERN unsigned int bkc_flags; ///< flags from 'backupcopy'
-#ifdef IN_OPTION_C
-static char *(p_bkc_values[]) =
-{ "yes", "auto", "no", "breaksymlink", "breakhardlink", NULL };
-#endif
#define BKC_YES 0x001
#define BKC_AUTO 0x002
#define BKC_NO 0x004
@@ -335,13 +417,6 @@ EXTERN char_u *p_bex; // 'backupext'
EXTERN char_u *p_bo; // 'belloff'
EXTERN char breakat_flags[256]; // which characters are in 'breakat'
EXTERN unsigned bo_flags;
-#ifdef IN_OPTION_C
-static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete",
- "copy", "ctrlg", "error", "esc", "ex",
- "hangul", "lang", "mess", "showmatch",
- "operator", "register", "shell", "spell",
- "wildmode", NULL };
-#endif
// values for the 'belloff' option
#define BO_ALL 0x0001
@@ -366,27 +441,26 @@ static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete",
EXTERN char_u *p_bsk; // 'backupskip'
EXTERN char_u *p_breakat; // 'breakat'
+EXTERN char_u *p_bh; ///< 'bufhidden'
+EXTERN char_u *p_bt; ///< 'buftype'
EXTERN char_u *p_cmp; // 'casemap'
EXTERN unsigned cmp_flags;
-#ifdef IN_OPTION_C
-static char *(p_cmp_values[]) = { "internal", "keepascii", NULL };
-#endif
#define CMP_INTERNAL 0x001
#define CMP_KEEPASCII 0x002
EXTERN char_u *p_enc; // 'encoding'
EXTERN int p_deco; // 'delcombine'
EXTERN char_u *p_ccv; // 'charconvert'
+EXTERN char_u *p_cino; ///< 'cinoptions'
EXTERN char_u *p_cedit; // 'cedit'
EXTERN char_u *p_cb; // 'clipboard'
EXTERN unsigned cb_flags;
-#ifdef IN_OPTION_C
-static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
-#endif
#define CB_UNNAMED 0x001
#define CB_UNNAMEDPLUS 0x002
#define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS)
EXTERN long p_cwh; // 'cmdwinheight'
EXTERN long p_ch; // 'cmdheight'
+EXTERN char_u *p_cms; ///< 'commentstring'
+EXTERN char_u *p_cpt; ///< 'complete'
EXTERN long p_columns; // 'columns'
EXTERN int p_confirm; // 'confirm'
EXTERN char_u *p_cot; // 'completeopt'
@@ -396,6 +470,7 @@ EXTERN char_u *p_csl; // 'completeslash'
EXTERN long p_pb; // 'pumblend'
EXTERN long p_ph; // 'pumheight'
EXTERN long p_pw; // 'pumwidth'
+EXTERN char_u *p_com; ///< 'comments'
EXTERN char *p_cpo; // 'cpoptions'
EXTERN char_u *p_csprg; // 'cscopeprg'
EXTERN int p_csre; // 'cscoperelative'
@@ -416,18 +491,14 @@ EXTERN int p_dg; // 'digraph'
EXTERN char_u *p_dir; // 'directory'
EXTERN char_u *p_dy; // 'display'
EXTERN unsigned dy_flags;
-#ifdef IN_OPTION_C
-static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", "msgsep",
- NULL };
-#endif
#define DY_LASTLINE 0x001
#define DY_TRUNCATE 0x002
#define DY_UHEX 0x004
// code should use msg_use_msgsep() to check if msgsep is active
#define DY_MSGSEP 0x008
EXTERN int p_ed; // 'edcompatible'
-EXTERN int p_emoji; // 'emoji'
EXTERN char_u *p_ead; // 'eadirection'
+EXTERN int p_emoji; // 'emoji'
EXTERN int p_ea; // 'equalalways'
EXTERN char_u *p_ep; // 'equalprg'
EXTERN int p_eb; // 'errorbells'
@@ -435,20 +506,22 @@ EXTERN char_u *p_ef; // 'errorfile'
EXTERN char *p_efm; // 'errorformat'
EXTERN char *p_gefm; // 'grepformat'
EXTERN char_u *p_gp; // 'grepprg'
+EXTERN int p_eol; ///< 'endofline'
EXTERN char_u *p_ei; // 'eventignore'
+EXTERN int p_et; ///< 'expandtab'
EXTERN int p_exrc; // 'exrc'
+EXTERN char_u *p_fenc; ///< 'fileencoding'
EXTERN char_u *p_fencs; // 'fileencodings'
+EXTERN char_u *p_ff; ///< 'fileformat'
EXTERN char *p_ffs; // 'fileformats'
EXTERN int p_fic; // 'fileignorecase'
+EXTERN char_u *p_ft; ///< 'filetype'
+EXTERN char_u *p_fcs; ///< 'fillchar'
+EXTERN int p_fixeol; ///< 'fixendofline'
EXTERN char_u *p_fcl; // 'foldclose'
EXTERN long p_fdls; // 'foldlevelstart'
EXTERN char_u *p_fdo; // 'foldopen'
EXTERN unsigned fdo_flags;
-#ifdef IN_OPTION_C
-static char *(p_fdo_values[]) = { "all", "block", "hor", "mark", "percent",
- "quickfix", "search", "tag", "insert",
- "undo", "jump", NULL };
-#endif
#define FDO_ALL 0x001
#define FDO_BLOCK 0x002
#define FDO_HOR 0x004
@@ -460,6 +533,9 @@ static char *(p_fdo_values[]) = { "all", "block", "hor", "mark", "percent",
#define FDO_INSERT 0x100
#define FDO_UNDO 0x200
#define FDO_JUMP 0x400
+EXTERN char_u *p_fex; ///< 'formatexpr'
+EXTERN char_u *p_flp; ///< 'formatlistpat'
+EXTERN char_u *p_fo; ///< 'formatoptions'
EXTERN char_u *p_fp; // 'formatprg'
EXTERN int p_fs; // 'fsync'
EXTERN int p_gd; // 'gdefault'
@@ -487,19 +563,24 @@ EXTERN int p_arshape; // 'arabicshape'
EXTERN int p_icon; // 'icon'
EXTERN char_u *p_iconstring; // 'iconstring'
EXTERN int p_ic; // 'ignorecase'
+EXTERN long p_iminsert; ///< 'iminsert'
+EXTERN long p_imsearch; ///< 'imsearch'
+EXTERN int p_inf; ///< 'infercase'
+EXTERN char_u *p_inex; ///< 'includeexpr'
EXTERN int p_is; // 'incsearch'
+EXTERN char_u *p_inde; ///< 'indentexpr'
+EXTERN char_u *p_indk; ///< 'indentkeys'
EXTERN char_u *p_icm; // 'inccommand'
EXTERN char_u *p_isf; // 'isfname'
EXTERN char_u *p_isi; // 'isident'
+EXTERN char_u *p_isk; ///< 'iskeyword'
EXTERN char_u *p_isp; // 'isprint'
EXTERN int p_js; // 'joinspaces'
EXTERN char_u *p_jop; // 'jumpooptions'
EXTERN unsigned jop_flags;
-#ifdef IN_OPTION_C
-static char *(p_jop_values[]) = { "stack", "view", NULL };
-#endif
#define JOP_STACK 0x01
#define JOP_VIEW 0x02
+EXTERN char_u *p_keymap; ///< 'keymap'
EXTERN char_u *p_kp; // 'keywordprg'
EXTERN char_u *p_km; // 'keymodel'
EXTERN char_u *p_langmap; // 'langmap'
@@ -508,6 +589,7 @@ EXTERN int p_lrm; // 'langremap'
EXTERN char_u *p_lm; // 'langmenu'
EXTERN long p_lines; // 'lines'
EXTERN long p_linespace; // 'linespace'
+EXTERN int p_lisp; ///< 'lisp'
EXTERN char_u *p_lispwords; // 'lispwords'
EXTERN long p_ls; // 'laststatus'
EXTERN long p_stal; // 'showtabline'
@@ -519,6 +601,7 @@ EXTERN int p_magic; // 'magic'
EXTERN char_u *p_menc; // 'makeencoding'
EXTERN char *p_mef; // 'makeef'
EXTERN char_u *p_mp; // 'makeprg'
+EXTERN char_u *p_mps; ///< 'matchpairs'
EXTERN char_u *p_cc; // 'colorcolumn'
EXTERN int p_cc_cols[256]; // array for 'colorcolumn' columns
EXTERN long p_mat; // 'matchtime'
@@ -528,8 +611,11 @@ EXTERN long p_mmd; // 'maxmapdepth'
EXTERN long p_mmp; // 'maxmempattern'
EXTERN long p_mis; // 'menuitems'
EXTERN char_u *p_msm; // 'mkspellmem'
+EXTERN int p_ml; ///< 'modeline'
EXTERN int p_mle; // 'modelineexpr'
EXTERN long p_mls; // 'modelines'
+EXTERN int p_ma; ///< 'modifiable'
+EXTERN int p_mod; ///< 'modified'
EXTERN char_u *p_mouse; // 'mouse'
EXTERN char_u *p_mousem; // 'mousemodel'
EXTERN int p_mousef; // 'mousefocus'
@@ -538,6 +624,7 @@ EXTERN long p_mousescroll_vert INIT(= MOUSESCROLL_VERT_DFLT);
EXTERN long p_mousescroll_hor INIT(= MOUSESCROLL_HOR_DFLT);
EXTERN long p_mouset; // 'mousetime'
EXTERN int p_more; // 'more'
+EXTERN char_u *p_nf; ///< 'nrformats'
EXTERN char_u *p_opfunc; // 'operatorfunc'
EXTERN char_u *p_para; // 'paragraphs'
EXTERN int p_paste; // 'paste'
@@ -546,18 +633,12 @@ EXTERN char_u *p_pex; // 'patchexpr'
EXTERN char_u *p_pm; // 'patchmode'
EXTERN char_u *p_path; // 'path'
EXTERN char_u *p_cdpath; // 'cdpath'
+EXTERN int p_pi; ///< 'preserveindent'
EXTERN long p_pyx; // 'pyxversion'
+EXTERN char_u *p_qe; ///< 'quoteescape'
+EXTERN int p_ro; ///< 'readonly'
EXTERN char_u *p_rdb; // 'redrawdebug'
EXTERN unsigned rdb_flags;
-#ifdef IN_OPTION_C
-static char *(p_rdb_values[]) = {
- "compositor",
- "nothrottle",
- "invalid",
- "nodelta",
- NULL
-};
-#endif
#define RDB_COMPOSITOR 0x001
#define RDB_NOTHROTTLE 0x002
#define RDB_INVALID 0x004
@@ -584,15 +665,7 @@ EXTERN char_u *p_sel; // 'selection'
EXTERN char_u *p_slm; // 'selectmode'
EXTERN char_u *p_ssop; // 'sessionoptions'
EXTERN unsigned ssop_flags;
-#ifdef IN_OPTION_C
-// Also used for 'viewoptions'! Keep in sync with SSOP_ flags.
-static char *(p_ssop_values[]) = {
- "buffers", "winpos", "resize", "winsize",
- "localoptions", "options", "help", "blank", "globals", "slash", "unix",
- "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
- NULL
-};
-#endif
+
#define SSOP_BUFFERS 0x001
#define SSOP_WINPOS 0x002
#define SSOP_RESIZE 0x004
@@ -626,6 +699,7 @@ EXTERN int p_ssl; // 'shellslash'
EXTERN char_u *p_stl; // 'statusline'
EXTERN char *p_wbr; // 'winbar'
EXTERN int p_sr; // 'shiftround'
+EXTERN long p_sw; ///< 'shiftwidth'
EXTERN char_u *p_shm; // 'shortmess'
EXTERN char_u *p_sbr; // 'showbreak'
EXTERN int p_sc; // 'showcmd'
@@ -635,16 +709,17 @@ EXTERN int p_smd; // 'showmode'
EXTERN long p_ss; // 'sidescroll'
EXTERN long p_siso; // 'sidescrolloff'
EXTERN int p_scs; // 'smartcase'
+EXTERN int p_si; ///< 'smartindent'
EXTERN int p_sta; // 'smarttab'
+EXTERN long p_sts; ///< 'softtabstop'
EXTERN int p_sb; // 'splitbelow'
+EXTERN char_u *p_sua; ///< 'suffixesadd'
+EXTERN int p_swf; ///< 'swapfile'
+EXTERN long p_smc; ///< 'synmaxcol'
EXTERN long p_tpm; // 'tabpagemax'
EXTERN char_u *p_tal; // 'tabline'
EXTERN char_u *p_tpf; // 'termpastefilter'
EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter'
-#ifdef IN_OPTION_C
-static char *(p_tpf_values[]) =
-{ "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL };
-#endif
#define TPF_BS 0x001
#define TPF_HT 0x002
#define TPF_FF 0x004
@@ -652,29 +727,29 @@ static char *(p_tpf_values[]) =
#define TPF_DEL 0x010
#define TPF_C0 0x020
#define TPF_C1 0x040
+EXTERN char_u *p_tfu; ///< 'tagfunc'
+EXTERN char_u *p_spc; ///< 'spellcapcheck'
+EXTERN char_u *p_spf; ///< 'spellfile'
+EXTERN char_u *p_spl; ///< 'spelllang'
+EXTERN char_u *p_spo; // 'spelloptions'
EXTERN char_u *p_sps; // 'spellsuggest'
EXTERN int p_spr; // 'splitright'
EXTERN int p_sol; // 'startofline'
EXTERN char_u *p_su; // 'suffixes'
EXTERN char_u *p_swb; // 'switchbuf'
EXTERN unsigned swb_flags;
-#ifdef IN_OPTION_C
-static char *(p_swb_values[]) =
-{ "useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL };
-#endif
+// Keep in sync with p_swb_values in optionstr.c
#define SWB_USEOPEN 0x001
#define SWB_USETAB 0x002
#define SWB_SPLIT 0x004
#define SWB_NEWTAB 0x008
#define SWB_VSPLIT 0x010
#define SWB_USELAST 0x020
+EXTERN char_u *p_syn; ///< 'syntax'
+EXTERN long p_ts; ///< 'tabstop'
EXTERN int p_tbs; ///< 'tagbsearch'
EXTERN char_u *p_tc; ///< 'tagcase'
EXTERN unsigned tc_flags; ///< flags from 'tagcase'
-#ifdef IN_OPTION_C
-static char *(p_tc_values[]) =
-{ "followic", "ignore", "match", "followscs", "smart", NULL };
-#endif
#define TC_FOLLOWIC 0x01
#define TC_IGNORE 0x02
#define TC_MATCH 0x04
@@ -685,6 +760,7 @@ EXTERN int p_tr; ///< 'tagrelative'
EXTERN char_u *p_tags; ///< 'tags'
EXTERN int p_tgst; ///< 'tagstack'
EXTERN int p_tbidi; ///< 'termbidi'
+EXTERN long p_tw; ///< 'textwidth'
EXTERN int p_to; ///< 'tildeop'
EXTERN int p_timeout; ///< 'timeout'
EXTERN long p_tm; ///< 'timeoutlen'
@@ -693,27 +769,25 @@ EXTERN long p_titlelen; ///< 'titlelen'
EXTERN char_u *p_titleold; ///< 'titleold'
EXTERN char_u *p_titlestring; ///< 'titlestring'
EXTERN char_u *p_tsr; ///< 'thesaurus'
-EXTERN char_u *p_tsrfu; ///< 'thesaurusfunc'
EXTERN int p_tgc; ///< 'termguicolors'
EXTERN int p_ttimeout; ///< 'ttimeout'
EXTERN long p_ttm; ///< 'ttimeoutlen'
EXTERN char_u *p_udir; ///< 'undodir'
+EXTERN int p_udf; ///< 'undofile'
EXTERN long p_ul; ///< 'undolevels'
EXTERN long p_ur; ///< 'undoreload'
EXTERN long p_uc; ///< 'updatecount'
EXTERN long p_ut; ///< 'updatetime'
-EXTERN char_u *p_fcs; ///< 'fillchar'
EXTERN char_u *p_shada; ///< 'shada'
EXTERN char *p_shadafile; ///< 'shadafile'
+EXTERN char_u *p_vsts; ///< 'varsofttabstop'
+EXTERN char_u *p_vts; ///< 'vartabstop'
EXTERN char_u *p_vdir; ///< 'viewdir'
EXTERN char_u *p_vop; ///< 'viewoptions'
EXTERN unsigned vop_flags; ///< uses SSOP_ flags
EXTERN int p_vb; ///< 'visualbell'
EXTERN char_u *p_ve; ///< 'virtualedit'
EXTERN unsigned ve_flags;
-#ifdef IN_OPTION_C
-static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL };
-#endif
#define VE_BLOCK 5U // includes "all"
#define VE_INSERT 6U // includes "all"
#define VE_ALL 4U
@@ -729,9 +803,6 @@ extern char_u *p_vfile; // 'verbosefile'
EXTERN int p_warn; // 'warn'
EXTERN char_u *p_wop; // 'wildoptions'
EXTERN unsigned wop_flags;
-#ifdef IN_OPTION_C
-static char *(p_wop_values[]) = { "tagfile", "pum", NULL };
-#endif
#define WOP_TAGFILE 0x01
#define WOP_PUM 0x02
EXTERN long p_window; // 'window'
@@ -747,6 +818,7 @@ EXTERN long p_wh; // 'winheight'
EXTERN long p_wmh; // 'winminheight'
EXTERN long p_wmw; // 'winminwidth'
EXTERN long p_wiw; // 'winwidth'
+EXTERN long p_wm; ///< 'wrapmargin'
EXTERN int p_ws; // 'wrapscan'
EXTERN int p_write; // 'write'
EXTERN int p_wa; // 'writeany'
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
new file mode 100644
index 0000000000..4ff14f0122
--- /dev/null
+++ b/src/nvim/optionstr.c
@@ -0,0 +1,1665 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/cursor_shape.h"
+#include "nvim/diff.h"
+#include "nvim/digraph.h"
+#include "nvim/drawscreen.h"
+#include "nvim/eval.h"
+#include "nvim/eval/vars.h"
+#include "nvim/hardcopy.h"
+#include "nvim/highlight_group.h"
+#include "nvim/indent.h"
+#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
+#include "nvim/keycodes.h"
+#include "nvim/mapping.h"
+#include "nvim/memline.h"
+#include "nvim/mouse.h"
+#include "nvim/move.h"
+#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/optionstr.h"
+#include "nvim/quickfix.h"
+#include "nvim/runtime.h"
+#include "nvim/spell.h"
+#include "nvim/spellfile.h"
+#include "nvim/spellsuggest.h"
+#include "nvim/strings.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "optionstr.c.generated.h"
+#endif
+
+static char e_unclosed_expression_sequence[] = N_("E540: Unclosed expression sequence");
+static char e_unbalanced_groups[] = N_("E542: unbalanced groups");
+
+static char *(p_ambw_values[]) = { "single", "double", NULL };
+static char *(p_bg_values[]) = { "light", "dark", NULL };
+static char *(p_bkc_values[]) = { "yes", "auto", "no", "breaksymlink", "breakhardlink", NULL };
+static char *(p_bo_values[]) = { "all", "backspace", "cursor", "complete", "copy", "ctrlg", "error",
+ "esc", "ex", "hangul", "lang", "mess", "showmatch", "operator",
+ "register", "shell", "spell", "wildmode", NULL };
+static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", NULL };
+static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
+static char *(p_cmp_values[]) = { "internal", "keepascii", NULL };
+static char *(p_dy_values[]) = { "lastline", "truncate", "uhex", "msgsep", NULL };
+static char *(p_fdo_values[]) = { "all", "block", "hor", "mark", "percent", "quickfix", "search",
+ "tag", "insert", "undo", "jump", NULL };
+/// Also used for 'viewoptions'! Keep in sync with SSOP_ flags.
+static char *(p_ssop_values[]) = { "buffers", "winpos", "resize", "winsize", "localoptions",
+ "options", "help", "blank", "globals", "slash", "unix", "sesdir",
+ "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
+ NULL };
+// Keep in sync with SWB_ flags in option_defs.h
+static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast",
+ NULL };
+static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL };
+static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL };
+static char *(p_wop_values[]) = { "tagfile", "pum", NULL };
+static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
+static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos", "mac", NULL };
+static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
+static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
+static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
+static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
+static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
+static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
+static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix", "help", "acwrite",
+ "terminal", "prompt", NULL };
+static char *(p_bufhidden_values[]) = { "hide", "unload", "delete", "wipe", NULL };
+static char *(p_bs_values[]) = { "indent", "eol", "start", "nostop", NULL };
+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 };
+#ifdef BACKSLASH_IN_FILENAME
+static char *(p_csl_values[]) = { "slash", "backslash", NULL };
+#endif
+
+static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2", "auto:3", "auto:4",
+ "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", "yes:1",
+ "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8",
+ "yes:9", "number", NULL };
+static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2", "auto:3", "auto:4", "auto:5",
+ "auto:6", "auto:7", "auto:8", "auto:9", "0", "1", "2", "3", "4",
+ "5", "6", "7", "8", "9", NULL };
+static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
+static char *(p_icm_values[]) = { "nosplit", "split", NULL };
+static char *(p_jop_values[]) = { "stack", "view", NULL };
+static char *(p_tpf_values[]) = { "BS", "HT", "FF", "ESC", "DEL", "C0", "C1", NULL };
+static char *(p_rdb_values[]) = { "compositor", "nothrottle", "invalid", "nodelta", NULL };
+
+/// All possible flags for 'shm'.
+static char_u SHM_ALL[] = { SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW,
+ SHM_WRI, SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL,
+ SHM_OVER, SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO,
+ SHM_COMPLETIONMENU, SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT, 0, };
+
+/// After setting various option values: recompute variables that depend on
+/// 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_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_jop, p_jop_values, &jop_flags, true);
+ (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
+}
+
+/// Trigger the OptionSet autocommand.
+/// "opt_idx" is the index of the option being set.
+/// "opt_flags" can be OPT_LOCAL etc.
+/// "oldval" the old value
+/// "oldval_l" the old local value (only non-NULL if global and local value are set)
+/// "oldval_g" the old global value (only non-NULL if global and local value are set)
+/// "newval" the new value
+void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l,
+ char *oldval_g, char *newval)
+{
+ // Don't do this recursively.
+ if (oldval != NULL
+ && newval != NULL
+ && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
+ char buf_type[7];
+
+ vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
+ (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_OLD, oldval, -1);
+ set_vim_var_string(VV_OPTION_NEW, newval, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ if (opt_flags & OPT_LOCAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
+ }
+ if (opt_flags & OPT_GLOBAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1);
+ }
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ set_vim_var_string(VV_OPTION_COMMAND, "set", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1);
+ }
+ if (opt_flags & OPT_MODELINE) {
+ set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
+ }
+ apply_autocmds(EVENT_OPTIONSET, get_option_fullname(opt_idx), NULL, false, NULL);
+ reset_v_option_vars();
+ }
+}
+
+static char *illegal_char(char *errbuf, size_t errbuflen, int c)
+{
+ if (errbuf == NULL) {
+ return "";
+ }
+ vim_snprintf(errbuf, errbuflen, _("E539: Illegal character <%s>"),
+ (char *)transchar(c));
+ return errbuf;
+}
+
+/// Check string options in a buffer for NULL value.
+void check_buf_options(buf_T *buf)
+{
+ check_string_option(&buf->b_p_bh);
+ check_string_option(&buf->b_p_bt);
+ check_string_option(&buf->b_p_fenc);
+ check_string_option(&buf->b_p_ff);
+ check_string_option(&buf->b_p_def);
+ check_string_option(&buf->b_p_inc);
+ check_string_option(&buf->b_p_inex);
+ check_string_option(&buf->b_p_inde);
+ check_string_option(&buf->b_p_indk);
+ check_string_option(&buf->b_p_fp);
+ check_string_option(&buf->b_p_fex);
+ check_string_option(&buf->b_p_kp);
+ check_string_option(&buf->b_p_mps);
+ check_string_option(&buf->b_p_fo);
+ check_string_option(&buf->b_p_flp);
+ check_string_option(&buf->b_p_isk);
+ check_string_option(&buf->b_p_com);
+ check_string_option(&buf->b_p_cms);
+ check_string_option(&buf->b_p_nf);
+ check_string_option(&buf->b_p_qe);
+ check_string_option(&buf->b_p_syn);
+ check_string_option(&buf->b_s.b_syn_isk);
+ check_string_option(&buf->b_s.b_p_spc);
+ check_string_option(&buf->b_s.b_p_spf);
+ check_string_option(&buf->b_s.b_p_spl);
+ check_string_option(&buf->b_s.b_p_spo);
+ check_string_option(&buf->b_p_sua);
+ check_string_option(&buf->b_p_cink);
+ check_string_option(&buf->b_p_cino);
+ parse_cino(buf);
+ check_string_option(&buf->b_p_ft);
+ check_string_option(&buf->b_p_cinw);
+ check_string_option(&buf->b_p_cinsd);
+ check_string_option(&buf->b_p_cpt);
+ check_string_option(&buf->b_p_cfu);
+ check_string_option(&buf->b_p_ofu);
+ check_string_option(&buf->b_p_keymap);
+ check_string_option(&buf->b_p_gp);
+ check_string_option(&buf->b_p_mp);
+ check_string_option(&buf->b_p_efm);
+ check_string_option(&buf->b_p_ep);
+ check_string_option(&buf->b_p_path);
+ check_string_option(&buf->b_p_tags);
+ check_string_option(&buf->b_p_tfu);
+ check_string_option(&buf->b_p_tc);
+ check_string_option(&buf->b_p_dict);
+ check_string_option(&buf->b_p_tsr);
+ check_string_option(&buf->b_p_tsrfu);
+ check_string_option(&buf->b_p_lw);
+ check_string_option(&buf->b_p_bkc);
+ check_string_option(&buf->b_p_menc);
+ check_string_option(&buf->b_p_vsts);
+ check_string_option(&buf->b_p_vts);
+}
+
+/// Free the string allocated for an option.
+/// Checks for the string being empty_option. This may happen if we're out of
+/// memory, vim_strsave() returned NULL, which was replaced by empty_option by
+/// check_options().
+/// Does NOT check for P_ALLOCED flag!
+void free_string_option(char_u *p)
+{
+ if (p != empty_option) {
+ xfree(p);
+ }
+}
+
+void clear_string_option(char_u **pp)
+{
+ if (*pp != empty_option) {
+ xfree(*pp);
+ }
+ *pp = empty_option;
+}
+
+void check_string_option(char_u **pp)
+{
+ if (*pp == NULL) {
+ *pp = empty_option;
+ }
+}
+
+/// Set global value for string option when it's a local option.
+///
+/// @param opt_idx option index
+/// @param varp pointer to option variable
+static void set_string_option_global(int opt_idx, char_u **varp)
+{
+ char_u **p, *s;
+
+ // the global value is always allocated
+ if (is_window_local_option(opt_idx)) {
+ p = (char_u **)GLOBAL_WO(varp);
+ } else {
+ p = (char_u **)get_option_var(opt_idx);
+ }
+ if (!is_global_option(opt_idx) && p != varp) {
+ s = vim_strsave(*varp);
+ free_string_option(*p);
+ *p = s;
+ }
+}
+
+/// 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.
+/// 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
+void set_string_option_direct(const char *name, int opt_idx, const char *val, int opt_flags,
+ int set_sid)
+{
+ char *s;
+ char **varp;
+ 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;
+ }
+ }
+
+ if (is_hidden_option(idx)) { // can't set hidden option
+ return;
+ }
+
+ assert((void *)get_option_var(idx) != (void *)&p_shada);
+
+ s = xstrdup(val);
+ {
+ varp = (char **)get_option_varp_scope(idx, both ? OPT_LOCAL : opt_flags);
+ if ((opt_flags & OPT_FREE) && (get_option_flags(idx) & P_ALLOCED)) {
+ free_string_option((char_u *)(*varp));
+ }
+ *varp = s;
+
+ // For buffer/window local option may also set the global value.
+ if (both) {
+ set_string_option_global(idx, (char_u **)varp);
+ }
+
+ set_option_flag(idx, P_ALLOCED);
+
+ // 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 (is_global_local_option(idx) && both) {
+ free_string_option((char_u *)(*varp));
+ *varp = (char *)empty_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_idx(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)
+{
+ 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);
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ unblock_autocmds();
+}
+
+/// Set a string option to a new value, handling the effects
+///
+/// @param[in] opt_idx Option to set.
+/// @param[in] value New value.
+/// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or
+/// #OPT_GLOBAL.
+///
+/// @return NULL on success, error message on error.
+char *set_string_option(const int opt_idx, const char *const value, const int opt_flags)
+ FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (is_hidden_option(opt_idx)) { // don't set hidden option
+ return NULL;
+ }
+
+ char *const s = xstrdup(value);
+ char **const varp
+ = (char **)get_option_varp_scope(opt_idx,
+ (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ ? (is_global_local_option(opt_idx)
+ ? OPT_GLOBAL : OPT_LOCAL)
+ : opt_flags);
+ char *const oldval = *varp;
+ char *oldval_l = NULL;
+ char *oldval_g = NULL;
+
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ oldval_l = *(char **)get_option_varp_scope(opt_idx, OPT_LOCAL);
+ oldval_g = *(char **)get_option_varp_scope(opt_idx, OPT_GLOBAL);
+ }
+
+ *varp = s;
+
+ char *const saved_oldval = xstrdup(oldval);
+ char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup(oldval_l) : 0;
+ char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup(oldval_g) : 0;
+ char *const saved_newval = xstrdup(s);
+
+ int value_checked = false;
+ char *const r = did_set_string_option(opt_idx, (char_u **)varp, (char_u *)oldval,
+ NULL, 0,
+ opt_flags, &value_checked);
+ if (r == NULL) {
+ did_set_option(opt_idx, opt_flags, true, value_checked);
+ }
+
+ // call autocommand after handling side effects
+ if (r == NULL) {
+ if (!starting) {
+ trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g,
+ saved_newval);
+ }
+ if (get_option_flags(opt_idx) & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(get_option_fullname(opt_idx)),
+ STRING_OBJ(cstr_as_string(saved_newval)));
+ }
+ }
+ xfree(saved_oldval);
+ xfree(saved_oldval_l);
+ xfree(saved_oldval_g);
+ xfree(saved_newval);
+
+ return r;
+}
+
+/// Return true if "val" is a valid 'filetype' name.
+/// Also used for 'syntax' and 'keymap'.
+static bool valid_filetype(const char_u *val)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return valid_name(val, ".-_");
+}
+
+/// Handle setting 'mousescroll'.
+/// @return error message, NULL if it's OK.
+static char *check_mousescroll(char *string)
+{
+ long vertical = -1;
+ long horizontal = -1;
+
+ for (;;) {
+ char *end = vim_strchr(string, ',');
+ size_t length = end ? (size_t)(end - string) : STRLEN(string);
+
+ // Both "ver:" and "hor:" are 4 bytes long.
+ // They should be followed by at least one digit.
+ if (length <= 4) {
+ return e_invarg;
+ }
+
+ long *direction;
+
+ if (memcmp(string, "ver:", 4) == 0) {
+ direction = &vertical;
+ } else if (memcmp(string, "hor:", 4) == 0) {
+ direction = &horizontal;
+ } else {
+ return e_invarg;
+ }
+
+ // If the direction has already been set, this is a duplicate.
+ if (*direction != -1) {
+ return e_invarg;
+ }
+
+ // Verify that only digits follow the colon.
+ for (size_t i = 4; i < length; i++) {
+ if (!ascii_isdigit(string[i])) {
+ return N_("E548: digit expected");
+ }
+ }
+
+ string += 4;
+ *direction = getdigits_int(&string, false, -1);
+
+ // Num options are generally kept within the signed int range.
+ // We know this number won't be negative because we've already checked for
+ // a minus sign. We'll allow 0 as a means of disabling mouse scrolling.
+ if (*direction == -1) {
+ return e_invarg;
+ }
+
+ if (!end) {
+ break;
+ }
+
+ string = end + 1;
+ }
+
+ // If a direction wasn't set, fallback to the default value.
+ p_mousescroll_vert = (vertical == -1) ? MOUSESCROLL_VERT_DFLT : vertical;
+ p_mousescroll_hor = (horizontal == -1) ? MOUSESCROLL_HOR_DFLT : horizontal;
+
+ return NULL;
+}
+
+/// Handle setting 'signcolumn' for value 'val'
+///
+/// @return OK when the value is valid, FAIL otherwise
+static int check_signcolumn(char_u *val)
+{
+ if (*val == NUL) {
+ return FAIL;
+ }
+ // check for basic match
+ if (check_opt_strings(val, p_scl_values, false) == OK) {
+ return OK;
+ }
+
+ // check for 'auto:<NUMBER>-<NUMBER>'
+ if (STRLEN(val) == 8
+ && !STRNCMP(val, "auto:", 5)
+ && ascii_isdigit(val[5])
+ && val[6] == '-'
+ && ascii_isdigit(val[7])) {
+ int min = val[5] - '0';
+ int max = val[7] - '0';
+ if (min < 1 || max < 2 || min > 8 || max > 9 || min >= max) {
+ return FAIL;
+ }
+ return OK;
+ }
+
+ return FAIL;
+}
+
+/// Check validity of options with the 'statusline' format.
+/// Return an untranslated error message or NULL.
+char *check_stl_option(char *s)
+{
+ int groupdepth = 0;
+ static char errbuf[80];
+
+ while (*s) {
+ // Check for valid keys after % sequences
+ while (*s && *s != '%') {
+ s++;
+ }
+ if (!*s) {
+ break;
+ }
+ s++;
+ if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) {
+ s++;
+ continue;
+ }
+ if (*s == ')') {
+ s++;
+ if (--groupdepth < 0) {
+ break;
+ }
+ continue;
+ }
+ if (*s == '-') {
+ s++;
+ }
+ while (ascii_isdigit(*s)) {
+ s++;
+ }
+ if (*s == STL_USER_HL) {
+ continue;
+ }
+ if (*s == '.') {
+ s++;
+ while (*s && ascii_isdigit(*s)) {
+ s++;
+ }
+ }
+ if (*s == '(') {
+ groupdepth++;
+ continue;
+ }
+ if (vim_strchr(STL_ALL, *s) == NULL) {
+ return illegal_char(errbuf, sizeof(errbuf), *s);
+ }
+ if (*s == '{') {
+ bool reevaluate = (*++s == '%');
+
+ if (reevaluate && *++s == '}') {
+ // "}" is not allowed immediately after "%{%"
+ return illegal_char(errbuf, sizeof(errbuf), '}');
+ }
+ while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s) {
+ s++;
+ }
+ if (*s != '}') {
+ return e_unclosed_expression_sequence;
+ }
+ }
+ }
+ if (groupdepth != 0) {
+ return e_unbalanced_groups;
+ }
+ return NULL;
+}
+
+static int shada_idx = -1;
+
+/// Handle string options that need some action to perform when changed.
+/// The new value must be allocated.
+/// Returns NULL for success, or an error message for an error.
+///
+/// @param opt_idx index in options[] table
+/// @param varp pointer to the option variable
+/// @param oldval previous value of the option
+/// @param errbuf buffer for errors, or NULL
+/// @param errbuflen length of errors buffer
+/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
+/// @param value_checked value was checked to be safe, no need to set P_INSECURE
+char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *errbuf,
+ size_t errbuflen, int opt_flags, int *value_checked)
+{
+ char *errmsg = NULL;
+ char *s, *p;
+ int did_chartab = false;
+ char_u **gvarp;
+ bool free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
+ bool value_changed = false;
+
+ // Get the global option to compare with, otherwise we would have to check
+ // two values for all local options.
+ gvarp = (char_u **)get_option_varp_scope(opt_idx, OPT_GLOBAL);
+
+ // Disallow changing some options from secure mode
+ if ((secure || sandbox != 0)
+ && (get_option_flags(opt_idx) & P_SECURE)) {
+ errmsg = e_secure;
+ } else if (((get_option_flags(opt_idx) & P_NFNAME)
+ && strpbrk((char *)(*varp),
+ (secure ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
+ || ((get_option_flags(opt_idx) & P_NDNAME)
+ && strpbrk((char *)(*varp), "*?[|;&<>\r\n") != NULL)) {
+ // Check for a "normal" directory or file name in some options. Disallow a
+ // path separator (slash and/or backslash), wildcards and characters that
+ // are often illegal in a file name. Be more permissive if "secure" is off.
+ errmsg = e_invarg;
+ } else if (gvarp == &p_bkc) { // 'backupcopy'
+ char_u *bkc = p_bkc;
+ unsigned int *flags = &bkc_flags;
+
+ if (opt_flags & OPT_LOCAL) {
+ bkc = curbuf->b_p_bkc;
+ flags = &curbuf->b_bkc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *bkc == NUL) {
+ // make the local value empty: use the global value
+ *flags = 0;
+ } else {
+ if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+
+ if (((*flags & BKC_AUTO) != 0)
+ + ((*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);
+ errmsg = e_invarg;
+ }
+ }
+ } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode'
+ if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
+ *p_pm == '.' ? p_pm + 1 : p_pm) == 0) {
+ errmsg = N_("E589: 'backupext' and 'patchmode' are equal");
+ }
+ } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt'
+ if (briopt_check(curwin) == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_isi
+ || varp == &(curbuf->b_p_isk)
+ || varp == &p_isp
+ || varp == &p_isf) {
+ // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
+ // If the new option is invalid, use old value. 'lisp' option: refill
+ // g_chartab[] for '-' char
+ if (init_chartab() == FAIL) {
+ did_chartab = true; // need to restore it below
+ errmsg = e_invarg; // error in value
+ }
+ } else if (varp == &p_hf) { // 'helpfile'
+ // May compute new values for $VIM and $VIMRUNTIME
+ if (didset_vim) {
+ os_setenv("VIM", "", 1);
+ didset_vim = false;
+ }
+ if (didset_vimruntime) {
+ os_setenv("VIMRUNTIME", "", 1);
+ didset_vimruntime = false;
+ }
+ } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath'
+ runtime_search_path_invalidate();
+ } else if (varp == &curwin->w_p_culopt
+ || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
+ if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &curwin->w_p_cc) { // 'colorcolumn'
+ errmsg = check_colorcolumn(curwin);
+ } else if (varp == &p_hlg) { // 'helplang'
+ // Check for "", "ab", "ab,cd", etc.
+ for (s = (char *)p_hlg; *s != NUL; s += 3) {
+ if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) {
+ errmsg = e_invarg;
+ break;
+ }
+ if (s[2] == NUL) {
+ break;
+ }
+ }
+ } else if (varp == &p_hl) { // 'highlight'
+ if (STRCMP(*varp, HIGHLIGHT_INIT) != 0) {
+ errmsg = e_unsupportedoption;
+ }
+ } else if (varp == &p_jop) { // 'jumpoptions'
+ if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_nf) { // 'nrformats'
+ if (check_opt_strings(*varp, p_nf_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_ssop) { // 'sessionoptions'
+ if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
+ // Don't allow both "sesdir" and "curdir".
+ (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_vop) { // 'viewoptions'
+ if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_rdb) { // 'redrawdebug'
+ if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == (char_u **)&p_sbo) { // 'scrollopt'
+ if (check_opt_strings((char_u *)p_sbo, p_scbopt_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_ambw || (int *)varp == &p_emoji) { // 'ambiwidth'
+ if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) {
+ errmsg = e_invarg;
+ } else {
+ errmsg = check_chars_options();
+ }
+ } else if (varp == &p_bg) { // 'background'
+ if (check_opt_strings(p_bg, p_bg_values, false) == OK) {
+ int dark = (*p_bg == 'd');
+
+ init_highlight(false, false);
+
+ if (dark != (*p_bg == 'd') && get_var_value("g:colors_name") != NULL) {
+ // The color scheme must have set 'background' back to another
+ // value, that's not what we want here. Disable the color
+ // scheme and set the colors again.
+ do_unlet(S_LEN("g:colors_name"), true);
+ free_string_option(p_bg);
+ p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
+ check_string_option(&p_bg);
+ init_highlight(false, false);
+ }
+ } else {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_wim) { // 'wildmode'
+ if (check_opt_wim() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_wop) { // 'wildoptions'
+ if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_wak) { // 'winaltkeys'
+ if (*p_wak == NUL
+ || check_opt_strings(p_wak, p_wak_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_ei) { // 'eventignore'
+ if (check_ei() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) {
+ // 'encoding', 'fileencoding' and 'makeencoding'
+ if (gvarp == &p_fenc) {
+ if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) {
+ errmsg = e_modifiable;
+ } else if (vim_strchr((char *)(*varp), ',') != NULL) {
+ // No comma allowed in 'fileencoding'; catches confusing it
+ // with 'fileencodings'.
+ errmsg = e_invarg;
+ } else {
+ // May show a "+" in the title now.
+ redraw_titles();
+ // Add 'fileencoding' to the swap file.
+ ml_setflags(curbuf);
+ }
+ }
+
+ if (errmsg == NULL) {
+ // canonize the value, so that STRCMP() can be used on it
+ p = (char *)enc_canonize(*varp);
+ xfree(*varp);
+ *varp = (char_u *)p;
+ if (varp == &p_enc) {
+ // only encoding=utf-8 allowed
+ if (STRCMP(p_enc, "utf-8") != 0) {
+ errmsg = e_unsupportedoption;
+ } else {
+ spell_reload();
+ }
+ }
+ }
+ } else if (varp == &p_penc) {
+ // Canonize printencoding if VIM standard one
+ p = (char *)enc_canonize(p_penc);
+ xfree(p_penc);
+ p_penc = (char_u *)p;
+ } else if (varp == &curbuf->b_p_keymap) {
+ if (!valid_filetype(*varp)) {
+ errmsg = e_invarg;
+ } else {
+ int secure_save = secure;
+
+ // Reset the secure flag, since the value of 'keymap' has
+ // been checked to be safe.
+ secure = 0;
+
+ // load or unload key mapping tables
+ errmsg = keymap_init();
+
+ secure = secure_save;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = true;
+ }
+
+ if (errmsg == NULL) {
+ if (*curbuf->b_p_keymap != NUL) {
+ // Installed a new keymap, switch on using it.
+ curbuf->b_p_iminsert = B_IMODE_LMAP;
+ if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) {
+ curbuf->b_p_imsearch = B_IMODE_LMAP;
+ }
+ } else {
+ // Cleared the keymap, may reset 'iminsert' and 'imsearch'.
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP) {
+ curbuf->b_p_iminsert = B_IMODE_NONE;
+ }
+ if (curbuf->b_p_imsearch == B_IMODE_LMAP) {
+ curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
+ }
+ }
+ if ((opt_flags & OPT_LOCAL) == 0) {
+ set_iminsert_global();
+ set_imsearch_global();
+ }
+ status_redraw_curbuf();
+ }
+ } else if (gvarp == &p_ff) { // 'fileformat'
+ if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) {
+ errmsg = e_modifiable;
+ } else if (check_opt_strings(*varp, p_ff_values, false) != OK) {
+ errmsg = e_invarg;
+ } else {
+ redraw_titles();
+ // update flag in swap file
+ ml_setflags(curbuf);
+ // Redraw needed when switching to/from "mac": a CR in the text
+ // will be displayed differently.
+ if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') {
+ redraw_curbuf_later(NOT_VALID);
+ }
+ }
+ } else if (varp == (char_u **)&p_ffs) { // 'fileformats'
+ if (check_opt_strings((char_u *)p_ffs, p_ff_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_mps) { // 'matchpairs'
+ for (p = (char *)(*varp); *p != NUL; p++) {
+ int x2 = -1;
+ int x3 = -1;
+
+ p += utfc_ptr2len(p);
+ if (*p != NUL) {
+ x2 = (unsigned char)(*p++);
+ }
+ if (*p != NUL) {
+ x3 = utf_ptr2char(p);
+ p += utfc_ptr2len(p);
+ }
+ if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) {
+ errmsg = e_invarg;
+ break;
+ }
+ if (*p == NUL) {
+ break;
+ }
+ }
+ } else if (gvarp == &p_com) { // 'comments'
+ for (s = (char *)(*varp); *s;) {
+ while (*s && *s != ':') {
+ if (vim_strchr(COM_ALL, *s) == NULL
+ && !ascii_isdigit(*s) && *s != '-') {
+ errmsg = illegal_char(errbuf, errbuflen, *s);
+ break;
+ }
+ s++;
+ }
+ if (*s++ == NUL) {
+ errmsg = N_("E524: Missing colon");
+ } else if (*s == ',' || *s == NUL) {
+ errmsg = N_("E525: Zero length string");
+ }
+ if (errmsg != NULL) {
+ break;
+ }
+ while (*s && *s != ',') {
+ if (*s == '\\' && s[1] != NUL) {
+ s++;
+ }
+ s++;
+ }
+ s = (char *)skip_to_option_part((char_u *)s);
+ }
+ } else if (varp == &p_lcs) { // global 'listchars'
+ errmsg = set_chars_option(curwin, varp, false);
+ if (errmsg == NULL) {
+ // The current window is set to use the global 'listchars' value.
+ // So clear the window-local value.
+ if (!(opt_flags & OPT_GLOBAL)) {
+ clear_string_option(&curwin->w_p_lcs);
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ // If no error was returned above, we don't expect an error
+ // here, so ignore the return value.
+ (void)set_chars_option(wp, &wp->w_p_lcs, true);
+ }
+ redraw_all_later(NOT_VALID);
+ }
+ } else if (varp == &curwin->w_p_lcs) { // local 'listchars'
+ 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, &wp->w_p_fcs, true);
+ }
+ redraw_all_later(NOT_VALID);
+ }
+ } else if (varp == &curwin->w_p_fcs) { // local 'fillchars'
+ errmsg = set_chars_option(curwin, varp, true);
+ } else if (varp == &p_cedit) { // 'cedit'
+ errmsg = check_cedit();
+ } else if (varp == &p_vfile) { // 'verbosefile'
+ verbose_stop();
+ if (*p_vfile != NUL && verbose_open() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_shada) { // 'shada'
+ // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
+ // option.
+ opt_idx = ((get_option_fullname(opt_idx)[0] == 'v')
+ ? (shada_idx == -1 ? ((shada_idx = findoption("shada"))) : shada_idx)
+ : opt_idx);
+ // Update free_oldval now that we have the opt_idx for 'shada', otherwise
+ // there would be a disconnect between the check for P_ALLOCED at the start
+ // of the function and the set of P_ALLOCED at the end of the function.
+ free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
+ for (s = (char *)p_shada; *s;) {
+ // Check it's a valid character
+ if (vim_strchr("!\"%'/:<@cfhnrs", *s) == NULL) {
+ errmsg = illegal_char(errbuf, errbuflen, *s);
+ break;
+ }
+ if (*s == 'n') { // name is always last one
+ break;
+ } else if (*s == 'r') { // skip until next ','
+ while (*++s && *s != ',') {}
+ } else if (*s == '%') {
+ // optional number
+ while (ascii_isdigit(*++s)) {}
+ } else if (*s == '!' || *s == 'h' || *s == 'c') {
+ s++; // no extra chars
+ } else { // must have a number
+ while (ascii_isdigit(*++s)) {}
+
+ if (!ascii_isdigit(*(s - 1))) {
+ if (errbuf != NULL) {
+ vim_snprintf(errbuf, errbuflen,
+ _("E526: Missing number after <%s>"),
+ transchar_byte(*(s - 1)));
+ errmsg = errbuf;
+ } else {
+ errmsg = "";
+ }
+ break;
+ }
+ }
+ if (*s == ',') {
+ s++;
+ } else if (*s) {
+ if (errbuf != NULL) {
+ errmsg = N_("E527: Missing comma");
+ } else {
+ errmsg = "";
+ }
+ break;
+ }
+ }
+ if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) {
+ errmsg = N_("E528: Must specify a ' value");
+ }
+ } else if (gvarp == &p_sbr) { // 'showbreak'
+ for (s = (char *)(*varp); *s;) {
+ if (ptr2cells(s) != 1) {
+ errmsg = N_("E595: 'showbreak' contains unprintable or wide character");
+ }
+ MB_PTR_ADV(s);
+ }
+ } else if (varp == &p_guicursor) { // 'guicursor'
+ errmsg = parse_shape_opt(SHAPE_CURSOR);
+ } else if (varp == &p_popt) {
+ errmsg = parse_printoptions();
+ } else if (varp == &p_pmfn) {
+ errmsg = parse_printmbfont();
+ } else if (varp == &p_langmap) { // 'langmap'
+ langmap_set();
+ } else if (varp == &p_breakat) { // 'breakat'
+ fill_breakat_flags();
+ } else if (varp == &p_titlestring || varp == &p_iconstring) {
+ // 'titlestring' and 'iconstring'
+ int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
+
+ // NULL => statusline syntax
+ if (vim_strchr((char *)(*varp), '%') && check_stl_option((char *)(*varp)) == NULL) {
+ stl_syntax |= flagval;
+ } else {
+ stl_syntax &= ~flagval;
+ }
+ did_set_title();
+ } else if (varp == &p_sel) { // 'selection'
+ if (*p_sel == NUL
+ || check_opt_strings(p_sel, p_sel_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_slm) { // 'selectmode'
+ if (check_opt_strings(p_slm, p_slm_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_km) { // 'keymodel'
+ if (check_opt_strings(p_km, p_km_values, true) != OK) {
+ errmsg = e_invarg;
+ } else {
+ km_stopsel = (vim_strchr((char *)p_km, 'o') != NULL);
+ km_startsel = (vim_strchr((char *)p_km, 'a') != NULL);
+ }
+ } else if (varp == &p_mousem) { // 'mousemodel'
+ if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_mousescroll) { // 'mousescroll'
+ errmsg = check_mousescroll((char *)p_mousescroll);
+ } else if (varp == &p_swb) { // 'switchbuf'
+ if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_debug) { // 'debug'
+ if (check_opt_strings(p_debug, p_debug_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_dy) { // 'display'
+ if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) {
+ errmsg = e_invarg;
+ } else {
+ (void)init_chartab();
+ msg_grid_validate();
+ }
+ } else if (varp == &p_ead) { // 'eadirection'
+ if (check_opt_strings(p_ead, p_ead_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_cb) { // 'clipboard'
+ if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &(curwin->w_s->b_p_spl) // 'spell'
+ || varp == &(curwin->w_s->b_p_spf)) {
+ // When 'spelllang' or 'spellfile' is set and there is a window for this
+ // buffer in which 'spell' is set load the wordlists.
+ const bool is_spellfile = varp == &(curwin->w_s->b_p_spf);
+
+ if ((is_spellfile && !valid_spellfile(*varp))
+ || (!is_spellfile && !valid_spelllang(*varp))) {
+ errmsg = e_invarg;
+ } else {
+ errmsg = did_set_spell_option(is_spellfile);
+ }
+ } else if (varp == &(curwin->w_s->b_p_spc)) {
+ // When 'spellcapcheck' is set compile the regexp program.
+ errmsg = compile_cap_prog(curwin->w_s);
+ } else if (varp == &(curwin->w_s->b_p_spo)) { // 'spelloptions'
+ if (**varp != NUL && STRCMP("camel", *varp) != 0) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_sps) { // 'spellsuggest'
+ if (spell_check_sps() != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_msm) { // 'mkspellmem'
+ if (spell_check_msm() != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_bh) {
+ // When 'bufhidden' is set, check for valid value.
+ if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_bt) {
+ // When 'buftype' is set, check for valid value.
+ if ((curbuf->terminal && curbuf->b_p_bt[0] != 't')
+ || (!curbuf->terminal && curbuf->b_p_bt[0] == 't')
+ || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) {
+ errmsg = e_invarg;
+ } else {
+ if (curwin->w_status_height || global_stl_height()) {
+ curwin->w_redr_status = true;
+ redraw_later(curwin, VALID);
+ }
+ curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
+ redraw_titles();
+ }
+ } else if (gvarp == &p_stl || gvarp == (char_u **)&p_wbr || varp == &p_tal || varp == &p_ruf) {
+ // 'statusline', 'winbar', 'tabline' or 'rulerformat'
+ int wid;
+
+ if (varp == &p_ruf) { // reset ru_wid first
+ ru_wid = 0;
+ }
+ s = (char *)(*varp);
+ if (varp == &p_ruf && *s == '%') {
+ // set ru_wid if 'ruf' starts with "%99("
+ if (*++s == '-') { // ignore a '-'
+ s++;
+ }
+ wid = getdigits_int(&s, true, 0);
+ if (wid && *s == '(' && (errmsg = check_stl_option((char *)p_ruf)) == NULL) {
+ ru_wid = wid;
+ } else {
+ errmsg = check_stl_option((char *)p_ruf);
+ }
+ } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
+ // check 'statusline', 'winbar' or 'tabline' only if it doesn't start with "%!"
+ errmsg = check_stl_option(s);
+ }
+ if (varp == &p_ruf && errmsg == NULL) {
+ comp_col();
+ }
+ // add / remove window bars for 'winbar'
+ if (gvarp == (char_u **)&p_wbr) {
+ set_winbar(true);
+ }
+ } else if (gvarp == &p_cpt) {
+ // check if it is a valid value for 'complete' -- Acevedo
+ for (s = (char *)(*varp); *s;) {
+ while (*s == ',' || *s == ' ') {
+ s++;
+ }
+ if (!*s) {
+ break;
+ }
+ if (vim_strchr(".wbuksid]tU", *s) == NULL) {
+ errmsg = illegal_char(errbuf, errbuflen, *s);
+ break;
+ }
+ if (*++s != NUL && *s != ',' && *s != ' ') {
+ if (s[-1] == 'k' || s[-1] == 's') {
+ // skip optional filename after 'k' and 's'
+ while (*s && *s != ',' && *s != ' ') {
+ if (*s == '\\' && s[1] != NUL) {
+ s++;
+ }
+ s++;
+ }
+ } else {
+ if (errbuf != NULL) {
+ vim_snprintf(errbuf, errbuflen,
+ _("E535: Illegal character after <%c>"),
+ *--s);
+ errmsg = errbuf;
+ } else {
+ errmsg = "";
+ }
+ break;
+ }
+ }
+ }
+ } else if (varp == &p_cot) { // 'completeopt'
+ if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
+ errmsg = e_invarg;
+ } else {
+ completeopt_was_set();
+ }
+#ifdef BACKSLASH_IN_FILENAME
+ } else if (gvarp == &p_csl) { // 'completeslash'
+ if (check_opt_strings(p_csl, p_csl_values, false) != OK
+ || check_opt_strings(curbuf->b_p_csl, p_csl_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+#endif
+ } else if (varp == &curwin->w_p_scl) { // 'signcolumn'
+ if (check_signcolumn(*varp) != OK) {
+ errmsg = e_invarg;
+ }
+ // 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')
+ || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u'))
+ && (curwin->w_p_nu || curwin->w_p_rnu)) {
+ curwin->w_nrwidth_line_count = 0;
+ }
+ } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) {
+ // 'foldcolumn'
+ if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_pt) {
+ // 'pastetoggle': translate key codes like in a mapping
+ if (*p_pt) {
+ p = NULL;
+ (void)replace_termcodes((char *)p_pt,
+ STRLEN(p_pt),
+ &p, REPTERM_FROM_PART | REPTERM_DO_LT, NULL,
+ CPO_TO_CPO_FLAGS);
+ if (p != NULL) {
+ free_string_option(p_pt);
+ p_pt = (char_u *)p;
+ }
+ }
+ } else if (varp == &p_bs) { // 'backspace'
+ if (ascii_isdigit(*p_bs)) {
+ if (*p_bs > '3' || p_bs[1] != NUL) {
+ errmsg = e_invarg;
+ }
+ } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_bo) {
+ if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_tc) { // 'tagcase'
+ unsigned int *flags;
+
+ if (opt_flags & OPT_LOCAL) {
+ p = (char *)curbuf->b_p_tc;
+ flags = &curbuf->b_tc_flags;
+ } else {
+ p = (char *)p_tc;
+ flags = &tc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *p == NUL) {
+ // make the local value empty: use the global value
+ *flags = 0;
+ } else if (*p == NUL
+ || opt_strings_flags((char_u *)p, p_tc_values, flags, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_cmp) { // 'casemap'
+ if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_dip) { // 'diffopt'
+ if (diffopt_changed() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod'
+ if (check_opt_strings(*varp, p_fdm_values, false) != OK
+ || *curwin->w_p_fdm == NUL) {
+ errmsg = e_invarg;
+ } else {
+ foldUpdateAll(curwin);
+ if (foldmethodIsDiff(curwin)) {
+ newFoldLevel();
+ }
+ }
+ } else if (varp == &curwin->w_p_fde) { // 'foldexpr'
+ if (foldmethodIsExpr(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker'
+ p = vim_strchr((char *)(*varp), ',');
+ if (p == NULL) {
+ errmsg = N_("E536: comma required");
+ } else if ((char_u *)p == *varp || p[1] == NUL) {
+ errmsg = e_invarg;
+ } else if (foldmethodIsMarker(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else if (gvarp == &p_cms) { // 'commentstring'
+ if (**varp != NUL && strstr((char *)(*varp), "%s") == NULL) {
+ errmsg = N_("E537: 'commentstring' must be empty or contain %s");
+ }
+ } else if (varp == &p_fdo) { // 'foldopen'
+ if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_fcl) { // 'foldclose'
+ if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore'
+ if (foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else if (gvarp == &p_ve) { // 'virtualedit'
+ char_u *ve = p_ve;
+ unsigned int *flags = &ve_flags;
+
+ if (opt_flags & OPT_LOCAL) {
+ ve = curwin->w_p_ve;
+ flags = &curwin->w_ve_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *ve == NUL) {
+ // make the local value empty: use the global value
+ *flags = 0;
+ } else {
+ if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) {
+ errmsg = e_invarg;
+ } else if (STRCMP(p_ve, oldval) != 0) {
+ // Recompute cursor position in case the new 've' setting
+ // changes something.
+ validate_virtcol();
+ coladvance(curwin->w_virtcol);
+ }
+ }
+ } else if (varp == &p_csqf) {
+ if (p_csqf != NULL) {
+ p = (char *)p_csqf;
+ while (*p != NUL) {
+ if (vim_strchr(CSQF_CMDS, *p) == NULL
+ || p[1] == NUL
+ || vim_strchr(CSQF_FLAGS, p[1]) == NULL
+ || (p[2] != NUL && p[2] != ',')) {
+ errmsg = e_invarg;
+ break;
+ } else if (p[2] == NUL) {
+ break;
+ } else {
+ p += 3;
+ }
+ }
+ }
+ } else if (gvarp == &p_cino) { // 'cinoptions'
+ // TODO(vim): recognize errors
+ parse_cino(curbuf);
+ } else if (varp == &p_icm) { // 'inccommand'
+ if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (gvarp == &p_ft) {
+ if (!valid_filetype(*varp)) {
+ errmsg = e_invarg;
+ } else {
+ value_changed = STRCMP(oldval, *varp) != 0;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = true;
+ }
+ } else if (gvarp == &p_syn) {
+ if (!valid_filetype(*varp)) {
+ errmsg = e_invarg;
+ } else {
+ value_changed = STRCMP(oldval, *varp) != 0;
+
+ // Since we check the value, there is no need to set P_INSECURE,
+ // even when the value comes from a modeline.
+ *value_checked = true;
+ }
+ } else if (varp == &curwin->w_p_winhl) {
+ if (!parse_winhl_opt(curwin)) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_tpf) {
+ if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop'
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
+ XFREE_CLEAR(curbuf->b_p_vsts_array);
+ } else {
+ for (cp = *varp; *cp; cp++) {
+ if (ascii_isdigit(*cp)) {
+ continue;
+ }
+ if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
+ continue;
+ }
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL) {
+ long *oldarray = curbuf->b_p_vsts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) {
+ xfree(oldarray);
+ } else {
+ errmsg = e_invarg;
+ }
+ }
+ }
+ } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop'
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
+ XFREE_CLEAR(curbuf->b_p_vts_array);
+ } else {
+ for (cp = *varp; *cp; cp++) {
+ if (ascii_isdigit(*cp)) {
+ continue;
+ }
+ if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
+ continue;
+ }
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL) {
+ long *oldarray = curbuf->b_p_vts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) {
+ xfree(oldarray);
+ if (foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else {
+ errmsg = e_invarg;
+ }
+ }
+ }
+ } else if (varp == &p_opfunc) { // 'operatorfunc'
+ if (set_operatorfunc_option() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else if (varp == &p_qftf) { // 'quickfixtextfunc'
+ if (qf_process_qftf_option() == FAIL) {
+ errmsg = e_invarg;
+ }
+ } else {
+ // Options that are a list of flags.
+ p = NULL;
+ if (varp == &p_ww) { // 'whichwrap'
+ p = WW_ALL;
+ }
+ if (varp == &p_shm) { // 'shortmess'
+ p = (char *)SHM_ALL;
+ } else if (varp == (char_u **)&(p_cpo)) { // 'cpoptions'
+ p = CPO_VI;
+ } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions'
+ p = FO_ALL;
+ } else if (varp == &curwin->w_p_cocu) { // 'concealcursor'
+ p = COCU_ALL;
+ } else if (varp == &p_mouse) { // 'mouse'
+ p = MOUSE_ALL;
+ }
+ if (p != NULL) {
+ for (s = (char *)(*varp); *s; s++) {
+ if (vim_strchr(p, *s) == NULL) {
+ errmsg = illegal_char(errbuf, errbuflen, *s);
+ break;
+ }
+ }
+ }
+ }
+
+ // If error detected, restore the previous value.
+ if (errmsg != NULL) {
+ free_string_option(*varp);
+ *varp = oldval;
+ // When resetting some values, need to act on it.
+ if (did_chartab) {
+ (void)init_chartab();
+ }
+ } else {
+ // Remember where the option was set.
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+ // Free string options that are in allocated memory.
+ // Use "free_oldval", because recursiveness may change the flags under
+ // our fingers (esp. init_highlight()).
+ if (free_oldval) {
+ free_string_option(oldval);
+ }
+ set_option_flag(opt_idx, P_ALLOCED);
+
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ && is_global_local_option(opt_idx)) {
+ // global option with local value set to use global value; free
+ // the local value and make it empty
+ p = (char *)get_option_varp_scope(opt_idx, OPT_LOCAL);
+ free_string_option(*(char_u **)p);
+ *(char_u **)p = empty_option;
+ } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) {
+ // May set global value for local option.
+ set_string_option_global(opt_idx, varp);
+ }
+
+ // Trigger the autocommand only after setting the flags.
+ // When 'syntax' is set, load the syntax of that name
+ if (varp == &(curbuf->b_p_syn)) {
+ static int syn_recursive = 0;
+
+ syn_recursive++;
+ // Only pass true for "force" when the value changed or not used
+ // recursively, to avoid endless recurrence.
+ apply_autocmds(EVENT_SYNTAX, (char *)curbuf->b_p_syn, curbuf->b_fname,
+ value_changed || syn_recursive == 1, curbuf);
+ curbuf->b_flags |= BF_SYN_SET;
+ syn_recursive--;
+ } else if (varp == &(curbuf->b_p_ft)) {
+ // 'filetype' is set, trigger the FileType autocommand
+ // Skip this when called from a modeline and the filetype was
+ // already set to this value.
+ if (!(opt_flags & OPT_MODELINE) || value_changed) {
+ static int ft_recursive = 0;
+ int secure_save = secure;
+
+ // Reset the secure flag, since the value of 'filetype' has
+ // been checked to be safe.
+ secure = 0;
+
+ ft_recursive++;
+ did_filetype = true;
+ // Only pass true for "force" when the value changed or not
+ // used recursively, to avoid endless recurrence.
+ apply_autocmds(EVENT_FILETYPE, (char *)curbuf->b_p_ft, curbuf->b_fname,
+ value_changed || ft_recursive == 1, curbuf);
+ ft_recursive--;
+ // Just in case the old "curbuf" is now invalid
+ if (varp != &(curbuf->b_p_ft)) {
+ varp = NULL;
+ }
+ secure = secure_save;
+ }
+ }
+ if (varp == &(curwin->w_s->b_p_spl)) {
+ char_u fname[200];
+ char_u *q = curwin->w_s->b_p_spl;
+
+ // Skip the first name if it is "cjk".
+ if (STRNCMP(q, "cjk,", 4) == 0) {
+ q += 4;
+ }
+
+ // Source the spell/LANG.vim in 'runtimepath'.
+ // They could set 'spellcapcheck' depending on the language.
+ // Use the first name in 'spelllang' up to '_region' or
+ // '.encoding'.
+ for (p = (char *)q; *p != NUL; p++) {
+ if (!ASCII_ISALNUM(*p) && *p != '-') {
+ break;
+ }
+ }
+ if (p > (char *)q) {
+ vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim",
+ (int)(p - (char *)q), q);
+ source_runtime((char *)fname, DIP_ALL);
+ }
+ }
+ }
+
+ if (varp == &p_mouse) {
+ setmouse(); // in case 'mouse' changed
+ }
+
+ if (curwin->w_curswant != MAXCOL
+ && (get_option_flags(opt_idx) & (P_CURSWANT | P_RALL)) != 0) {
+ curwin->w_set_curswant = true;
+ }
+
+ check_redraw(get_option_flags(opt_idx));
+
+ return errmsg;
+}
+
+/// Check an option that can be a range of string values.
+///
+/// @param list when true: accept a list of values
+///
+/// @return OK for correct value, FAIL otherwise. Empty is always OK.
+static int check_opt_strings(char_u *val, char **values, int list)
+{
+ return opt_strings_flags(val, values, NULL, list);
+}
+
+/// Handle an option that can be a range of string values.
+/// Set a flag in "*flagp" for each string present.
+///
+/// @param val new value
+/// @param values array of valid string values
+/// @param list when true: accept a list of values
+///
+/// @return OK for correct value, FAIL otherwise. Empty is always OK.
+static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool list)
+{
+ unsigned int new_flags = 0;
+
+ while (*val) {
+ for (unsigned int i = 0;; i++) {
+ if (values[i] == NULL) { // val not found in values[]
+ return FAIL;
+ }
+
+ size_t len = STRLEN(values[i]);
+ if (STRNCMP(values[i], val, len) == 0
+ && ((list && val[len] == ',') || val[len] == NUL)) {
+ val += len + (val[len] == ',');
+ assert(i < sizeof(1U) * 8);
+ new_flags |= (1U << i);
+ break; // check next item in val list
+ }
+ }
+ }
+ if (flagp != NULL) {
+ *flagp = new_flags;
+ }
+
+ return OK;
+}
+
+/// @return OK if "p" is a valid fileformat name, FAIL otherwise.
+int check_ff_value(char_u *p)
+{
+ return check_opt_strings(p, p_ff_values, false);
+}
diff --git a/src/nvim/optionstr.h b/src/nvim/optionstr.h
new file mode 100644
index 0000000000..ac8d90e10e
--- /dev/null
+++ b/src/nvim/optionstr.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_OPTIONSTR_H
+#define NVIM_OPTIONSTR_H
+
+#include "nvim/buffer_defs.h" // for buf_T, win_T
+#include "nvim/option_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "optionstr.h.generated.h"
+#endif
+#endif // NVIM_OPTIONSTR_H
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index d04c2bc470..17fbbe17b8 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -34,6 +34,7 @@
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os_unix.h"
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index c9a8faa8c6..4bc6e362eb 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -30,6 +30,7 @@
#include "nvim/menu.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/profile.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c
index c3260fd496..e868a79b9a 100644
--- a/src/nvim/statusline.c
+++ b/src/nvim/statusline.c
@@ -19,6 +19,7 @@
#include "nvim/highlight_group.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/statusline.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 47b5647a08..2a3ec56451 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -37,6 +37,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index f212aefbfc..5866f11aab 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -34,6 +34,7 @@
#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 844a79b33d..08fcefaa88 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -69,6 +69,7 @@
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/state.h"
#include "nvim/terminal.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 564b5c4c51..68c5b42e30 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -42,6 +42,7 @@
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
diff --git a/test/unit/option_spec.lua b/test/unit/optionstr_spec.lua
index b3c3718035..f8122f4fe0 100644
--- a/test/unit/option_spec.lua
+++ b/test/unit/optionstr_spec.lua
@@ -4,7 +4,7 @@ local itp = helpers.gen_itp(it)
local to_cstr = helpers.to_cstr
local eq = helpers.eq
-local option = helpers.cimport("./src/nvim/option.h")
+local option = helpers.cimport("./src/nvim/optionstr.h")
local check_ff_value = function(ff)
return option.check_ff_value(to_cstr(ff))