diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-20 17:26:44 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-20 17:26:44 +0800 |
commit | ff5cfcdeab2446459ab59d44ce173ef811902c49 (patch) | |
tree | 2cad932a46390cb0d5821f13aa39f30b5be11770 | |
parent | 1cc4706e94489498b12c4844c1b3a2e9aa5cc921 (diff) | |
download | rneovim-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.c | 1 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 2 | ||||
-rw-r--r-- | src/nvim/buffer.c | 1 | ||||
-rw-r--r-- | src/nvim/diff.c | 7 | ||||
-rw-r--r-- | src/nvim/eval.c | 1 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 1 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 1 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 1 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 1 | ||||
-rw-r--r-- | src/nvim/fileio.c | 1 | ||||
-rw-r--r-- | src/nvim/help.c | 1 | ||||
-rw-r--r-- | src/nvim/main.c | 1 | ||||
-rw-r--r-- | src/nvim/ops.c | 39 | ||||
-rw-r--r-- | src/nvim/option.c | 1827 | ||||
-rw-r--r-- | src/nvim/option.h | 17 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 212 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 1665 | ||||
-rw-r--r-- | src/nvim/optionstr.h | 10 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 1 | ||||
-rw-r--r-- | src/nvim/screen.c | 1 | ||||
-rw-r--r-- | src/nvim/statusline.c | 1 | ||||
-rw-r--r-- | src/nvim/syntax.c | 1 | ||||
-rw-r--r-- | src/nvim/tag.c | 1 | ||||
-rw-r--r-- | src/nvim/terminal.c | 1 | ||||
-rw-r--r-- | src/nvim/window.c | 1 | ||||
-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)) |