blob: 553b55f687dfc2a5ec0e6defff39677d1cdafda0 [file] [log] [blame]
Bram Moolenaardac13472019-09-16 21:06:21 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * optionstr.c: Functions related to string options
12 */
13
14#include "vim.h"
15
Christian Brabandt9aee8ec2022-12-16 16:41:23 +000016static char_u shm_buf[SHM_LEN];
17static int set_shm_recursive = 0;
18
Bram Moolenaardac13472019-09-16 21:06:21 +020019static char *(p_ambw_values[]) = {"single", "double", NULL};
20static char *(p_bg_values[]) = {"light", "dark", NULL};
21static char *(p_bkc_values[]) = {"yes", "auto", "no", "breaksymlink", "breakhardlink", NULL};
22static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
23 "copy", "ctrlg", "error", "esc", "ex",
24 "hangul", "insertmode", "lang", "mess",
25 "showmatch", "operator", "register", "shell",
LemonBoy77771d32022-04-13 11:47:25 +010026 "spell", "term", "wildmode", NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +020027#if defined(FEAT_LINEBREAK)
28// Note: Keep this in sync with briopt_check()
29static char *(p_briopt_values[]) = {"shift:", "min:", "sbr", "list:", "column:", NULL};
30#endif
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020031#if defined(FEAT_TABPANEL)
32static char *(p_tpl_values[]) = {"wrap", "align:", "columns:", "vert:", NULL};
33#endif
Yee Cheng Chin900894b2023-09-29 20:42:32 +020034#if defined(FEAT_DIFF)
35// Note: Keep this in sync with diffopt_changed()
Yee Cheng Chin9943d472025-03-26 19:41:02 +010036static char *(p_dip_values[]) = {"filler", "context:", "iblank", "icase", "iwhite", "iwhiteall", "iwhiteeol", "horizontal", "vertical", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "indent-heuristic", "algorithm:", "inline:", "linematch:", NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +020037static char *(p_dip_algorithm_values[]) = {"myers", "minimal", "patience", "histogram", NULL};
Yee Cheng Chin9943d472025-03-26 19:41:02 +010038static char *(p_dip_inline_values[]) = {"none", "simple", "char", "word", NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +020039#endif
distobs25ac6d62024-07-06 17:50:09 +020040static char *(p_nf_values[]) = {"bin", "octal", "hex", "alpha", "unsigned", "blank", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020041static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +020042#ifdef FEAT_CLIPBOARD
43// Note: Keep this in sync with did_set_clipboard()
44static char *(p_cb_values[]) = {"unnamed", "unnamedplus", "autoselect", "autoselectplus", "autoselectml", "html", "exclude:", NULL};
45#endif
Bram Moolenaardac13472019-09-16 21:06:21 +020046#ifdef FEAT_CRYPT
Christian Brabandtf573c6e2021-06-20 14:02:16 +020047static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2",
48 # ifdef FEAT_SODIUM
Christian Brabandtaae58342023-04-23 17:50:22 +010049 "xchacha20", "xchacha20v2",
Christian Brabandtf573c6e2021-06-20 14:02:16 +020050 # endif
51 NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020052#endif
53static char *(p_cmp_values[]) = {"internal", "keepascii", NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +020054#ifdef FEAT_SYN_HL
55// Note: Keep this in sync with fill_culopt_flags()
56static char *(p_culopt_values[]) = {"line", "screenline", "number", "both", NULL};
57#endif
Bram Moolenaardac13472019-09-16 21:06:21 +020058static char *(p_dy_values[]) = {"lastline", "truncate", "uhex", NULL};
Yegappan Lakshmanan87018252023-09-20 20:20:04 +020059static char *(p_jop_values[]) = {"stack", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020060#ifdef FEAT_FOLDING
61static char *(p_fdo_values[]) = {"all", "block", "hor", "mark", "percent",
62 "quickfix", "search", "tag", "insert",
63 "undo", "jump", NULL};
64#endif
Yee Cheng Chin900894b2023-09-29 20:42:32 +020065// Note: Keep this in sync with match_keyprotocol()
66static char *(p_kpc_protocol_values[]) = {"none", "mok2", "kitty", NULL};
67#ifdef FEAT_PROP_POPUP
68// Note: Keep this in sync with parse_popup_option()
69static char *(p_popup_option_values[]) = {"height:", "width:", "highlight:", "border:", "align:", NULL};
70static char *(p_popup_option_border_values[]) = {"on", "off", NULL};
71static char *(p_popup_option_align_values[]) = {"item", "menu", NULL};
72#endif
73#if defined(FEAT_SPELL)
74// Note: Keep this in sync with spell_check_sps()
75static char *(p_sps_values[]) = {"best", "fast", "double", "expr:", "file:", "timeout:", NULL};
76#endif
Bram Moolenaardac13472019-09-16 21:06:21 +020077#ifdef FEAT_SESSION
Bram Moolenaar635bd602021-04-16 19:58:22 +020078// Also used for 'viewoptions'! Keep in sync with SSOP_ flags.
Bram Moolenaardac13472019-09-16 21:06:21 +020079static char *(p_ssop_values[]) = {"buffers", "winpos", "resize", "winsize",
80 "localoptions", "options", "help", "blank", "globals", "slash", "unix",
Bram Moolenaar635bd602021-04-16 19:58:22 +020081 "sesdir", "curdir", "folds", "cursor", "tabpages", "terminal", "skiprtp",
82 NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020083#endif
Bram Moolenaar539aa6b2019-11-17 18:09:38 +010084// Keep in sync with SWB_ flags in option.h
85static char *(p_swb_values[]) = {"useopen", "usetab", "split", "newtab", "vsplit", "uselast", NULL};
Luuk van Baal13ece2a2022-10-03 15:28:08 +010086static char *(p_spk_values[]) = {"cursor", "screen", "topline", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020087static char *(p_tc_values[]) = {"followic", "ignore", "match", "followscs", "smart", NULL};
LemonBoy5247b0b2024-07-12 19:30:58 +020088// Keep in sync with TCL_ flags in option.h
89static char *(p_tcl_values[]) = {"left", "uselast", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +020090#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
91static char *(p_toolbar_values[]) = {"text", "icons", "tooltips", "horiz", NULL};
92#endif
93#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
94static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "giant", NULL};
95#endif
Bram Moolenaara1cb1d12019-10-17 23:00:07 +020096#if defined(UNIX) || defined(VMS)
Bram Moolenaardac13472019-09-16 21:06:21 +020097static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", "jsbterm", "pterm", "urxvt", "sgr", NULL};
98#endif
Gary Johnson53ba05b2021-07-26 22:19:10 +020099static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", "none", "NONE", NULL};
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200100// Note: Keep this in sync with check_opt_wim()
Girish Palya2bacc3e2025-03-02 22:55:57 +0100101static char *(p_wim_values[]) = {"full", "longest", "list", "lastused", "noselect", NULL};
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +0000102static char *(p_wop_values[]) = {"fuzzy", "tagfile", "pum", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +0200103#ifdef FEAT_WAK
104static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
105#endif
106static char *(p_mousem_values[]) = {"extend", "popup", "popup_setpos", "mac", NULL};
107static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
108static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
109static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
110#ifdef FEAT_BROWSE
111static char *(p_bsdir_values[]) = {"current", "last", "buffer", NULL};
112#endif
113static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
114static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
115static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
116static char *(p_buftype_values[]) = {"nofile", "nowrite", "quickfix", "help", "terminal", "acwrite", "prompt", "popup", NULL};
117static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
Bram Moolenaaraa0489e2020-04-17 19:41:21 +0200118static char *(p_bs_values[]) = {"indent", "eol", "start", "nostop", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +0200119#ifdef FEAT_FOLDING
120static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
121# ifdef FEAT_DIFF
122 "diff",
123# endif
124 NULL};
125static char *(p_fcl_values[]) = {"all", NULL};
126#endif
glepnirf31cfa22025-03-06 21:59:13 +0100127static char *(p_cfc_values[]) = {"keyword", "files", "whole_line", NULL};
Girish Palyab1565882025-04-15 20:16:00 +0200128static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview", "popup", "popuphidden", "noinsert", "noselect", "fuzzy", "nosort", "preinsert", "nearest", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +0200129#ifdef BACKSLASH_IN_FILENAME
130static char *(p_csl_values[]) = {"slash", "backslash", NULL};
131#endif
132#ifdef FEAT_SIGNS
133static char *(p_scl_values[]) = {"yes", "no", "auto", "number", NULL};
134#endif
135#if defined(MSWIN) && defined(FEAT_TERMINAL)
136static char *(p_twt_values[]) = {"winpty", "conpty", "", NULL};
137#endif
Luuk van Baalba936f62022-12-15 13:15:39 +0000138static char *(p_sloc_values[]) = {"last", "statusline", "tabline", NULL};
Yegappan Lakshmanan5da901b2023-02-27 12:47:47 +0000139static char *(p_sws_values[]) = {"fsync", "sync", NULL};
Bram Moolenaardac13472019-09-16 21:06:21 +0200140
141static int check_opt_strings(char_u *val, char **values, int list);
142static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, int list);
143
144/*
145 * After setting various option values: recompute variables that depend on
146 * option values.
147 */
148 void
149didset_string_options(void)
150{
151 (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
152 (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, TRUE);
153 (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, TRUE);
glepnirf31cfa22025-03-06 21:59:13 +0100154 (void)opt_strings_flags(p_cfc, p_cfc_values, &cfc_flags, TRUE);
zeertzjq529b9ad2024-06-05 20:27:06 +0200155 (void)opt_strings_flags(p_cot, p_cot_values, &cot_flags, TRUE);
Bram Moolenaardac13472019-09-16 21:06:21 +0200156#ifdef FEAT_SESSION
157 (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE);
158 (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
159#endif
160#ifdef FEAT_FOLDING
161 (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
162#endif
163 (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE);
Yegappan Lakshmanan87018252023-09-20 20:20:04 +0200164 (void)opt_strings_flags(p_jop, p_jop_values, &jop_flags, TRUE);
Bram Moolenaardac13472019-09-16 21:06:21 +0200165 (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, FALSE);
166 (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE);
Bram Moolenaara1cb1d12019-10-17 23:00:07 +0200167#if defined(UNIX) || defined(VMS)
Bram Moolenaardac13472019-09-16 21:06:21 +0200168 (void)opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE);
169#endif
170#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
171 (void)opt_strings_flags(p_toolbar, p_toolbar_values, &toolbar_flags, TRUE);
172#endif
173#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
174 (void)opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE);
175#endif
Sean Dewar39c46b42022-05-12 17:44:29 +0100176 (void)opt_strings_flags(p_swb, p_swb_values, &swb_flags, TRUE);
LemonBoy5247b0b2024-07-12 19:30:58 +0200177 (void)opt_strings_flags(p_tcl, p_tcl_values, &tcl_flags, TRUE);
Bram Moolenaardac13472019-09-16 21:06:21 +0200178}
179
Yegappan Lakshmananf9dc2782023-05-11 15:02:56 +0100180#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaardac13472019-09-16 21:06:21 +0200181/*
182 * Trigger the OptionSet autocommand.
183 * "opt_idx" is the index of the option being set.
184 * "opt_flags" can be OPT_LOCAL etc.
185 * "oldval" the old value
186 * "oldval_l" the old local value (only non-NULL if global and local value
187 * are set)
188 * "oldval_g" the old global value (only non-NULL if global and local value
189 * are set)
190 * "newval" the new value
191 */
192 void
zeertzjq269aa2b2022-11-28 11:36:50 +0000193trigger_optionset_string(
Bram Moolenaardac13472019-09-16 21:06:21 +0200194 int opt_idx,
195 int opt_flags,
196 char_u *oldval,
197 char_u *oldval_l,
198 char_u *oldval_g,
199 char_u *newval)
200{
201 // Don't do this recursively.
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000202 if (oldval == NULL || newval == NULL
203 || *get_vim_var_str(VV_OPTION_TYPE) != NUL)
204 return;
Bram Moolenaardac13472019-09-16 21:06:21 +0200205
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000206 char_u buf_type[7];
207
208 sprintf((char *)buf_type, "%s",
Bram Moolenaardac13472019-09-16 21:06:21 +0200209 (opt_flags & OPT_LOCAL) ? "local" : "global");
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000210 set_vim_var_string(VV_OPTION_OLD, oldval, -1);
211 set_vim_var_string(VV_OPTION_NEW, newval, -1);
212 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
213 if (opt_flags & OPT_LOCAL)
214 {
215 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1);
216 set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
Bram Moolenaardac13472019-09-16 21:06:21 +0200217 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000218 if (opt_flags & OPT_GLOBAL)
219 {
220 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1);
221 set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1);
222 }
223 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
224 {
225 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1);
226 set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1);
227 set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1);
228 }
229 if (opt_flags & OPT_MODELINE)
230 {
231 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1);
232 set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
233 }
234 apply_autocmds(EVENT_OPTIONSET,
235 get_option_fullname(opt_idx), NULL, FALSE,
236 NULL);
237 reset_v_option_vars();
Bram Moolenaardac13472019-09-16 21:06:21 +0200238}
239#endif
240
241 static char *
Mike Williams620f0112023-12-05 15:36:06 +0100242illegal_char(char *errbuf, size_t errbuflen, int c)
Bram Moolenaardac13472019-09-16 21:06:21 +0200243{
244 if (errbuf == NULL)
245 return "";
zeertzjq6a8d2e12024-01-17 20:54:49 +0100246 vim_snprintf(errbuf, errbuflen, _(e_illegal_character_str),
Christian Brabandtb39b2402023-11-29 11:34:05 +0100247 (char *)transchar(c));
Bram Moolenaardac13472019-09-16 21:06:21 +0200248 return errbuf;
249}
250
251/*
252 * Check string options in a buffer for NULL value.
253 */
254 void
255check_buf_options(buf_T *buf)
256{
257 check_string_option(&buf->b_p_bh);
258 check_string_option(&buf->b_p_bt);
259 check_string_option(&buf->b_p_fenc);
260 check_string_option(&buf->b_p_ff);
261#ifdef FEAT_FIND_ID
262 check_string_option(&buf->b_p_def);
263 check_string_option(&buf->b_p_inc);
264# ifdef FEAT_EVAL
265 check_string_option(&buf->b_p_inex);
266# endif
267#endif
Bram Moolenaar8e145b82022-05-21 20:17:31 +0100268#if defined(FEAT_EVAL)
Bram Moolenaardac13472019-09-16 21:06:21 +0200269 check_string_option(&buf->b_p_inde);
270 check_string_option(&buf->b_p_indk);
271#endif
272#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
273 check_string_option(&buf->b_p_bexpr);
274#endif
275#if defined(FEAT_CRYPT)
276 check_string_option(&buf->b_p_cm);
277#endif
278 check_string_option(&buf->b_p_fp);
279#if defined(FEAT_EVAL)
280 check_string_option(&buf->b_p_fex);
281#endif
282#ifdef FEAT_CRYPT
283 check_string_option(&buf->b_p_key);
284#endif
285 check_string_option(&buf->b_p_kp);
286 check_string_option(&buf->b_p_mps);
287 check_string_option(&buf->b_p_fo);
288 check_string_option(&buf->b_p_flp);
289 check_string_option(&buf->b_p_isk);
Bram Moolenaardac13472019-09-16 21:06:21 +0200290 check_string_option(&buf->b_p_com);
Bram Moolenaardac13472019-09-16 21:06:21 +0200291#ifdef FEAT_FOLDING
292 check_string_option(&buf->b_p_cms);
293#endif
294 check_string_option(&buf->b_p_nf);
Bram Moolenaardac13472019-09-16 21:06:21 +0200295 check_string_option(&buf->b_p_qe);
Bram Moolenaardac13472019-09-16 21:06:21 +0200296#ifdef FEAT_SYN_HL
297 check_string_option(&buf->b_p_syn);
298 check_string_option(&buf->b_s.b_syn_isk);
299#endif
300#ifdef FEAT_SPELL
301 check_string_option(&buf->b_s.b_p_spc);
302 check_string_option(&buf->b_s.b_p_spf);
303 check_string_option(&buf->b_s.b_p_spl);
Bram Moolenaar362b44b2020-06-10 21:47:00 +0200304 check_string_option(&buf->b_s.b_p_spo);
Bram Moolenaardac13472019-09-16 21:06:21 +0200305#endif
Bram Moolenaardac13472019-09-16 21:06:21 +0200306 check_string_option(&buf->b_p_sua);
Bram Moolenaardac13472019-09-16 21:06:21 +0200307 check_string_option(&buf->b_p_cink);
308 check_string_option(&buf->b_p_cino);
Tom Praschan3506cf32022-04-07 12:39:08 +0100309 check_string_option(&buf->b_p_cinsd);
Bram Moolenaardac13472019-09-16 21:06:21 +0200310 parse_cino(buf);
Bram Moolenaar49846fb2022-10-15 16:05:33 +0100311 check_string_option(&buf->b_p_lop);
Bram Moolenaardac13472019-09-16 21:06:21 +0200312 check_string_option(&buf->b_p_ft);
Bram Moolenaardac13472019-09-16 21:06:21 +0200313 check_string_option(&buf->b_p_cinw);
zeertzjq529b9ad2024-06-05 20:27:06 +0200314 check_string_option(&buf->b_p_cot);
Bram Moolenaardac13472019-09-16 21:06:21 +0200315 check_string_option(&buf->b_p_cpt);
glepnirbcd59952025-04-24 21:48:35 +0200316 check_string_option(&buf->b_p_ise);
Bram Moolenaardac13472019-09-16 21:06:21 +0200317#ifdef FEAT_COMPL_FUNC
318 check_string_option(&buf->b_p_cfu);
319 check_string_option(&buf->b_p_ofu);
Bram Moolenaard4c4bfa2021-10-16 21:14:11 +0100320 check_string_option(&buf->b_p_tsrfu);
Bram Moolenaardac13472019-09-16 21:06:21 +0200321#endif
322#ifdef FEAT_EVAL
Yegappan Lakshmanana13f3a42024-11-02 18:40:10 +0100323 check_string_option(&buf->b_p_ffu);
Bram Moolenaardac13472019-09-16 21:06:21 +0200324 check_string_option(&buf->b_p_tfu);
325#endif
326#ifdef FEAT_KEYMAP
327 check_string_option(&buf->b_p_keymap);
328#endif
329#ifdef FEAT_QUICKFIX
glepnir7b9eb632025-05-16 19:49:23 +0200330 check_string_option(&buf->b_p_gefm);
Bram Moolenaardac13472019-09-16 21:06:21 +0200331 check_string_option(&buf->b_p_gp);
332 check_string_option(&buf->b_p_mp);
333 check_string_option(&buf->b_p_efm);
334#endif
335 check_string_option(&buf->b_p_ep);
336 check_string_option(&buf->b_p_path);
337 check_string_option(&buf->b_p_tags);
338 check_string_option(&buf->b_p_tc);
339 check_string_option(&buf->b_p_dict);
340 check_string_option(&buf->b_p_tsr);
Bram Moolenaardac13472019-09-16 21:06:21 +0200341 check_string_option(&buf->b_p_lw);
Bram Moolenaardac13472019-09-16 21:06:21 +0200342 check_string_option(&buf->b_p_bkc);
343 check_string_option(&buf->b_p_menc);
344#ifdef FEAT_VARTABS
345 check_string_option(&buf->b_p_vsts);
346 check_string_option(&buf->b_p_vts);
347#endif
348}
349
350/*
351 * Free the string allocated for an option.
352 * Checks for the string being empty_option. This may happen if we're out of
353 * memory, vim_strsave() returned NULL, which was replaced by empty_option by
354 * check_options().
355 * Does NOT check for P_ALLOCED flag!
356 */
357 void
358free_string_option(char_u *p)
359{
360 if (p != empty_option)
361 vim_free(p);
362}
363
364 void
365clear_string_option(char_u **pp)
366{
367 if (*pp != empty_option)
368 vim_free(*pp);
369 *pp = empty_option;
370}
371
372 void
373check_string_option(char_u **pp)
374{
375 if (*pp == NULL)
376 *pp = empty_option;
377}
378
379/*
380 * Set global value for string option when it's a local option.
381 */
382 static void
383set_string_option_global(
384 int opt_idx, // option index
385 char_u **varp) // pointer to option variable
386{
387 char_u **p, *s;
388
389 // the global value is always allocated
390 if (is_window_local_option(opt_idx))
391 p = (char_u **)GLOBAL_WO(varp);
392 else
393 p = (char_u **)get_option_var(opt_idx);
394 if (!is_global_option(opt_idx)
395 && p != varp
396 && (s = vim_strsave(*varp)) != NULL)
397 {
398 free_string_option(*p);
399 *p = s;
400 }
401}
402
403/*
404 * Set a string option to a new value (without checking the effect).
405 * The string is copied into allocated memory.
406 * if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
407 * When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
408 * "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
409 * "set_sid".
410 */
411 void
412set_string_option_direct(
413 char_u *name,
414 int opt_idx,
415 char_u *val,
416 int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
417 int set_sid UNUSED)
418{
419 char_u *s;
420 char_u **varp;
421 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
422 int idx = opt_idx;
423
424 if (idx == -1) // use name
425 {
426 idx = findoption(name);
427 if (idx < 0) // not found (should not happen)
428 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000429 semsg(_(e_internal_error_str), "set_string_option_direct()");
RestorerZ68ebcee2023-05-31 17:12:14 +0100430 siemsg("For option %s", name);
Bram Moolenaardac13472019-09-16 21:06:21 +0200431 return;
432 }
433 }
434
435 if (is_hidden_option(idx)) // can't set hidden option
436 return;
437
438 s = vim_strsave(val);
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000439 if (s == NULL)
440 return;
441
442 varp = (char_u **)get_option_varp_scope(idx,
443 both ? OPT_LOCAL : opt_flags);
444 if ((opt_flags & OPT_FREE) && (get_option_flags(idx) & P_ALLOCED))
445 free_string_option(*varp);
446 *varp = s;
447
448 // For buffer/window local option may also set the global value.
449 if (both)
450 set_string_option_global(idx, varp);
451
452 set_option_flag(idx, P_ALLOCED);
453
454 // When setting both values of a global option with a local value,
455 // make the local value empty, so that the global value is used.
456 if (is_global_local_option(idx) && both)
Bram Moolenaardac13472019-09-16 21:06:21 +0200457 {
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000458 free_string_option(*varp);
459 *varp = empty_option;
Bram Moolenaardac13472019-09-16 21:06:21 +0200460 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000461# ifdef FEAT_EVAL
462 if (set_sid != SID_NONE)
463 {
464 sctx_T script_ctx;
465
466 if (set_sid == 0)
467 script_ctx = current_sctx;
468 else
469 {
470 script_ctx.sc_sid = set_sid;
471 script_ctx.sc_seq = 0;
472 script_ctx.sc_lnum = 0;
473 script_ctx.sc_version = 1;
474 }
475 set_option_sctx_idx(idx, opt_flags, script_ctx);
476 }
477# endif
Bram Moolenaardac13472019-09-16 21:06:21 +0200478}
479
Dominique Pellee764d1b2023-03-12 21:20:59 +0000480#if defined(FEAT_PROP_POPUP) || \
481 (defined(FEAT_DIFF) && defined(FEAT_FOLDING)) || defined(PROTO)
Bram Moolenaardac13472019-09-16 21:06:21 +0200482/*
483 * Like set_string_option_direct(), but for a window-local option in "wp".
484 * Blocks autocommands to avoid the old curwin becoming invalid.
485 */
486 void
487set_string_option_direct_in_win(
488 win_T *wp,
489 char_u *name,
490 int opt_idx,
491 char_u *val,
492 int opt_flags,
493 int set_sid)
494{
495 win_T *save_curwin = curwin;
496
497 block_autocmds();
498 curwin = wp;
499 curbuf = curwin->w_buffer;
500 set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
501 curwin = save_curwin;
502 curbuf = curwin->w_buffer;
503 unblock_autocmds();
504}
Dominique Pellee764d1b2023-03-12 21:20:59 +0000505#endif
Bram Moolenaardac13472019-09-16 21:06:21 +0200506
Dominique Pelle748b3082022-01-08 12:41:16 +0000507#if defined(FEAT_PROP_POPUP) || defined(PROTO)
Bram Moolenaardac13472019-09-16 21:06:21 +0200508/*
509 * Like set_string_option_direct(), but for a buffer-local option in "buf".
510 * Blocks autocommands to avoid the old curbuf becoming invalid.
511 */
512 void
513set_string_option_direct_in_buf(
514 buf_T *buf,
515 char_u *name,
516 int opt_idx,
517 char_u *val,
518 int opt_flags,
519 int set_sid)
520{
521 buf_T *save_curbuf = curbuf;
522
523 block_autocmds();
524 curbuf = buf;
525 curwin->w_buffer = curbuf;
526 set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
527 curbuf = save_curbuf;
528 curwin->w_buffer = curbuf;
529 unblock_autocmds();
530}
Dominique Pelle748b3082022-01-08 12:41:16 +0000531#endif
Bram Moolenaardac13472019-09-16 21:06:21 +0200532
533/*
534 * Set a string option to a new value, and handle the effects.
535 *
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100536 * Returns NULL on success or an untranslated error message on error.
Bram Moolenaardac13472019-09-16 21:06:21 +0200537 */
538 char *
539set_string_option(
540 int opt_idx,
541 char_u *value,
Yegappan Lakshmanan32ff96e2023-02-13 16:10:04 +0000542 int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL
Christian Brabandtb39b2402023-11-29 11:34:05 +0100543 char *errbuf,
Mike Williams620f0112023-12-05 15:36:06 +0100544 size_t errbuflen)
Bram Moolenaardac13472019-09-16 21:06:21 +0200545{
546 char_u *s;
547 char_u **varp;
548 char_u *oldval;
549#if defined(FEAT_EVAL)
550 char_u *oldval_l = NULL;
551 char_u *oldval_g = NULL;
552 char_u *saved_oldval = NULL;
553 char_u *saved_oldval_l = NULL;
554 char_u *saved_oldval_g = NULL;
555 char_u *saved_newval = NULL;
556#endif
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100557 char *errmsg = NULL;
Bram Moolenaardac13472019-09-16 21:06:21 +0200558 int value_checked = FALSE;
559
560 if (is_hidden_option(opt_idx)) // don't set hidden option
561 return NULL;
562
Bram Moolenaar7f009df2020-03-16 20:27:38 +0100563 s = vim_strsave(value == NULL ? (char_u *)"" : value);
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000564 if (s == NULL)
565 return NULL;
566
567 varp = (char_u **)get_option_varp_scope(opt_idx,
568 (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
569 ? (is_global_local_option(opt_idx)
570 ? OPT_GLOBAL : OPT_LOCAL)
571 : opt_flags);
572 oldval = *varp;
573#if defined(FEAT_EVAL)
574 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
Bram Moolenaardac13472019-09-16 21:06:21 +0200575 {
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000576 oldval_l = *(char_u **)get_option_varp_scope(opt_idx, OPT_LOCAL);
577 oldval_g = *(char_u **)get_option_varp_scope(opt_idx, OPT_GLOBAL);
Bram Moolenaardac13472019-09-16 21:06:21 +0200578 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000579#endif
580 *varp = s;
581
582#if defined(FEAT_EVAL)
583 if (!starting
584# ifdef FEAT_CRYPT
585 && !is_crypt_key_option(opt_idx)
586# endif
587 )
588 {
589 if (oldval_l != NULL)
590 saved_oldval_l = vim_strsave(oldval_l);
591 if (oldval_g != NULL)
592 saved_oldval_g = vim_strsave(oldval_g);
593 saved_oldval = vim_strsave(oldval);
594 saved_newval = vim_strsave(s);
595 }
596#endif
Yegappan Lakshmananaf936912023-02-20 12:16:39 +0000597 if ((errmsg = did_set_string_option(opt_idx, varp, oldval, value, errbuf,
Christian Brabandtb39b2402023-11-29 11:34:05 +0100598 errbuflen, opt_flags, OP_NONE, &value_checked)) == NULL)
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000599 did_set_option(opt_idx, opt_flags, TRUE, value_checked);
600
601#if defined(FEAT_EVAL)
602 // call autocommand after handling side effects
603 if (errmsg == NULL)
604 trigger_optionset_string(opt_idx, opt_flags,
605 saved_oldval, saved_oldval_l,
606 saved_oldval_g, saved_newval);
607 vim_free(saved_oldval);
608 vim_free(saved_oldval_l);
609 vim_free(saved_oldval_g);
610 vim_free(saved_newval);
611#endif
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100612 return errmsg;
Bram Moolenaardac13472019-09-16 21:06:21 +0200613}
614
615/*
616 * Return TRUE if "val" is a valid 'filetype' name.
617 * Also used for 'syntax' and 'keymap'.
618 */
619 static int
620valid_filetype(char_u *val)
621{
622 return valid_name(val, ".-_");
623}
624
625#ifdef FEAT_STL_OPT
626/*
627 * Check validity of options with the 'statusline' format.
zeertzjq5dc294a2022-04-15 13:17:57 +0100628 * Return an untranslated error message or NULL.
Bram Moolenaardac13472019-09-16 21:06:21 +0200629 */
630 static char *
631check_stl_option(char_u *s)
632{
Bram Moolenaardac13472019-09-16 21:06:21 +0200633 int groupdepth = 0;
Christian Brabandtb39b2402023-11-29 11:34:05 +0100634 static char errbuf[ERR_BUFLEN];
635 int errbuflen = ERR_BUFLEN;
Bram Moolenaardac13472019-09-16 21:06:21 +0200636
Bram Moolenaar8133cc62020-10-26 21:05:27 +0100637 while (*s)
Bram Moolenaardac13472019-09-16 21:06:21 +0200638 {
639 // Check for valid keys after % sequences
640 while (*s && *s != '%')
641 s++;
642 if (!*s)
643 break;
644 s++;
Yegappan Lakshmanan3ec78f92023-02-11 11:15:25 +0000645 if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE)
Bram Moolenaardac13472019-09-16 21:06:21 +0200646 {
647 s++;
648 continue;
649 }
650 if (*s == ')')
651 {
652 s++;
653 if (--groupdepth < 0)
654 break;
655 continue;
656 }
657 if (*s == '-')
658 s++;
659 while (VIM_ISDIGIT(*s))
660 s++;
661 if (*s == STL_USER_HL)
662 continue;
663 if (*s == '.')
664 {
665 s++;
666 while (*s && VIM_ISDIGIT(*s))
667 s++;
668 }
669 if (*s == '(')
670 {
671 groupdepth++;
672 continue;
673 }
674 if (vim_strchr(STL_ALL, *s) == NULL)
675 {
Christian Brabandtb39b2402023-11-29 11:34:05 +0100676 return illegal_char(errbuf, errbuflen, *s);
Bram Moolenaardac13472019-09-16 21:06:21 +0200677 }
678 if (*s == '{')
679 {
zeertzjq5dc294a2022-04-15 13:17:57 +0100680 int reevaluate = (*++s == '%');
shadmansaleh30e3de22021-05-15 17:23:28 +0200681
zeertzjq5dc294a2022-04-15 13:17:57 +0100682 if (reevaluate && *++s == '}')
683 // "}" is not allowed immediately after "%{%"
Christian Brabandtb39b2402023-11-29 11:34:05 +0100684 return illegal_char(errbuf, errbuflen, '}');
shadmansaleh30e3de22021-05-15 17:23:28 +0200685 while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s)
Bram Moolenaardac13472019-09-16 21:06:21 +0200686 s++;
687 if (*s != '}')
zeertzjq5dc294a2022-04-15 13:17:57 +0100688 return e_unclosed_expression_sequence;
Bram Moolenaardac13472019-09-16 21:06:21 +0200689 }
690 }
Bram Moolenaardac13472019-09-16 21:06:21 +0200691 if (groupdepth != 0)
zeertzjq5dc294a2022-04-15 13:17:57 +0100692 return e_unbalanced_groups;
Bram Moolenaardac13472019-09-16 21:06:21 +0200693 return NULL;
694}
695#endif
696
697/*
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +0000698 * Check for a "normal" directory or file name in some options. Disallow a
699 * path separator (slash and/or backslash), wildcards and characters that are
700 * often illegal in a file name. Be more permissive if "secure" is off.
701 */
702 static int
703check_illegal_path_names(int opt_idx, char_u **varp)
704{
705 return (((get_option_flags(opt_idx) & P_NFNAME)
706 && vim_strpbrk(*varp, (char_u *)(secure
707 ? "/\\*?[|;&<>\r\n" : "/\\*?[<>\r\n")) != NULL)
708 || ((get_option_flags(opt_idx) & P_NDNAME)
709 && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL));
710}
711
712/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000713 * An option that accepts a list of flags is changed.
714 * e.g. 'viewoptions', 'switchbuf', 'casemap', etc.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +0000715 */
716 static char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000717did_set_opt_flags(char_u *val, char **values, unsigned *flagp, int list)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +0000718{
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000719 if (opt_strings_flags(val, values, flagp, list) == FAIL)
720 return e_invalid_argument;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +0000721
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000722 return NULL;
723}
724
725/*
726 * An option that accepts a list of string values is changed.
727 * e.g. 'nrformats', 'scrollopt', 'wildoptions', etc.
728 */
729 static char *
730did_set_opt_strings(char_u *val, char **values, int list)
731{
732 return did_set_opt_flags(val, values, NULL, list);
733}
734
735/*
736 * An option which is a list of flags is set. Valid values are in 'flags'.
737 */
738 static char *
Christian Brabandtb39b2402023-11-29 11:34:05 +0100739did_set_option_listflag(
740 char_u *val,
741 char_u *flags,
742 char *errbuf,
Mike Williams620f0112023-12-05 15:36:06 +0100743 size_t errbuflen)
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000744{
745 char_u *s;
746
Yegappan Lakshmananc727b192023-03-03 12:26:15 +0000747 for (s = val; *s; ++s)
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000748 if (vim_strchr(flags, *s) == NULL)
Christian Brabandtb39b2402023-11-29 11:34:05 +0100749 return illegal_char(errbuf, errbuflen, *s);
Yegappan Lakshmananad608982023-03-01 12:44:06 +0000750
751 return NULL;
752}
753
754/*
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200755 * Expand an option that accepts a list of fixed string values with known
756 * number of items.
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200757 */
Yee Cheng Chinf7f746b2023-09-30 12:28:50 +0200758 static int
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200759expand_set_opt_string(
760 optexpand_T *args,
761 char **values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +0200762 size_t numValues,
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200763 int *numMatches,
764 char_u ***matches)
765{
766 char_u *p;
767 regmatch_T *regmatch = args->oe_regmatch;
768 int include_orig_val = args->oe_include_orig_val;
769 char_u *option_val = args->oe_opt_value;
770
771 // Assume numValues is small since they are fixed enums, so just allocate
772 // upfront instead of needing two passes to calculate output size.
773 *matches = ALLOC_MULT(char_u *, numValues + 1);
774 if (*matches == NULL)
775 return FAIL;
776
777 int count = 0;
778
779 if (include_orig_val && *option_val != NUL)
780 {
781 p = vim_strsave(option_val);
782 if (p == NULL)
783 {
784 VIM_CLEAR(*matches);
785 return FAIL;
786 }
787 (*matches)[count++] = p;
788 }
789
790 for (char **val = values; *val != NULL; val++)
791 {
792 if (include_orig_val && *option_val != NUL)
793 {
794 if (STRCMP((char_u*)*val, option_val) == 0)
795 continue;
796 }
797 if (vim_regexec(regmatch, (char_u*)(*val), (colnr_T)0))
798 {
799 p = vim_strsave((char_u*)*val);
800 if (p == NULL)
801 {
802 if (count == 0)
803 {
804 VIM_CLEAR(*matches);
805 return FAIL;
806 }
807 else
808 break;
809 }
810 (*matches)[count++] = p;
811 }
812 }
813 if (count == 0)
814 {
815 VIM_CLEAR(*matches);
816 return FAIL;
817 }
818 *numMatches = count;
819 return OK;
820}
821
822static char_u *set_opt_callback_orig_option = NULL;
823static char_u *((*set_opt_callback_func)(expand_T *, int));
824
825/*
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200826 * Callback used by expand_set_opt_generic to also include the original value
827 * as the first item.
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200828 */
829 static char_u *
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200830expand_set_opt_generic_cb(expand_T *xp, int idx)
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200831{
832 if (idx == 0)
833 {
834 if (set_opt_callback_orig_option != NULL)
835 return set_opt_callback_orig_option;
836 else
837 return (char_u *)""; // empty strings are ignored
838 }
839 return set_opt_callback_func(xp, idx - 1);
840}
841
842/*
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200843 * Expand an option with a callback that iterates through a list of possible
844 * names using an index.
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200845 */
Yee Cheng Chinf7f746b2023-09-30 12:28:50 +0200846 static int
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200847expand_set_opt_generic(
848 optexpand_T *args,
849 char_u *((*func)(expand_T *, int)),
850 int *numMatches,
851 char_u ***matches)
852{
853 int ret;
854
855 set_opt_callback_orig_option = args->oe_include_orig_val ?
856 args->oe_opt_value : NULL;
857 set_opt_callback_func = func;
858
859 ret = ExpandGeneric(
860 (char_u*)"", // not using fuzzy as currently EXPAND_STRING_SETTING doesn't use it
861 args->oe_xp,
862 args->oe_regmatch,
863 matches,
864 numMatches,
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200865 expand_set_opt_generic_cb,
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200866 FALSE);
867
868 set_opt_callback_orig_option = NULL;
869 set_opt_callback_func = NULL;
870 return ret;
871}
872
Christian Brabandt9960ebc2023-10-05 22:17:09 +0200873# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)
Yee Cheng Chin290b8872023-10-05 20:54:21 +0200874static garray_T *expand_cb_ga;
875static optexpand_T *expand_cb_args;
876
877/*
878 * Callback provided to a function in expand_set_opt_callback. Will perform
879 * regex matching against the value and add to the list.
880 *
881 * Returns OK usually. Returns FAIL if it failed to allocate memory, and the
882 * caller should terminate the enumeration.
883 */
884 static int
885expand_set_opt_callback_cb(char_u *val)
886{
887 regmatch_T *regmatch = expand_cb_args->oe_regmatch;
888 expand_T *xp = expand_cb_args->oe_xp;
889 garray_T *ga = expand_cb_ga;
890 char_u *str;
891
892 if (val == NULL || *val == NUL)
893 return OK;
894
895 if (xp->xp_pattern[0] != NUL &&
896 !vim_regexec(regmatch, val, (colnr_T)0))
897 return OK;
898
899 str = vim_strsave_escaped(val, (char_u *)" \t\\");
900
901 if (str == NULL)
902 return FAIL;
903
904 if (ga_grow(ga, 1) == FAIL)
905 {
906 vim_free(str);
907 return FAIL;
908 }
909
910 ((char_u **)ga->ga_data)[ga->ga_len] = str;
911 ++ga->ga_len;
912 return OK;
913}
914
915/*
916 * Expand an option with a provided function that takes a callback. The
917 * function will enumerate through all options and call the callback to add it
918 * to the list.
919 *
920 * "func" is the enumerator function that will generate the list of options.
921 * "func_params" is a single parameter that will be passed to func.
922 */
923 static int
924expand_set_opt_callback(
925 optexpand_T *args,
926 void (*func)(optexpand_T *, void* params, int (*cb)(char_u *val)),
927 void *func_params,
928 int *numMatches,
929 char_u ***matches)
930{
931 garray_T ga;
932 int include_orig_val = args->oe_include_orig_val;
933 char_u *option_val = args->oe_opt_value;
934
935 ga_init2(&ga, sizeof(char *), 30);
936
937 if (include_orig_val && *option_val != NUL)
938 {
939 char_u *p = vim_strsave(option_val);
940 if (p == NULL)
941 return FAIL;
942 if (ga_grow(&ga, 1) == FAIL)
943 {
944 vim_free(p);
945 return FAIL;
946 }
947 ((char_u **)ga.ga_data)[ga.ga_len] = p;
948 ++ga.ga_len;
949 }
950
951 expand_cb_ga = &ga;
952 expand_cb_args = args;
953
954 func(args, func_params, expand_set_opt_callback_cb);
955
956 expand_cb_ga = NULL;
957 expand_cb_args = NULL;
958
959 *matches = ga.ga_data;
960 *numMatches = ga.ga_len;
961 return OK;
962}
Christian Brabandt9960ebc2023-10-05 22:17:09 +0200963#endif
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200964
965/*
966 * Expand an option which is a list of flags.
967 */
Yee Cheng Chinf7f746b2023-09-30 12:28:50 +0200968 static int
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200969expand_set_opt_listflag(
970 optexpand_T *args,
971 char_u *flags,
972 int *numMatches,
973 char_u ***matches)
974{
975 char_u *p;
976 char_u *option_val = args->oe_opt_value;
977 char_u *cmdline_val = args->oe_set_arg;
978 int append = args->oe_append;
979 int include_orig_val = args->oe_include_orig_val && (*option_val != NUL);
980
Yee Cheng Chin6d113472023-10-02 21:38:39 +0200981 size_t num_flags = STRLEN(flags);
Yee Cheng Chin900894b2023-09-29 20:42:32 +0200982
983 // Assume we only have small number of flags, so just allocate max size.
984 *matches = ALLOC_MULT(char_u *, num_flags + 1);
985 if (*matches == NULL)
986 return FAIL;
987
988 int count = 0;
989
990 if (include_orig_val)
991 {
992 p = vim_strsave(option_val);
993 if (p == NULL)
994 {
995 VIM_CLEAR(*matches);
996 return FAIL;
997 }
998 (*matches)[count++] = p;
999 }
1000
1001 for (char_u *flag = flags; *flag != NUL; flag++)
1002 {
1003 if (append && vim_strchr(option_val, *flag) != NULL)
1004 continue;
1005
1006 if (vim_strchr(cmdline_val, *flag) == NULL)
1007 {
1008 if (include_orig_val
1009 && option_val[1] == NUL
1010 && *flag == option_val[0])
1011 {
1012 // This value is already used as the first choice as it's the
1013 // existing flag. Just skip it to avoid duplicate.
1014 continue;
1015 }
1016 p = vim_strnsave(flag, 1);
1017 if (p == NULL)
1018 {
1019 if (count == 0)
1020 {
1021 VIM_CLEAR(*matches);
1022 return FAIL;
1023 }
1024 else
1025 break;
1026 }
1027 (*matches)[count++] = p;
1028 }
1029 }
1030
1031 if (count == 0)
1032 {
1033 VIM_CLEAR(*matches);
1034 return FAIL;
1035 }
1036 *numMatches = count;
1037 return OK;
1038}
1039
1040/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001041 * The 'ambiwidth' option is changed.
1042 */
1043 char *
1044did_set_ambiwidth(optset_T *args UNUSED)
1045{
1046 if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK)
1047 return e_invalid_argument;
1048
1049 return check_chars_options();
1050}
1051
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001052 int
1053expand_set_ambiwidth(optexpand_T *args, int *numMatches, char_u ***matches)
1054{
1055 return expand_set_opt_string(
1056 args,
1057 p_ambw_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001058 ARRAY_LENGTH(p_ambw_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001059 numMatches,
1060 matches);
1061}
1062
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001063/*
1064 * The 'background' option is changed.
1065 */
1066 char *
Gregory Anders83ad2722024-01-03 19:48:51 +01001067did_set_background(optset_T *args)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001068{
1069 if (check_opt_strings(p_bg, p_bg_values, FALSE) == FAIL)
1070 return e_invalid_argument;
1071
Gregory Anders83ad2722024-01-03 19:48:51 +01001072 if (args->os_oldval.string != NULL && args->os_oldval.string[0] == *p_bg)
1073 // Value was not changed
1074 return NULL;
1075
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001076#ifdef FEAT_EVAL
1077 int dark = (*p_bg == 'd');
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001078#endif
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001079
1080 init_highlight(FALSE, FALSE);
1081
1082#ifdef FEAT_EVAL
1083 if (dark != (*p_bg == 'd')
1084 && get_var_value((char_u *)"g:colors_name") != NULL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001085 {
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001086 // The color scheme must have set 'background' back to another
1087 // value, that's not what we want here. Disable the color
1088 // scheme and set the colors again.
1089 do_unlet((char_u *)"g:colors_name", TRUE);
1090 free_string_option(p_bg);
1091 p_bg = vim_strsave((char_u *)(dark ? "dark" : "light"));
1092 check_string_option(&p_bg);
1093 init_highlight(FALSE, FALSE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001094 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001095#endif
1096#ifdef FEAT_TERMINAL
1097 term_update_colors_all();
1098#endif
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001099
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001100 return NULL;
1101}
1102
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001103 int
1104expand_set_background(optexpand_T *args, int *numMatches, char_u ***matches)
1105{
1106 return expand_set_opt_string(
1107 args,
1108 p_bg_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001109 ARRAY_LENGTH(p_bg_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001110 numMatches,
1111 matches);
1112}
1113
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001114/*
1115 * The 'backspace' option is changed.
1116 */
1117 char *
1118did_set_backspace(optset_T *args UNUSED)
1119{
1120 if (VIM_ISDIGIT(*p_bs))
1121 {
1122 if (*p_bs > '3' || p_bs[1] != NUL)
1123 return e_invalid_argument;
1124 }
1125 else if (check_opt_strings(p_bs, p_bs_values, TRUE) != OK)
1126 return e_invalid_argument;
1127
1128 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001129}
1130
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001131 int
1132expand_set_backspace(optexpand_T *args, int *numMatches, char_u ***matches)
1133{
1134 return expand_set_opt_string(
1135 args,
1136 p_bs_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001137 ARRAY_LENGTH(p_bs_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001138 numMatches,
1139 matches);
1140}
1141
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001142/*
1143 * The 'backupcopy' option is changed.
1144 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001145 char *
1146did_set_backupcopy(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001147{
1148 char_u *bkc = p_bkc;
1149 unsigned int *flags = &bkc_flags;
1150 char *errmsg = NULL;
1151
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001152 if (args->os_flags & OPT_LOCAL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001153 {
1154 bkc = curbuf->b_p_bkc;
1155 flags = &curbuf->b_bkc_flags;
1156 }
zeertzjq46dcd842024-11-03 09:10:50 +01001157 else if (!(args->os_flags & OPT_GLOBAL))
1158 // When using :set, clear the local flags.
1159 curbuf->b_bkc_flags = 0;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001160
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001161 if ((args->os_flags & OPT_LOCAL) && *bkc == NUL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001162 // make the local value empty: use the global value
1163 *flags = 0;
1164 else
1165 {
1166 if (opt_strings_flags(bkc, p_bkc_values, flags, TRUE) != OK)
1167 errmsg = e_invalid_argument;
1168 if ((((int)*flags & BKC_AUTO) != 0)
1169 + (((int)*flags & BKC_YES) != 0)
1170 + (((int)*flags & BKC_NO) != 0) != 1)
1171 {
1172 // Must have exactly one of "auto", "yes" and "no".
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001173 (void)opt_strings_flags(args->os_oldval.string, p_bkc_values,
1174 flags, TRUE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001175 errmsg = e_invalid_argument;
1176 }
1177 }
1178
1179 return errmsg;
1180}
1181
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001182 int
1183expand_set_backupcopy(optexpand_T *args, int *numMatches, char_u ***matches)
1184{
1185 return expand_set_opt_string(
1186 args,
1187 p_bkc_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001188 ARRAY_LENGTH(p_bkc_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001189 numMatches,
1190 matches);
1191}
1192
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001193/*
1194 * The 'backupext' or the 'patchmode' option is changed.
1195 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001196 char *
1197did_set_backupext_or_patchmode(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001198{
1199 if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
1200 *p_pm == '.' ? p_pm + 1 : p_pm) == 0)
1201 return e_backupext_and_patchmode_are_equal;
1202
1203 return NULL;
1204}
1205
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001206/*
1207 * The 'belloff' option is changed.
1208 */
1209 char *
1210did_set_belloff(optset_T *args UNUSED)
1211{
1212 return did_set_opt_flags(p_bo, p_bo_values, &bo_flags, TRUE);
1213}
1214
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001215 int
1216expand_set_belloff(optexpand_T *args, int *numMatches, char_u ***matches)
1217{
1218 return expand_set_opt_string(
1219 args,
1220 p_bo_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001221 ARRAY_LENGTH(p_bo_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001222 numMatches,
1223 matches);
1224}
1225
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001226#if defined(FEAT_LINEBREAK) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001227/*
zeertzjqeac3fdc2024-02-03 18:08:09 +01001228 * The 'breakat' option is changed.
1229 */
1230 char *
1231did_set_breakat(optset_T *args UNUSED)
1232{
1233 char_u *p;
1234 int i;
1235
1236 for (i = 0; i < 256; i++)
1237 breakat_flags[i] = FALSE;
1238
1239 if (p_breakat != NULL)
1240 for (p = p_breakat; *p; p++)
1241 breakat_flags[*p] = TRUE;
1242
1243 return NULL;
1244}
1245
1246/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001247 * The 'breakindentopt' option is changed.
1248 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001249 char *
Millyb38700a2024-10-22 22:59:39 +02001250did_set_breakindentopt(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001251{
Millyb38700a2024-10-22 22:59:39 +02001252 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001253
Millyb38700a2024-10-22 22:59:39 +02001254 if (briopt_check(*varp, varp == &curwin->w_p_briopt ? curwin : NULL)
1255 == FAIL)
1256 return e_invalid_argument;
1257
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001258 // list setting requires a redraw
Millyb38700a2024-10-22 22:59:39 +02001259 if (varp == &curwin->w_p_briopt && curwin->w_briopt_list)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001260 redraw_all_later(UPD_NOT_VALID);
1261
Millyb38700a2024-10-22 22:59:39 +02001262 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001263}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001264
1265 int
1266expand_set_breakindentopt(optexpand_T *args, int *numMatches, char_u ***matches)
1267{
1268 return expand_set_opt_string(
1269 args,
1270 p_briopt_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001271 ARRAY_LENGTH(p_briopt_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001272 numMatches,
1273 matches);
1274}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001275#endif
1276
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001277#if defined(FEAT_BROWSE) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001278/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001279 * The 'browsedir' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001280 */
Yegappan Lakshmanan5da901b2023-02-27 12:47:47 +00001281 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001282did_set_browsedir(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001283{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001284 if (check_opt_strings(p_bsdir, p_bsdir_values, FALSE) != OK
1285 && !mch_isdir(p_bsdir))
1286 return e_invalid_argument;
1287
1288 return NULL;
1289}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001290
1291 int
1292expand_set_browsedir(optexpand_T *args, int *numMatches, char_u ***matches)
1293{
1294 return expand_set_opt_string(
1295 args,
1296 p_bsdir_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001297 ARRAY_LENGTH(p_bsdir_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001298 numMatches,
1299 matches);
1300}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001301#endif
1302
1303/*
1304 * The 'bufhidden' option is changed.
1305 */
1306 char *
1307did_set_bufhidden(optset_T *args UNUSED)
1308{
1309 return did_set_opt_strings(curbuf->b_p_bh, p_bufhidden_values, FALSE);
1310}
1311
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001312 int
1313expand_set_bufhidden(optexpand_T *args, int *numMatches, char_u ***matches)
1314{
1315 return expand_set_opt_string(
1316 args,
1317 p_bufhidden_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001318 ARRAY_LENGTH(p_bufhidden_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001319 numMatches,
1320 matches);
1321}
1322
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001323/*
1324 * The 'buftype' option is changed.
1325 */
1326 char *
1327did_set_buftype(optset_T *args UNUSED)
1328{
1329 if (check_opt_strings(curbuf->b_p_bt, p_buftype_values, FALSE) != OK)
1330 return e_invalid_argument;
1331
1332 if (curwin->w_status_height)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001333 {
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001334 curwin->w_redr_status = TRUE;
1335 redraw_later(UPD_VALID);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001336 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001337 curbuf->b_help = (curbuf->b_p_bt[0] == 'h');
1338 redraw_titles();
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001339
1340 return NULL;
1341}
1342
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001343 int
1344expand_set_buftype(optexpand_T *args, int *numMatches, char_u ***matches)
1345{
1346 return expand_set_opt_string(
1347 args,
1348 p_buftype_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001349 ARRAY_LENGTH(p_buftype_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001350 numMatches,
1351 matches);
1352}
1353
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001354/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001355 * The 'casemap' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001356 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001357 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001358did_set_casemap(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001359{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001360 return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
1361}
1362
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001363 int
1364expand_set_casemap(optexpand_T *args, int *numMatches, char_u ***matches)
1365{
1366 return expand_set_opt_string(
1367 args,
1368 p_cmp_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001369 ARRAY_LENGTH(p_cmp_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001370 numMatches,
1371 matches);
1372}
1373
1374#if defined(FEAT_CLIPBOARD) || defined(PROTO)
1375 int
1376expand_set_clipboard(optexpand_T *args, int *numMatches, char_u ***matches)
1377{
1378 return expand_set_opt_string(
1379 args,
1380 p_cb_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001381 ARRAY_LENGTH(p_cb_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001382 numMatches,
1383 matches);
1384}
1385#endif
1386
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001387/*
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001388 * The global 'listchars' or 'fillchars' option is changed.
1389 */
1390 static char *
zeertzjq6a8d2e12024-01-17 20:54:49 +01001391did_set_global_listfillchars(char_u *val, int opt_lcs, int opt_flags,
1392 char *errbuf, size_t errbuflen)
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001393{
1394 char *errmsg = NULL;
1395 char_u **local_ptr = opt_lcs ? &curwin->w_p_lcs : &curwin->w_p_fcs;
1396
1397 // only apply the global value to "curwin" when it does not have a
1398 // local value
1399 if (opt_lcs)
1400 errmsg = set_listchars_option(curwin, val,
zeertzjq6a8d2e12024-01-17 20:54:49 +01001401 **local_ptr == NUL || !(opt_flags & OPT_GLOBAL),
1402 errbuf, errbuflen);
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001403 else
1404 errmsg = set_fillchars_option(curwin, val,
zeertzjq6a8d2e12024-01-17 20:54:49 +01001405 **local_ptr == NUL || !(opt_flags & OPT_GLOBAL),
1406 errbuf, errbuflen);
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001407 if (errmsg != NULL)
1408 return errmsg;
1409
1410 tabpage_T *tp;
1411 win_T *wp;
1412
1413 // If the current window is set to use the global
1414 // 'listchars'/'fillchars' value, clear the window-local value.
1415 if (!(opt_flags & OPT_GLOBAL))
1416 clear_string_option(local_ptr);
1417 FOR_ALL_TAB_WINDOWS(tp, wp)
1418 {
1419 // If the current window has a local value need to apply it
1420 // again, it was changed when setting the global value.
1421 // If no error was returned above, we don't expect an error
1422 // here, so ignore the return value.
1423 if (opt_lcs)
1424 {
1425 if (*wp->w_p_lcs == NUL)
zeertzjq6a8d2e12024-01-17 20:54:49 +01001426 (void)set_listchars_option(wp, wp->w_p_lcs, TRUE, NULL, 0);
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001427 }
1428 else
1429 {
1430 if (*wp->w_p_fcs == NUL)
zeertzjq6a8d2e12024-01-17 20:54:49 +01001431 (void)set_fillchars_option(wp, wp->w_p_fcs, TRUE, NULL, 0);
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001432 }
1433 }
1434
1435 redraw_all_later(UPD_NOT_VALID);
1436
1437 return NULL;
1438}
1439
1440/*
1441 * The 'fillchars' option or the 'listchars' option is changed.
1442 */
1443 char *
1444did_set_chars_option(optset_T *args)
1445{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001446 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001447 char *errmsg = NULL;
1448
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001449 if ( varp == &p_lcs // global 'listchars'
1450 || varp == &p_fcs) // global 'fillchars'
1451 errmsg = did_set_global_listfillchars(*varp, varp == &p_lcs,
zeertzjq6a8d2e12024-01-17 20:54:49 +01001452 args->os_flags, args->os_errbuf, args->os_errbuflen);
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001453 else if (varp == &curwin->w_p_lcs) // local 'listchars'
zeertzjq6a8d2e12024-01-17 20:54:49 +01001454 errmsg = set_listchars_option(curwin, *varp, TRUE,
1455 args->os_errbuf, args->os_errbuflen);
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001456 else if (varp == &curwin->w_p_fcs) // local 'fillchars'
zeertzjq6a8d2e12024-01-17 20:54:49 +01001457 errmsg = set_fillchars_option(curwin, *varp, TRUE,
1458 args->os_errbuf, args->os_errbuflen);
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001459
1460 return errmsg;
1461}
1462
1463/*
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001464 * Expand 'fillchars' or 'listchars' option value.
1465 */
1466 int
1467expand_set_chars_option(optexpand_T *args, int *numMatches, char_u ***matches)
1468{
1469 char_u **varp = (char_u **)args->oe_varp;
1470 int is_lcs = (varp == &p_lcs || varp == &curwin->w_p_lcs);
1471 return expand_set_opt_generic(
1472 args,
1473 is_lcs ? get_listchars_name : get_fillchars_name,
1474 numMatches,
1475 matches);
1476}
1477
1478/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001479 * The 'cinoptions' option is changed.
1480 */
1481 char *
1482did_set_cinoptions(optset_T *args UNUSED)
1483{
1484 // TODO: recognize errors
1485 parse_cino(curbuf);
1486
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001487 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001488}
1489
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00001490#if defined(FEAT_SYN_HL) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001491/*
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00001492 * The 'colorcolumn' option is changed.
1493 */
1494 char *
Millya441a3e2024-10-22 22:43:01 +02001495did_set_colorcolumn(optset_T *args)
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00001496{
Millya441a3e2024-10-22 22:43:01 +02001497 char_u **varp = (char_u **)args->os_varp;
1498
1499 return check_colorcolumn(*varp, varp == &curwin->w_p_cc ? curwin : NULL);
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00001500}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001501#endif
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00001502
1503/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001504 * The 'comments' option is changed.
1505 */
1506 char *
1507did_set_comments(optset_T *args)
1508{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001509 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001510 char_u *s;
1511 char *errmsg = NULL;
1512
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001513 for (s = *varp; *s; )
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001514 {
1515 while (*s && *s != ':')
1516 {
1517 if (vim_strchr((char_u *)COM_ALL, *s) == NULL
1518 && !VIM_ISDIGIT(*s) && *s != '-')
1519 {
Christian Brabandtb39b2402023-11-29 11:34:05 +01001520 errmsg = illegal_char(args->os_errbuf, args->os_errbuflen, *s);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001521 break;
1522 }
1523 ++s;
1524 }
1525 if (*s++ == NUL)
1526 errmsg = e_missing_colon;
1527 else if (*s == ',' || *s == NUL)
1528 errmsg = e_zero_length_string;
1529 if (errmsg != NULL)
1530 break;
1531 while (*s && *s != ',')
1532 {
1533 if (*s == '\\' && s[1] != NUL)
1534 ++s;
1535 ++s;
1536 }
1537 s = skip_to_option_part(s);
1538 }
1539
1540 return errmsg;
1541}
1542
1543#if defined(FEAT_FOLDING) || defined(PROTO)
1544/*
1545 * The 'commentstring' option is changed.
1546 */
1547 char *
1548did_set_commentstring(optset_T *args)
1549{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001550 char_u **varp = (char_u **)args->os_varp;
1551
1552 if (**varp != NUL && strstr((char *)*varp, "%s") == NULL)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001553 return e_commentstring_must_be_empty_or_contain_str;
1554
1555 return NULL;
1556}
1557#endif
1558
1559/*
Girish Palyacbe53192025-04-14 22:13:15 +02001560 * Check if value for 'complete' is valid when 'complete' option is changed.
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001561 */
1562 char *
1563did_set_complete(optset_T *args)
1564{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001565 char_u **varp = (char_u **)args->os_varp;
Girish Palya0ac1eb32025-04-16 20:18:33 +02001566 char_u *p, *t;
Girish Palyacbe53192025-04-14 22:13:15 +02001567 char_u buffer[LSIZE];
1568 char_u *buf_ptr;
Girish Palya0ac1eb32025-04-16 20:18:33 +02001569 char_u char_before = NUL;
Girish Palyacbe53192025-04-14 22:13:15 +02001570 int escape;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001571
Girish Palyacbe53192025-04-14 22:13:15 +02001572 for (p = *varp; *p; )
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001573 {
Girish Palyacbe53192025-04-14 22:13:15 +02001574 vim_memset(buffer, 0, LSIZE);
1575 buf_ptr = buffer;
1576 escape = 0;
1577
1578 // Extract substring while handling escaped commas
1579 while (*p && (*p != ',' || escape) && buf_ptr < (buffer + LSIZE - 1))
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001580 {
Girish Palyacbe53192025-04-14 22:13:15 +02001581 if (*p == '\\' && *(p + 1) == ',')
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001582 {
Girish Palyacbe53192025-04-14 22:13:15 +02001583 escape = 1; // Mark escape mode
1584 p++; // Skip '\'
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001585 }
1586 else
1587 {
Girish Palyacbe53192025-04-14 22:13:15 +02001588 escape = 0;
1589 *buf_ptr++ = *p;
1590 }
1591 p++;
1592 }
1593 *buf_ptr = NUL;
1594
1595 if (vim_strchr((char_u *)".wbuksid]tUfo", *buffer) == NULL)
1596 return illegal_char(args->os_errbuf, args->os_errbuflen, *buffer);
1597
Girish Palya0ac1eb32025-04-16 20:18:33 +02001598 if (vim_strchr((char_u *)"ksf", *buffer) == NULL && *(buffer + 1) != NUL
1599 && *(buffer + 1) != '^')
1600 char_before = *buffer;
1601 else
1602 {
1603 // Test for a number after '^'
1604 if ((t = vim_strchr(buffer, '^')) != NULL)
1605 {
1606 *t++ = NUL;
1607 if (!*t)
1608 char_before = '^';
1609 else
1610 {
1611 for (; *t; t++)
1612 {
1613 if (!vim_isdigit(*t))
1614 {
1615 char_before = '^';
1616 break;
1617 }
1618 }
1619 }
1620 }
1621 }
1622 if (char_before != NUL)
Girish Palyacbe53192025-04-14 22:13:15 +02001623 {
1624 if (args->os_errbuf)
1625 {
1626 vim_snprintf((char *)args->os_errbuf, args->os_errbuflen,
Girish Palya0ac1eb32025-04-16 20:18:33 +02001627 _(e_illegal_character_after_chr), char_before);
Girish Palyacbe53192025-04-14 22:13:15 +02001628 return args->os_errbuf;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001629 }
Girish Palya0ac1eb32025-04-16 20:18:33 +02001630 return NULL;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001631 }
Girish Palyacbe53192025-04-14 22:13:15 +02001632 // Skip comma and spaces
1633 while (*p == ',' || *p == ' ')
1634 p++;
1635 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001636 return NULL;
1637}
1638
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001639 int
1640expand_set_complete(optexpand_T *args, int *numMatches, char_u ***matches)
1641{
1642 static char *(p_cpt_values[]) = {
Girish Palyacbe53192025-04-14 22:13:15 +02001643 ".", "w", "b", "u", "k", "kspell", "s", "i", "d", "]", "t", "U", "f", "o",
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001644 NULL};
1645 return expand_set_opt_string(
1646 args,
1647 p_cpt_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001648 ARRAY_LENGTH(p_cpt_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001649 numMatches,
1650 matches);
1651}
1652
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001653/*
1654 * The 'completeopt' option is changed.
1655 */
1656 char *
1657did_set_completeopt(optset_T *args UNUSED)
1658{
zeertzjq529b9ad2024-06-05 20:27:06 +02001659 char_u *cot = p_cot;
1660 unsigned *flags = &cot_flags;
1661
1662 if (args->os_flags & OPT_LOCAL)
1663 {
1664 cot = curbuf->b_p_cot;
1665 flags = &curbuf->b_cot_flags;
1666 }
zeertzjq46dcd842024-11-03 09:10:50 +01001667 else if (!(args->os_flags & OPT_GLOBAL))
1668 // When using :set, clear the local flags.
1669 curbuf->b_cot_flags = 0;
zeertzjq529b9ad2024-06-05 20:27:06 +02001670
1671 if (check_opt_strings(cot, p_cot_values, TRUE) != OK)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001672 return e_invalid_argument;
1673
zeertzjq529b9ad2024-06-05 20:27:06 +02001674 if (opt_strings_flags(cot, p_cot_values, flags, TRUE) != OK)
1675 return e_invalid_argument;
1676
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001677 return NULL;
1678}
1679
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001680 int
1681expand_set_completeopt(optexpand_T *args, int *numMatches, char_u ***matches)
1682{
1683 return expand_set_opt_string(
1684 args,
1685 p_cot_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001686 ARRAY_LENGTH(p_cot_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001687 numMatches,
1688 matches);
1689}
1690
glepnir6a89c942024-10-01 20:32:12 +02001691/*
glepnirf31cfa22025-03-06 21:59:13 +01001692 * The 'completefuzzycollect' option is changed.
1693 */
1694 char *
1695did_set_completefuzzycollect(optset_T *args UNUSED)
1696{
1697 if (opt_strings_flags(p_cfc, p_cfc_values, &cfc_flags, TRUE) != OK)
1698 return e_invalid_argument;
1699 return NULL;
1700}
1701
zeertzjq53d59ec2025-03-07 19:09:09 +01001702 int
1703expand_set_completefuzzycollect(
1704 optexpand_T *args,
1705 int *numMatches,
1706 char_u ***matches)
1707{
1708 return expand_set_opt_string(
1709 args,
1710 p_cfc_values,
1711 ARRAY_LENGTH(p_cfc_values) - 1,
1712 numMatches,
1713 matches);
1714}
1715
glepnirf31cfa22025-03-06 21:59:13 +01001716/*
glepnir6a89c942024-10-01 20:32:12 +02001717 * The 'completeitemalign' option is changed.
1718 */
1719 char *
1720did_set_completeitemalign(optset_T *args UNUSED)
1721{
1722 char_u *p = p_cia;
1723 unsigned new_cia_flags = 0;
1724 int seen[3] = { FALSE, FALSE, FALSE };
1725 int count = 0;
1726 char_u buf[10];
1727
1728 while (*p)
1729 {
1730 copy_option_part(&p, buf, sizeof(buf), ",");
1731 if (count >= 3)
1732 return e_invalid_argument;
1733
1734 if (STRCMP(buf, "abbr") == 0)
1735 {
1736 if (seen[CPT_ABBR])
1737 return e_invalid_argument;
1738 new_cia_flags = new_cia_flags * 10 + CPT_ABBR;
1739 seen[CPT_ABBR] = TRUE;
1740 count++;
1741 }
1742 else if (STRCMP(buf, "kind") == 0)
1743 {
1744 if (seen[CPT_KIND])
1745 return e_invalid_argument;
1746 new_cia_flags = new_cia_flags * 10 + CPT_KIND;
1747 seen[CPT_KIND] = TRUE;
1748 count++;
1749 }
1750 else if (STRCMP(buf, "menu") == 0)
1751 {
1752 if (seen[CPT_MENU])
1753 return e_invalid_argument;
1754 new_cia_flags = new_cia_flags * 10 + CPT_MENU;
1755 seen[CPT_MENU] = TRUE;
1756 count++;
1757 }
1758 else
1759 return e_invalid_argument;
1760 }
1761 if (new_cia_flags == 0 || count != 3)
1762 return e_invalid_argument;
1763
1764 cia_flags = new_cia_flags;
1765 return NULL;
1766}
1767
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001768#if (defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)) || defined(PROTO)
1769/*
1770 * The 'completepopup' option is changed.
1771 */
1772 char *
1773did_set_completepopup(optset_T *args UNUSED)
1774{
1775 if (parse_completepopup(NULL) == FAIL)
1776 return e_invalid_argument;
1777
1778 popup_close_info();
1779 return NULL;
1780}
1781#endif
1782
1783#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
1784/*
1785 * The 'completeslash' option is changed.
1786 */
1787 char *
1788did_set_completeslash(optset_T *args UNUSED)
1789{
1790 if (check_opt_strings(p_csl, p_csl_values, FALSE) != OK
1791 || check_opt_strings(curbuf->b_p_csl, p_csl_values, FALSE) != OK)
1792 return e_invalid_argument;
1793
1794 return NULL;
1795}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001796
1797 int
1798expand_set_completeslash(optexpand_T *args, int *numMatches, char_u ***matches)
1799{
1800 return expand_set_opt_string(
1801 args,
1802 p_csl_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001803 ARRAY_LENGTH(p_csl_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001804 numMatches,
1805 matches);
1806}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001807#endif
1808
1809#if defined(FEAT_CONCEAL) || defined(PROTO)
1810/*
1811 * The 'concealcursor' option is changed.
1812 */
1813 char *
1814did_set_concealcursor(optset_T *args)
1815{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001816 char_u **varp = (char_u **)args->os_varp;
1817
Christian Brabandtb39b2402023-11-29 11:34:05 +01001818 return did_set_option_listflag(*varp, (char_u *)COCU_ALL, args->os_errbuf,
1819 args->os_errbuflen);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001820}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001821
1822 int
1823expand_set_concealcursor(optexpand_T *args, int *numMatches, char_u ***matches)
1824{
1825 return expand_set_opt_listflag(args, (char_u*)COCU_ALL, numMatches, matches);
1826}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001827#endif
1828
1829/*
1830 * The 'cpoptions' option is changed.
1831 */
1832 char *
1833did_set_cpoptions(optset_T *args)
1834{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001835 char_u **varp = (char_u **)args->os_varp;
1836
Christian Brabandtb39b2402023-11-29 11:34:05 +01001837 return did_set_option_listflag(*varp, (char_u *)CPO_ALL, args->os_errbuf,
1838 args->os_errbuflen);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001839}
1840
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001841 int
1842expand_set_cpoptions(optexpand_T *args, int *numMatches, char_u ***matches)
1843{
1844 return expand_set_opt_listflag(args, (char_u*)CPO_ALL, numMatches, matches);
1845}
1846
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001847#if defined(FEAT_CRYPT) || defined(PROTO)
1848/*
1849 * The 'cryptkey' option is changed.
1850 */
1851 char *
1852did_set_cryptkey(optset_T *args)
1853{
1854 // Make sure the ":set" command doesn't show the new value in the
1855 // history.
1856 remove_key_from_history();
1857
Yee Cheng Chin6ee7b522023-10-01 09:13:22 +02001858 if (args->os_op != OP_NONE)
1859 // Don't allow set+=/-=/^= as they can allow for substring guessing
1860 return e_invalid_argument;
1861
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001862 if (STRCMP(curbuf->b_p_key, args->os_oldval.string) != 0)
1863 {
1864 // Need to update the swapfile.
1865 ml_set_crypt_key(curbuf, args->os_oldval.string,
1866 *curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
1867 changed_internal();
1868 }
Christian Brabandt19e6c4f2023-06-27 18:57:10 +01001869# ifdef FEAT_SODIUM
1870 if (crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
Yegappan Lakshmanane89aef32025-05-14 20:31:55 +02001871 crypt_sodium_lock_key(args->os_newval.string);
Christian Brabandt19e6c4f2023-06-27 18:57:10 +01001872# endif
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001873
1874 return NULL;
1875}
1876
1877/*
1878 * The 'cryptmethod' option is changed.
1879 */
1880 char *
1881did_set_cryptmethod(optset_T *args)
1882{
1883 char_u *p;
1884 char_u *s;
1885
1886 if (args->os_flags & OPT_LOCAL)
1887 p = curbuf->b_p_cm;
1888 else
1889 p = p_cm;
1890 if (check_opt_strings(p, p_cm_values, TRUE) != OK)
1891 return e_invalid_argument;
1892 else if (crypt_self_test() == FAIL)
1893 return e_invalid_argument;
1894
1895 // When setting the global value to empty, make it "zip".
1896 if (*p_cm == NUL)
1897 {
1898 free_string_option(p_cm);
1899 p_cm = vim_strsave((char_u *)"zip");
1900 }
1901 // When using ":set cm=name" the local value is going to be empty.
1902 // Do that here, otherwise the crypt functions will still use the
1903 // local value.
1904 if ((args->os_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
1905 {
1906 free_string_option(curbuf->b_p_cm);
1907 curbuf->b_p_cm = empty_option;
1908 }
1909
1910 // Need to update the swapfile when the effective method changed.
1911 // Set "s" to the effective old value, "p" to the effective new
1912 // method and compare.
1913 if ((args->os_flags & OPT_LOCAL) && *args->os_oldval.string == NUL)
1914 s = p_cm; // was previously using the global value
1915 else
1916 s = args->os_oldval.string;
1917 if (*curbuf->b_p_cm == NUL)
1918 p = p_cm; // is now using the global value
1919 else
1920 p = curbuf->b_p_cm;
1921 if (STRCMP(s, p) != 0)
1922 ml_set_crypt_key(curbuf, curbuf->b_p_key, s);
1923
1924 // If the global value changes need to update the swapfile for all
1925 // buffers using that value.
1926 if ((args->os_flags & OPT_GLOBAL)
1927 && STRCMP(p_cm, args->os_oldval.string) != 0)
1928 {
1929 buf_T *buf;
1930
1931 FOR_ALL_BUFFERS(buf)
1932 if (buf != curbuf && *buf->b_p_cm == NUL)
1933 ml_set_crypt_key(buf, buf->b_p_key, args->os_oldval.string);
1934 }
1935 return NULL;
1936}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001937
1938 int
1939expand_set_cryptmethod(optexpand_T *args, int *numMatches, char_u ***matches)
1940{
1941 return expand_set_opt_string(
1942 args,
1943 p_cm_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001944 ARRAY_LENGTH(p_cm_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001945 numMatches,
1946 matches);
1947}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00001948#endif
1949
1950#if (defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)) || defined(PROTO)
1951/*
1952 * The 'cscopequickfix' option is changed.
1953 */
1954 char *
1955did_set_cscopequickfix(optset_T *args UNUSED)
1956{
1957 char_u *p;
1958
1959 if (p_csqf == NULL)
1960 return NULL;
1961
1962 p = p_csqf;
1963 while (*p != NUL)
1964 {
1965 if (vim_strchr((char_u *)CSQF_CMDS, *p) == NULL
1966 || p[1] == NUL
1967 || vim_strchr((char_u *)CSQF_FLAGS, p[1]) == NULL
1968 || (p[2] != NUL && p[2] != ','))
1969 return e_invalid_argument;
1970 else if (p[2] == NUL)
1971 break;
1972 else
1973 p += 3;
1974 }
1975
1976 return NULL;
1977}
1978#endif
1979
1980#if defined(FEAT_SYN_HL) || defined(PROTO)
1981/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001982 * The 'cursorlineopt' option is changed.
1983 */
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00001984 char *
1985did_set_cursorlineopt(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001986{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001987 char_u **varp = (char_u **)args->os_varp;
1988
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001989 // This could be changed to use opt_strings_flags() instead.
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00001990 if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00001991 return e_invalid_argument;
1992
1993 return NULL;
1994}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001995
1996 int
1997expand_set_cursorlineopt(optexpand_T *args, int *numMatches, char_u ***matches)
1998{
1999 return expand_set_opt_string(
2000 args,
2001 p_culopt_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002002 ARRAY_LENGTH(p_culopt_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002003 numMatches,
2004 matches);
2005}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002006#endif
2007
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002008/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002009 * The 'debug' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002010 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002011 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002012did_set_debug(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002013{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002014 return did_set_opt_strings(p_debug, p_debug_values, TRUE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002015}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002016
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002017 int
2018expand_set_debug(optexpand_T *args, int *numMatches, char_u ***matches)
2019{
2020 return expand_set_opt_string(
2021 args,
2022 p_debug_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002023 ARRAY_LENGTH(p_debug_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002024 numMatches,
2025 matches);
2026}
2027
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002028#if defined(FEAT_DIFF) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002029/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002030 * The 'diffopt' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002031 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002032 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002033did_set_diffopt(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002034{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002035 if (diffopt_changed() == FAIL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002036 return e_invalid_argument;
2037
2038 return NULL;
2039}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002040
2041 int
2042expand_set_diffopt(optexpand_T *args, int *numMatches, char_u ***matches)
2043{
2044 expand_T *xp = args->oe_xp;
2045
2046 if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
2047 {
2048 // Within "algorithm:", we have a subgroup of possible options.
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002049 int algo_len = (int)STRLEN("algorithm:");
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002050 if (xp->xp_pattern - args->oe_set_arg >= algo_len &&
2051 STRNCMP(xp->xp_pattern - algo_len, "algorithm:", algo_len) == 0)
2052 {
2053 return expand_set_opt_string(
2054 args,
2055 p_dip_algorithm_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002056 ARRAY_LENGTH(p_dip_algorithm_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002057 numMatches,
2058 matches);
2059 }
Yee Cheng Chin9943d472025-03-26 19:41:02 +01002060 // Within "inline:", we have a subgroup of possible options.
2061 int inline_len = (int)STRLEN("inline:");
2062 if (xp->xp_pattern - args->oe_set_arg >= inline_len &&
2063 STRNCMP(xp->xp_pattern - inline_len, "inline:", inline_len) == 0)
2064 {
2065 return expand_set_opt_string(
2066 args,
2067 p_dip_inline_values,
2068 ARRAY_LENGTH(p_dip_inline_values) - 1,
2069 numMatches,
2070 matches);
2071 }
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002072 return FAIL;
2073 }
2074
2075 return expand_set_opt_string(
2076 args,
2077 p_dip_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002078 ARRAY_LENGTH(p_dip_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002079 numMatches,
2080 matches);
2081}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002082#endif
2083
2084/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002085 * The 'display' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002086 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002087 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002088did_set_display(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002089{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002090 if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE) != OK)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002091 return e_invalid_argument;
2092
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002093 (void)init_chartab();
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00002094 return NULL;
2095}
2096
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002097 int
2098expand_set_display(optexpand_T *args, int *numMatches, char_u ***matches)
2099{
2100 return expand_set_opt_string(
2101 args,
2102 p_dy_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002103 ARRAY_LENGTH(p_dy_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002104 numMatches,
2105 matches);
2106}
2107
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00002108/*
2109 * The 'eadirection' option is changed.
2110 */
2111 char *
2112did_set_eadirection(optset_T *args UNUSED)
2113{
2114 return did_set_opt_strings(p_ead, p_ead_values, FALSE);
2115}
2116
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002117 int
2118expand_set_eadirection(optexpand_T *args, int *numMatches, char_u ***matches)
2119{
2120 return expand_set_opt_string(
2121 args,
2122 p_ead_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002123 ARRAY_LENGTH(p_ead_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002124 numMatches,
2125 matches);
2126}
2127
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00002128/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002129 * One of the 'encoding', 'fileencoding', 'termencoding' or 'makeencoding'
2130 * options is changed.
2131 */
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002132 char *
2133did_set_encoding(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002134{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002135 char_u **varp = (char_u **)args->os_varp;
2136 char_u **gvarp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002137 char *errmsg = NULL;
2138 char_u *p;
2139
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002140 // Get the global option to compare with, otherwise we would have to check
2141 // two values for all local options.
2142 gvarp = (char_u **)get_option_varp_scope(args->os_idx, OPT_GLOBAL);
2143
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002144 if (gvarp == &p_fenc)
2145 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002146 if (!curbuf->b_p_ma && args->os_flags != OPT_GLOBAL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002147 errmsg = e_cannot_make_changes_modifiable_is_off;
2148 else if (vim_strchr(*varp, ',') != NULL)
2149 // No comma allowed in 'fileencoding'; catches confusing it
2150 // with 'fileencodings'.
2151 errmsg = e_invalid_argument;
2152 else
2153 {
2154 // May show a "+" in the title now.
2155 redraw_titles();
2156 // Add 'fileencoding' to the swap file.
2157 ml_setflags(curbuf);
2158 }
2159 }
2160 if (errmsg == NULL)
2161 {
2162 // canonize the value, so that STRCMP() can be used on it
2163 p = enc_canonize(*varp);
2164 if (p != NULL)
2165 {
2166 vim_free(*varp);
2167 *varp = p;
2168 }
2169 if (varp == &p_enc)
2170 {
2171 errmsg = mb_init();
2172 redraw_titles();
2173 }
2174 }
2175
2176#if defined(FEAT_GUI_GTK)
2177 if (errmsg == NULL && varp == &p_tenc && gui.in_use)
2178 {
2179 // GTK uses only a single encoding, and that is UTF-8.
2180 if (STRCMP(p_tenc, "utf-8") != 0)
2181 errmsg = e_cannot_be_changed_in_gtk_GUI;
2182 }
2183#endif
2184
2185 if (errmsg == NULL)
2186 {
2187#ifdef FEAT_KEYMAP
2188 // When 'keymap' is used and 'encoding' changes, reload the keymap
2189 // (with another encoding).
2190 if (varp == &p_enc && *curbuf->b_p_keymap != NUL)
2191 (void)keymap_init();
2192#endif
2193
2194 // When 'termencoding' is not empty and 'encoding' changes or when
2195 // 'termencoding' changes, need to setup for keyboard input and
2196 // display output conversion.
2197 if (((varp == &p_enc && *p_tenc != NUL) || varp == &p_tenc))
2198 {
2199 if (convert_setup(&input_conv, p_tenc, p_enc) == FAIL
2200 || convert_setup(&output_conv, p_enc, p_tenc) == FAIL)
2201 {
2202 semsg(_(e_cannot_convert_between_str_and_str),
2203 p_tenc, p_enc);
2204 errmsg = e_invalid_argument;
2205 }
2206 }
2207
2208#if defined(MSWIN)
K.Takatace3189d2023-02-15 19:13:43 +00002209 // $HOME, $VIM and $VIMRUNTIME may have characters in active code page.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002210 if (varp == &p_enc)
K.Takatace3189d2023-02-15 19:13:43 +00002211 {
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002212 init_homedir();
K.Takatace3189d2023-02-15 19:13:43 +00002213 init_vimdir();
2214 }
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002215#endif
2216 }
2217
2218 return errmsg;
2219}
2220
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002221 int
2222expand_set_encoding(optexpand_T *args, int *numMatches, char_u ***matches)
2223{
2224 return expand_set_opt_generic(
2225 args,
2226 get_encoding_name,
2227 numMatches,
2228 matches);
2229}
2230
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002231/*
Luuk van Baalb7147f82025-02-08 18:52:39 +01002232 * The 'eventignore(win)' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002233 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002234 char *
Luuk van Baalb7147f82025-02-08 18:52:39 +01002235did_set_eventignore(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002236{
Luuk van Baalb7147f82025-02-08 18:52:39 +01002237 char_u **varp = (char_u **)args->os_varp;
2238
2239 if (check_ei(*varp) == FAIL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002240 return e_invalid_argument;
2241 return NULL;
2242}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002243
Luuk van Baalb7147f82025-02-08 18:52:39 +01002244static int expand_eiw = FALSE;
2245
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002246 static char_u *
2247get_eventignore_name(expand_T *xp, int idx)
2248{
Luuk van Baalb7147f82025-02-08 18:52:39 +01002249 // 'eventignore(win)' allows special keyword "all" in addition to
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002250 // all event names.
2251 if (idx == 0)
2252 return (char_u *)"all";
Luuk van Baalb7147f82025-02-08 18:52:39 +01002253 return get_event_name_no_group(xp, idx - 1, expand_eiw);
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002254}
2255
2256 int
2257expand_set_eventignore(optexpand_T *args, int *numMatches, char_u ***matches)
2258{
Luuk van Baalb7147f82025-02-08 18:52:39 +01002259 expand_eiw = args->oe_varp != (char_u *)&p_ei;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002260 return expand_set_opt_generic(
2261 args,
2262 get_eventignore_name,
2263 numMatches,
2264 matches);
2265}
2266
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002267/*
2268 * The 'fileformat' option is changed.
2269 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002270 char *
2271did_set_fileformat(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002272{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002273 char_u **varp = (char_u **)args->os_varp;
2274
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002275 if (!curbuf->b_p_ma && !(args->os_flags & OPT_GLOBAL))
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002276 return e_cannot_make_changes_modifiable_is_off;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002277 else if (check_opt_strings(*varp, p_ff_values, FALSE) != OK)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002278 return e_invalid_argument;
2279
2280 // may also change 'textmode'
2281 if (get_fileformat(curbuf) == EOL_DOS)
2282 curbuf->b_p_tx = TRUE;
2283 else
2284 curbuf->b_p_tx = FALSE;
2285 redraw_titles();
2286 // update flag in swap file
2287 ml_setflags(curbuf);
2288 // Redraw needed when switching to/from "mac": a CR in the text
2289 // will be displayed differently.
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002290 if (get_fileformat(curbuf) == EOL_MAC || *args->os_oldval.string == 'm')
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002291 redraw_curbuf_later(UPD_NOT_VALID);
2292
2293 return NULL;
2294}
2295
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002296 int
2297expand_set_fileformat(optexpand_T *args, int *numMatches, char_u ***matches)
2298{
2299 return expand_set_opt_string(
2300 args,
2301 p_ff_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002302 ARRAY_LENGTH(p_ff_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002303 numMatches,
2304 matches);
2305}
2306
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002307/*
Yee Cheng Chin989426b2023-10-14 11:46:51 +02002308 * Function given to ExpandGeneric() to obtain the possible arguments of the
2309 * fileformat options.
2310 */
2311 char_u *
2312get_fileformat_name(expand_T *xp UNUSED, int idx)
2313{
2314 if (idx >= (int)ARRAY_LENGTH(p_ff_values))
2315 return NULL;
2316
2317 return (char_u*)p_ff_values[idx];
2318}
2319
2320/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002321 * The 'fileformats' option is changed.
2322 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002323 char *
2324did_set_fileformats(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002325{
2326 if (check_opt_strings(p_ffs, p_ff_values, TRUE) != OK)
2327 return e_invalid_argument;
2328
2329 // also change 'textauto'
2330 if (*p_ffs == NUL)
2331 p_ta = FALSE;
2332 else
2333 p_ta = TRUE;
2334
2335 return NULL;
2336}
2337
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002338/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002339 * The 'filetype' or the 'syntax' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002340 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002341 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002342did_set_filetype_or_syntax(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002343{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002344 char_u **varp = (char_u **)args->os_varp;
2345
2346 if (!valid_filetype(*varp))
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002347 return e_invalid_argument;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002348
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002349 args->os_value_changed = STRCMP(args->os_oldval.string, *varp) != 0;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002350
2351 // Since we check the value, there is no need to set P_INSECURE,
2352 // even when the value comes from a modeline.
2353 args->os_value_checked = TRUE;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002354
2355 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002356}
2357
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002358#if defined(FEAT_FOLDING) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002359/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002360 * The 'foldclose' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002361 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002362 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002363did_set_foldclose(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002364{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002365 return did_set_opt_strings(p_fcl, p_fcl_values, TRUE);
2366}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002367
2368 int
2369expand_set_foldclose(optexpand_T *args, int *numMatches, char_u ***matches)
2370{
2371 return expand_set_opt_string(
2372 args,
2373 p_fcl_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002374 ARRAY_LENGTH(p_fcl_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002375 numMatches,
2376 matches);
2377}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002378#endif
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002379
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002380#if (defined(FEAT_EVAL) && defined(FEAT_FOLDING)) || defined(PROTO)
2381/*
2382 * The 'foldexpr' option is changed.
2383 */
2384 char *
2385did_set_foldexpr(optset_T *args)
2386{
2387 (void)did_set_optexpr(args);
2388 if (foldmethodIsExpr(curwin))
2389 foldUpdateAll(curwin);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002390 return NULL;
2391}
2392#endif
2393
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002394#if defined(FEAT_FOLDING) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002395/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002396 * The 'foldignore' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002397 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002398 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002399did_set_foldignore(optset_T *args UNUSED)
2400{
2401 if (foldmethodIsIndent(curwin))
2402 foldUpdateAll(curwin);
2403 return NULL;
2404}
2405
2406/*
2407 * The 'foldmarker' option is changed.
2408 */
2409 char *
2410did_set_foldmarker(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002411{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002412 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002413 char_u *p;
2414
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002415 p = vim_strchr(*varp, ',');
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002416 if (p == NULL)
2417 return e_comma_required;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002418 else if (p == *varp || p[1] == NUL)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002419 return e_invalid_argument;
2420 else if (foldmethodIsMarker(curwin))
2421 foldUpdateAll(curwin);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002422
2423 return NULL;
2424}
2425
2426/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002427 * The 'foldmethod' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002428 */
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00002429 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002430did_set_foldmethod(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002431{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002432 char_u **varp = (char_u **)args->os_varp;
2433
Milly142cad12024-10-22 22:11:51 +02002434 if (check_opt_strings(*varp, p_fdm_values, FALSE) != OK || **varp == NUL)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002435 return e_invalid_argument;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002436
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002437 foldUpdateAll(curwin);
2438 if (foldmethodIsDiff(curwin))
2439 newFoldLevel();
2440 return NULL;
2441}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002442
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002443 int
2444expand_set_foldmethod(optexpand_T *args, int *numMatches, char_u ***matches)
2445{
2446 return expand_set_opt_string(
2447 args,
2448 p_fdm_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002449 ARRAY_LENGTH(p_fdm_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002450 numMatches,
2451 matches);
2452}
2453
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002454/*
2455 * The 'foldopen' option is changed.
2456 */
2457 char *
2458did_set_foldopen(optset_T *args UNUSED)
2459{
2460 return did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
2461}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002462
2463 int
2464expand_set_foldopen(optexpand_T *args, int *numMatches, char_u ***matches)
2465{
2466 return expand_set_opt_string(
2467 args,
2468 p_fdo_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002469 ARRAY_LENGTH(p_fdo_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002470 numMatches,
2471 matches);
2472}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002473#endif
2474
2475/*
2476 * The 'formatoptions' option is changed.
2477 */
2478 char *
2479did_set_formatoptions(optset_T *args)
2480{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002481 char_u **varp = (char_u **)args->os_varp;
2482
Christian Brabandtb39b2402023-11-29 11:34:05 +01002483 return did_set_option_listflag(*varp, (char_u *)FO_ALL, args->os_errbuf,
2484 args->os_errbuflen);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002485}
2486
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002487 int
2488expand_set_formatoptions(optexpand_T *args, int *numMatches, char_u ***matches)
2489{
2490 return expand_set_opt_listflag(args, (char_u*)FO_ALL, numMatches, matches);
2491}
2492
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00002493#if defined(CURSOR_SHAPE) || defined(PROTO)
2494/*
2495 * The 'guicursor' option is changed.
2496 */
2497 char *
2498did_set_guicursor(optset_T *args UNUSED)
2499{
2500 return parse_shape_opt(SHAPE_CURSOR);
2501}
2502#endif
2503
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002504#if defined(FEAT_GUI) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002505/*
2506 * The 'guifont' option is changed.
2507 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002508 char *
2509did_set_guifont(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002510{
2511 char_u *p;
2512 char *errmsg = NULL;
2513
2514 if (gui.in_use)
2515 {
2516 p = p_guifont;
2517# if defined(FEAT_GUI_GTK)
2518 // Put up a font dialog and let the user select a new value.
2519 // If this is cancelled go back to the old value but don't
2520 // give an error message.
2521 if (STRCMP(p, "*") == 0)
2522 {
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002523 p = gui_mch_font_dialog(args->os_oldval.string);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002524 free_string_option(p_guifont);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002525 p_guifont = (p != NULL) ? p : vim_strsave(args->os_oldval.string);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002526 }
2527# endif
2528 if (p != NULL && gui_init_font(p_guifont, FALSE) != OK)
2529 {
2530# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_PHOTON)
2531 if (STRCMP(p_guifont, "*") == 0)
2532 {
2533 // Dialog was cancelled: Keep the old value without giving
2534 // an error message.
2535 free_string_option(p_guifont);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002536 p_guifont = vim_strsave(args->os_oldval.string);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002537 }
2538 else
2539# endif
2540 errmsg = e_invalid_fonts;
2541 }
2542 }
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002543
2544 return errmsg;
2545}
2546
Yee Cheng Chin290b8872023-10-05 20:54:21 +02002547/*
2548 * Expand the 'guifont' option. Only when GUI is being used. Each platform has
2549 * specific behaviors.
2550 */
2551 int
2552expand_set_guifont(optexpand_T *args, int *numMatches, char_u ***matches)
2553{
2554 if (!gui.in_use)
2555 return FAIL;
2556
2557# if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK)
2558 char_u **varp = (char_u **)args->oe_varp;
2559 int wide = (varp == &p_guifontwide);
2560
2561 return expand_set_opt_callback(
2562 args, gui_mch_expand_font, &wide, numMatches, matches);
2563# else
2564 return FAIL;
2565# endif
2566}
2567
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002568# if defined(FEAT_XFONTSET) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002569/*
2570 * The 'guifontset' option is changed.
2571 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002572 char *
2573did_set_guifontset(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002574{
2575 char *errmsg = NULL;
2576
2577 if (STRCMP(p_guifontset, "*") == 0)
2578 errmsg = e_cant_select_fontset;
2579 else if (gui.in_use && gui_init_font(p_guifontset, TRUE) != OK)
2580 errmsg = e_invalid_fontset;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002581
2582 return errmsg;
2583}
2584# endif
2585
2586/*
2587 * The 'guifontwide' option is changed.
2588 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002589 char *
2590did_set_guifontwide(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002591{
2592 char *errmsg = NULL;
2593
2594 if (STRCMP(p_guifontwide, "*") == 0)
2595 errmsg = e_cant_select_wide_font;
2596 else if (gui_get_wide_font() == FAIL)
2597 errmsg = e_invalid_wide_font;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002598
2599 return errmsg;
2600}
2601#endif
2602
Erik S. V. Jansson8b1e7492024-02-24 14:26:52 +01002603#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN) || defined(PROTO)
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002604/*
2605 * The 'guiligatures' option is changed.
2606 */
2607 char *
2608did_set_guiligatures(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002609{
2610 gui_set_ligatures();
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002611 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002612}
2613#endif
2614
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00002615#if defined(FEAT_GUI) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002616/*
2617 * The 'guioptions' option is changed.
2618 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002619 char *
2620did_set_guioptions(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002621{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002622 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00002623 char *errmsg;
2624
Christian Brabandtb39b2402023-11-29 11:34:05 +01002625 errmsg = did_set_option_listflag(*varp, (char_u *)GO_ALL, args->os_errbuf,
2626 args->os_errbuflen);
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00002627 if (errmsg != NULL)
2628 return errmsg;
2629
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002630 gui_init_which_components(args->os_oldval.string);
2631 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002632}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002633
2634 int
2635expand_set_guioptions(optexpand_T *args, int *numMatches, char_u ***matches)
2636{
2637 return expand_set_opt_listflag(args, (char_u*)GO_ALL, numMatches, matches);
2638}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002639#endif
2640
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002641#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002642/*
2643 * The 'guitablabel' option is changed.
2644 */
2645 char *
2646did_set_guitablabel(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002647{
2648 redraw_tabline = TRUE;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002649 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002650}
2651#endif
2652
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002653/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002654 * The 'helpfile' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002655 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002656 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002657did_set_helpfile(optset_T *args UNUSED)
2658{
2659 // May compute new values for $VIM and $VIMRUNTIME
2660 if (didset_vim)
2661 vim_unsetenv_ext((char_u *)"VIM");
2662 if (didset_vimruntime)
2663 vim_unsetenv_ext((char_u *)"VIMRUNTIME");
2664 return NULL;
2665}
2666
2667#if defined(FEAT_MULTI_LANG) || defined(PROTO)
2668/*
2669 * The 'helplang' option is changed.
2670 */
2671 char *
2672did_set_helplang(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002673{
2674 char *errmsg = NULL;
2675
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002676 // Check for "", "ab", "ab,cd", etc.
2677 for (char_u *s = p_hlg; *s != NUL; s += 3)
2678 {
2679 if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL))
2680 {
2681 errmsg = e_invalid_argument;
2682 break;
2683 }
2684 if (s[2] == NUL)
2685 break;
2686 }
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002687
2688 return errmsg;
2689}
2690#endif
2691
2692/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002693 * The 'highlight' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002694 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002695 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002696did_set_highlight(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002697{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002698 if (highlight_changed() == FAIL)
2699 return e_invalid_argument; // invalid flags
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002700
2701 return NULL;
2702}
2703
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002704/*
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002705 * Expand 'highlight' option.
2706 */
2707 int
2708expand_set_highlight(optexpand_T *args, int *numMatches, char_u ***matches)
2709{
2710 char_u *p;
2711 expand_T *xp = args->oe_xp;
2712 static char_u hl_flags[HLF_COUNT] = HL_FLAGS;
Christian Brabandt3f168ec2023-10-02 23:21:11 +02002713 size_t i;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002714 int count = 0;
2715
2716 if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
2717 {
2718 // Right after a ':', meaning we just return all highlight names.
2719 return expand_set_opt_generic(
2720 args,
2721 get_highlight_name,
2722 numMatches,
2723 matches);
2724 }
2725
2726 if (*xp->xp_pattern == NUL)
2727 {
2728 // At beginning of a comma-separated list. Return the specific list of
2729 // supported occasions.
2730 *matches = ALLOC_MULT(char_u *, HLF_COUNT + 1);
2731 if (*matches == NULL)
2732 return FAIL;
2733
2734 // We still want to return the full option if it's requested.
2735 if (args->oe_include_orig_val)
2736 {
2737 p = vim_strsave(args->oe_opt_value);
2738 if (p == NULL)
2739 {
2740 VIM_CLEAR(*matches);
2741 return FAIL;
2742 }
2743 (*matches)[count++] = p;
2744 }
2745
2746 for (i = 0; i < HLF_COUNT; i++)
2747 {
2748 p = vim_strnsave(&hl_flags[i], 1);
2749 if (p == NULL)
2750 {
2751 if (count == 0)
2752 {
2753 VIM_CLEAR(*matches);
2754 return FAIL;
2755 }
2756 else
2757 break;
2758 }
2759 (*matches)[count++] = p;
2760 }
2761
2762 if (count == 0)
2763 {
2764 VIM_CLEAR(*matches);
2765 return FAIL;
2766 }
2767 *numMatches = count;
2768 return OK;
2769 }
2770
2771 // We are after the initial character (which indicates the occasion). We
2772 // already made sure we are not matching after a ':' above, so now we want
2773 // to match against display mode modifiers.
2774 // Since the xp_pattern starts from the beginning, we need to include it in
2775 // the returned match.
2776
2777 // Note: Keep this in sync with highlight_changed()
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002778 static char_u p_hl_mode_values[] =
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002779 {':', 'b', 'i', '-', 'n', 'r', 's', 'u', 'c', '2', 'd', '=', 't'};
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002780 size_t num_hl_modes = ARRAY_LENGTH(p_hl_mode_values);
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002781
2782 *matches = ALLOC_MULT(char_u *, num_hl_modes);
2783 if (*matches == NULL)
2784 return FAIL;
2785
Yee Cheng Chin209ec902023-10-17 10:56:25 +02002786 int pattern_len = xp->xp_pattern_len;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002787
2788 for (i = 0; i < num_hl_modes; i++)
2789 {
2790 // Don't allow duplicates as these are unique flags
Yee Cheng Chin209ec902023-10-17 10:56:25 +02002791 char_u *dup = vim_strchr(xp->xp_pattern + 1, p_hl_mode_values[i]);
2792 if (dup != NULL && (int)(dup - xp->xp_pattern) < pattern_len)
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002793 continue;
2794
2795 // ':' only works by itself, not with other flags.
2796 if (pattern_len > 1 && p_hl_mode_values[i] == ':')
2797 continue;
2798
2799 p = vim_strnsave(xp->xp_pattern, pattern_len + 1);
2800 if (p == NULL)
2801 {
2802 if (i == 0)
2803 {
2804 VIM_CLEAR(*matches);
2805 return FAIL;
2806 }
2807 else
2808 break;
2809 }
2810 p[pattern_len] = p_hl_mode_values[i];
2811 p[pattern_len + 1] = NUL;
2812 (*matches)[count++] = p;
2813 }
2814 if (count == 0)
2815 {
2816 VIM_CLEAR(*matches);
2817 return FAIL;
2818 }
2819 *numMatches = count;
2820
2821 return OK;
2822}
2823
2824/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002825 * The 'titlestring' or the 'iconstring' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002826 */
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002827 static char *
2828parse_titleiconstring(optset_T *args UNUSED, int flagval UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002829{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002830#ifdef FEAT_STL_OPT
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002831 char_u **varp = (char_u **)args->os_varp;
2832
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002833 // NULL => statusline syntax
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002834 if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002835 stl_syntax |= flagval;
2836 else
2837 stl_syntax &= ~flagval;
2838#endif
2839 did_set_title();
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00002840
2841 return NULL;
2842}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002843
2844/*
2845 * The 'iconstring' option is changed.
2846 */
2847 char *
2848did_set_iconstring(optset_T *args)
2849{
2850 int flagval = 0;
2851
2852#ifdef FEAT_STL_OPT
2853 flagval = STL_IN_ICON;
2854#endif
2855
2856 return parse_titleiconstring(args, flagval);
2857}
2858
2859#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
2860/*
2861 * The 'imactivatekey' option is changed.
2862 */
2863 char *
2864did_set_imactivatekey(optset_T *args UNUSED)
2865{
2866 if (!im_xim_isvalid_imactivate())
2867 return e_invalid_argument;
2868 return NULL;
2869}
2870#endif
2871
2872/*
glepnirbcd59952025-04-24 21:48:35 +02002873 * The 'isexpand' option is changed.
2874 */
2875 char *
2876did_set_isexpand(optset_T *args)
2877{
2878 char_u *ise = p_ise;
2879 char_u *p;
2880 int last_was_comma = FALSE;
2881
2882 if (args->os_flags & OPT_LOCAL)
2883 ise = curbuf->b_p_ise;
2884
2885 for (p = ise; *p != NUL;)
2886 {
2887 if (*p == '\\' && p[1] == ',')
2888 {
2889 p += 2;
2890 last_was_comma = FALSE;
2891 continue;
2892 }
2893
2894 if (*p == ',')
2895 {
2896 if (last_was_comma)
2897 return e_invalid_argument;
2898 last_was_comma = TRUE;
2899 p++;
2900 continue;
2901 }
2902
2903 last_was_comma = FALSE;
2904 MB_PTR_ADV(p);
2905 }
2906
2907 if (last_was_comma)
2908 return e_invalid_argument;
2909
2910 return NULL;
2911}
2912
2913
2914/*
Milly5e7a6a42024-10-22 22:27:19 +02002915 * The 'iskeyword' option is changed.
2916 */
2917 char *
2918did_set_iskeyword(optset_T *args)
2919{
2920 char_u **varp = (char_u **)args->os_varp;
2921
2922 if (varp == &p_isk) // only check for global-value
2923 {
2924 if (check_isopt(*varp) == FAIL)
2925 return e_invalid_argument;
2926 }
2927 else // fallthrough for local-value
2928 return did_set_isopt(args);
2929
2930 return NULL;
2931}
2932
2933/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002934 * The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is
2935 * changed.
2936 */
2937 char *
2938did_set_isopt(optset_T *args)
2939{
Milly5e7a6a42024-10-22 22:27:19 +02002940 // 'isident', 'iskeyword', 'isprint' or 'isfname' option: refill g_chartab[]
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002941 // If the new option is invalid, use old value.
2942 // 'lisp' option: refill g_chartab[] for '-' char.
2943 if (init_chartab() == FAIL)
2944 {
2945 args->os_restore_chartab = TRUE;// need to restore the chartab.
2946 return e_invalid_argument; // error in value
2947 }
2948
2949 return NULL;
2950}
2951
Yegappan Lakshmanan87018252023-09-20 20:20:04 +02002952/*
2953 * The 'jumpoptions' option is changed.
2954 */
2955 char *
Yegappan Lakshmanan1926ae42023-09-21 16:36:28 +02002956did_set_jumpoptions(optset_T *args UNUSED)
Yegappan Lakshmanan87018252023-09-20 20:20:04 +02002957{
2958 if (opt_strings_flags(p_jop, p_jop_values, &jop_flags, TRUE) != OK)
2959 return e_invalid_argument;
2960
2961 return NULL;
2962}
2963
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002964 int
2965expand_set_jumpoptions(optexpand_T *args, int *numMatches, char_u ***matches)
2966{
2967 return expand_set_opt_string(
2968 args,
2969 p_jop_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02002970 ARRAY_LENGTH(p_jop_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02002971 numMatches,
2972 matches);
2973}
2974
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002975#if defined(FEAT_KEYMAP) || defined(PROTO)
2976/*
2977 * The 'keymap' option is changed.
2978 */
2979 char *
2980did_set_keymap(optset_T *args)
2981{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002982 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002983 char *errmsg = NULL;
2984
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00002985 if (!valid_filetype(*varp))
Yegappan Lakshmananad608982023-03-01 12:44:06 +00002986 errmsg = e_invalid_argument;
2987 else
2988 {
2989 int secure_save = secure;
2990
2991 // Reset the secure flag, since the value of 'keymap' has
2992 // been checked to be safe.
2993 secure = 0;
2994
2995 // load or unload key mapping tables
2996 errmsg = keymap_init();
2997
2998 secure = secure_save;
2999
3000 // Since we check the value, there is no need to set P_INSECURE,
3001 // even when the value comes from a modeline.
3002 args->os_value_checked = TRUE;
3003 }
3004
3005 if (errmsg == NULL)
3006 {
3007 if (*curbuf->b_p_keymap != NUL)
3008 {
3009 // Installed a new keymap, switch on using it.
3010 curbuf->b_p_iminsert = B_IMODE_LMAP;
3011 if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT)
3012 curbuf->b_p_imsearch = B_IMODE_LMAP;
3013 }
3014 else
3015 {
3016 // Cleared the keymap, may reset 'iminsert' and 'imsearch'.
3017 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
3018 curbuf->b_p_iminsert = B_IMODE_NONE;
3019 if (curbuf->b_p_imsearch == B_IMODE_LMAP)
3020 curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
3021 }
3022 if ((args->os_flags & OPT_LOCAL) == 0)
3023 {
3024 set_iminsert_global();
3025 set_imsearch_global();
3026 }
3027 status_redraw_curbuf();
3028 }
3029
3030 return errmsg;
3031}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003032#endif
3033
3034/*
3035 * The 'keymodel' option is changed.
3036 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003037 char *
3038did_set_keymodel(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003039{
3040 if (check_opt_strings(p_km, p_km_values, TRUE) != OK)
3041 return e_invalid_argument;
3042
3043 km_stopsel = (vim_strchr(p_km, 'o') != NULL);
3044 km_startsel = (vim_strchr(p_km, 'a') != NULL);
3045 return NULL;
3046}
3047
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003048 int
3049expand_set_keymodel(optexpand_T *args, int *numMatches, char_u ***matches)
3050{
3051 return expand_set_opt_string(
3052 args,
3053 p_km_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003054 ARRAY_LENGTH(p_km_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003055 numMatches,
3056 matches);
3057}
3058
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003059/*
3060 * The 'keyprotocol' option is changed.
3061 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003062 char *
3063did_set_keyprotocol(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003064{
Gregory Anders3695d0e2023-09-29 20:17:20 +02003065 char_u *term = T_NAME;
3066 keyprot_T kpc = match_keyprotocol(term);
3067 if (kpc == KEYPROTOCOL_FAIL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003068 return e_invalid_argument;
3069
Gregory Anders3695d0e2023-09-29 20:17:20 +02003070 apply_keyprotocol(term, kpc);
3071
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003072 return NULL;
3073}
3074
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003075 int
3076expand_set_keyprotocol(optexpand_T *args, int *numMatches, char_u ***matches)
3077{
3078 expand_T *xp = args->oe_xp;
3079 if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
3080 {
3081 // 'keyprotocol' only has well-defined terms for completion for the
3082 // protocol part after the colon.
3083 return expand_set_opt_string(
3084 args,
3085 p_kpc_protocol_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003086 ARRAY_LENGTH(p_kpc_protocol_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003087 numMatches,
3088 matches);
3089 }
3090 // Use expand_set_opt_string instead of returning FAIL so that we can
3091 // include the original value if args->oe_include_orig_val is set.
3092 static char *(empty[]) = {NULL};
3093 return expand_set_opt_string(args, empty, 0, numMatches, matches);
3094}
3095
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003096/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003097 * The 'lispoptions' option is changed.
3098 */
3099 char *
3100did_set_lispoptions(optset_T *args)
3101{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003102 char_u **varp = (char_u **)args->os_varp;
3103
3104 if (**varp != NUL
3105 && STRCMP(*varp, "expr:0") != 0
3106 && STRCMP(*varp, "expr:1") != 0)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003107 return e_invalid_argument;
3108
3109 return NULL;
3110}
3111
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003112 int
3113expand_set_lispoptions(optexpand_T *args, int *numMatches, char_u ***matches)
3114{
3115 static char *(p_lop_values[]) = {"expr:0", "expr:1", NULL};
3116 return expand_set_opt_string(
3117 args,
3118 p_lop_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003119 ARRAY_LENGTH(p_lop_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003120 numMatches,
3121 matches);
3122}
3123
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003124/*
3125 * The 'matchpairs' option is changed.
3126 */
3127 char *
3128did_set_matchpairs(optset_T *args)
3129{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003130 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003131 char_u *p;
3132
3133 if (has_mbyte)
3134 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003135 for (p = *varp; *p != NUL; ++p)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003136 {
3137 int x2 = -1;
3138 int x3 = -1;
3139
3140 p += mb_ptr2len(p);
3141 if (*p != NUL)
3142 x2 = *p++;
3143 if (*p != NUL)
3144 {
3145 x3 = mb_ptr2char(p);
3146 p += mb_ptr2len(p);
3147 }
3148 if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ','))
3149 return e_invalid_argument;
3150 if (*p == NUL)
3151 break;
3152 }
3153 }
3154 else
3155 {
3156 // Check for "x:y,x:y"
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003157 for (p = *varp; *p != NUL; p += 4)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003158 {
3159 if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ','))
3160 return e_invalid_argument;
3161 if (p[3] == NUL)
3162 break;
3163 }
3164 }
3165
3166 return NULL;
3167}
3168
Christian Brabandt51d4d842024-12-06 17:26:25 +01003169/*
3170 * Process the updated 'messagesopt' option value.
3171 */
3172 char *
3173did_set_messagesopt(optset_T *args UNUSED)
3174{
3175 if (messagesopt_changed() == FAIL)
3176 return e_invalid_argument;
3177
3178 return NULL;
3179}
3180
3181 int
3182expand_set_messagesopt(optexpand_T *args, int *numMatches, char_u ***matches)
3183{
zeertzjq8cc43da2024-12-07 16:09:08 +01003184 static char *(p_mopt_values[]) = {"hit-enter", "wait:", "history:", NULL};
Christian Brabandt51d4d842024-12-06 17:26:25 +01003185 return expand_set_opt_string(
3186 args,
zeertzjq8cc43da2024-12-07 16:09:08 +01003187 p_mopt_values,
3188 ARRAY_LENGTH(p_mopt_values) - 1,
Christian Brabandt51d4d842024-12-06 17:26:25 +01003189 numMatches,
3190 matches);
3191}
3192
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003193#if defined(FEAT_SPELL) || defined(PROTO)
3194/*
3195 * The 'mkspellmem' option is changed.
3196 */
3197 char *
3198did_set_mkspellmem(optset_T *args UNUSED)
3199{
3200 if (spell_check_msm() != OK)
3201 return e_invalid_argument;
3202
3203 return NULL;
3204}
3205#endif
3206
3207/*
3208 * The 'mouse' option is changed.
3209 */
3210 char *
3211did_set_mouse(optset_T *args)
3212{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003213 char_u **varp = (char_u **)args->os_varp;
3214
Christian Brabandtb39b2402023-11-29 11:34:05 +01003215 return did_set_option_listflag(*varp, (char_u *)MOUSE_ALL, args->os_errbuf,
3216 args->os_errbuflen);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003217}
3218
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003219 int
3220expand_set_mouse(optexpand_T *args, int *numMatches, char_u ***matches)
3221{
3222 return expand_set_opt_listflag(args, (char_u*)MOUSE_ALL, numMatches, matches);
3223}
3224
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003225/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003226 * The 'mousemodel' option is changed.
3227 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003228 char *
3229did_set_mousemodel(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003230{
3231 if (check_opt_strings(p_mousem, p_mousem_values, FALSE) != OK)
3232 return e_invalid_argument;
3233#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU) && (XmVersion <= 1002)
Ken Takata18d0d292023-12-19 20:12:29 +01003234 else if (*p_mousem != *args->os_oldval.string)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003235 // Changed from "extend" to "popup" or "popup_setpos" or vv: need
3236 // to create or delete the popup menus.
3237 gui_motif_update_mousemodel(root_menu);
3238#endif
3239
3240 return NULL;
3241}
3242
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003243 int
3244expand_set_mousemodel(optexpand_T *args, int *numMatches, char_u ***matches)
3245{
3246 return expand_set_opt_string(
3247 args,
3248 p_mousem_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003249 ARRAY_LENGTH(p_mousem_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003250 numMatches,
3251 matches);
3252}
3253
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003254#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
3255 char *
3256did_set_mouseshape(optset_T *args UNUSED)
3257{
3258 char *errmsg = NULL;
3259
3260 errmsg = parse_shape_opt(SHAPE_MOUSE);
3261 update_mouseshape(-1);
3262
3263 return errmsg;
3264}
3265#endif
3266
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003267/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003268 * The 'nrformats' option is changed.
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00003269 */
3270 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003271did_set_nrformats(optset_T *args)
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00003272{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003273 char_u **varp = (char_u **)args->os_varp;
3274
3275 return did_set_opt_strings(*varp, p_nf_values, TRUE);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003276}
3277
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003278 int
3279expand_set_nrformats(optexpand_T *args, int *numMatches, char_u ***matches)
3280{
3281 return expand_set_opt_string(
3282 args,
3283 p_nf_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003284 ARRAY_LENGTH(p_nf_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003285 numMatches,
3286 matches);
3287}
3288
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003289#if defined(FEAT_EVAL) || defined(PROTO)
3290/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003291 * One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
Yegappan Lakshmanana13f3a42024-11-02 18:40:10 +01003292 * 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
3293 * 'patchexpr', 'printexpr' and 'charconvert'.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003294 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003295 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003296did_set_optexpr(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003297{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003298 char_u **varp = (char_u **)args->os_varp;
3299
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003300 // If the option value starts with <SID> or s:, then replace that with
3301 // the script identifier.
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003302 char_u *name = get_scriptlocal_funcname(*varp);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003303 if (name != NULL)
3304 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003305 free_string_option(*varp);
3306 *varp = name;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003307 }
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003308
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003309 return NULL;
3310}
3311#endif
3312
3313/*
3314 * The 'pastetoggle' option is changed.
3315 */
3316 char *
3317did_set_pastetoggle(optset_T *args UNUSED)
3318{
3319 char_u *p;
3320
3321 // translate key codes like in a mapping
3322 if (*p_pt)
3323 {
zeertzjq7e0bae02023-08-11 23:15:38 +02003324 (void)replace_termcodes(p_pt, &p, 0,
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003325 REPTERM_FROM_PART | REPTERM_DO_LT, NULL);
3326 if (p != NULL)
3327 {
3328 free_string_option(p_pt);
3329 p_pt = p;
3330 }
3331 }
3332
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003333 return NULL;
3334}
3335
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003336#if defined(FEAT_PROP_POPUP) || defined(PROTO)
3337/*
3338 * The 'previewpopup' option is changed.
3339 */
3340 char *
3341did_set_previewpopup(optset_T *args UNUSED)
3342{
3343 if (parse_previewpopup(NULL) == FAIL)
3344 return e_invalid_argument;
3345
3346 return NULL;
3347}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003348
3349 int
3350expand_set_popupoption(optexpand_T *args, int *numMatches, char_u ***matches)
3351{
3352 expand_T *xp = args->oe_xp;
3353
3354 if (xp->xp_pattern > args->oe_set_arg && *(xp->xp_pattern-1) == ':')
3355 {
3356 // Within "highlight:"/"border:"/"align:", we have a subgroup of possible options.
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003357 int border_len = (int)STRLEN("border:");
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003358 if (xp->xp_pattern - args->oe_set_arg >= border_len &&
3359 STRNCMP(xp->xp_pattern - border_len, "border:", border_len) == 0)
3360 {
3361 return expand_set_opt_string(
3362 args,
3363 p_popup_option_border_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003364 ARRAY_LENGTH(p_popup_option_border_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003365 numMatches,
3366 matches);
3367 }
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003368 int align_len = (int)STRLEN("align:");
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003369 if (xp->xp_pattern - args->oe_set_arg >= align_len &&
3370 STRNCMP(xp->xp_pattern - align_len, "align:", align_len) == 0)
3371 {
3372 return expand_set_opt_string(
3373 args,
3374 p_popup_option_align_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003375 ARRAY_LENGTH(p_popup_option_align_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003376 numMatches,
3377 matches);
3378 }
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003379 int highlight_len = (int)STRLEN("highlight:");
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003380 if (xp->xp_pattern - args->oe_set_arg >= highlight_len &&
3381 STRNCMP(xp->xp_pattern - highlight_len, "highlight:", highlight_len) == 0)
3382 {
3383 // Return the list of all highlight names
3384 return expand_set_opt_generic(
3385 args,
3386 get_highlight_name,
3387 numMatches,
3388 matches);
3389 }
3390 return FAIL;
3391 }
3392
3393 return expand_set_opt_string(
3394 args,
3395 p_popup_option_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003396 ARRAY_LENGTH(p_popup_option_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003397 numMatches,
3398 matches);
3399}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003400#endif
3401
3402#if defined(FEAT_POSTSCRIPT) || defined(PROTO)
3403/*
3404 * The 'printencoding' option is changed.
3405 */
3406 char *
3407did_set_printencoding(optset_T *args UNUSED)
3408{
3409 char_u *s, *p;
3410
3411 // Canonize 'printencoding' if VIM standard one
3412 p = enc_canonize(p_penc);
3413 if (p != NULL)
3414 {
3415 vim_free(p_penc);
3416 p_penc = p;
3417 }
3418 else
3419 {
3420 // Ensure lower case and '-' for '_'
3421 for (s = p_penc; *s != NUL; s++)
3422 {
3423 if (*s == '_')
3424 *s = '-';
3425 else
3426 *s = TOLOWER_ASC(*s);
3427 }
3428 }
3429
3430 return NULL;
3431}
3432#endif
3433
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003434#if defined(FEAT_PRINTER) || defined(PROTO)
3435
3436 static char_u *
3437get_printoptions_names(expand_T *xp UNUSED, int idx)
3438{
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003439 if (idx >= (int)ARRAY_LENGTH(printer_opts))
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003440 return NULL;
3441 return (char_u*)printer_opts[idx].name;
3442}
3443
3444/*
3445 * Expand 'printoptions' option
3446 */
3447 int
3448expand_set_printoptions(optexpand_T *args, int *numMatches, char_u ***matches)
3449{
3450 return expand_set_opt_generic(
3451 args,
3452 get_printoptions_names,
3453 numMatches,
3454 matches);
3455}
3456#endif
3457
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003458#if defined(FEAT_STL_OPT) || defined(PROTO)
3459/*
3460 * The 'statusline' or the 'tabline' or the 'rulerformat' option is changed.
3461 * "rulerformat" is TRUE if the 'rulerformat' option is changed.
3462 */
3463 static char *
3464parse_statustabline_rulerformat(optset_T *args, int rulerformat)
3465{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003466 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003467 char_u *s;
3468 char *errmsg = NULL;
3469 int wid;
3470
3471 if (rulerformat) // reset ru_wid first
3472 ru_wid = 0;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003473 s = *varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003474 if (rulerformat && *s == '%')
3475 {
3476 // set ru_wid if 'ruf' starts with "%99("
3477 if (*++s == '-') // ignore a '-'
3478 s++;
3479 wid = getdigits(&s);
3480 if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL)
3481 ru_wid = wid;
3482 else
Yegappan Lakshmananac023e82024-11-27 20:55:45 +01003483 {
3484 // Validate the flags in 'rulerformat' only if it doesn't point to
3485 // a custom function ("%!" flag).
3486 if ((*varp)[1] != '!')
3487 errmsg = check_stl_option(p_ruf);
3488 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003489 }
3490 // check 'statusline' or 'tabline' only if it doesn't start with "%!"
3491 else if (rulerformat || s[0] != '%' || s[1] != '!')
3492 errmsg = check_stl_option(s);
3493 if (rulerformat && errmsg == NULL)
3494 comp_col();
3495
3496 return errmsg;
3497}
3498#endif
3499
3500#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
3501/*
3502 * The 'renderoptions' option is changed.
3503 */
3504 char *
3505did_set_renderoptions(optset_T *args UNUSED)
3506{
3507 if (!gui_mch_set_rendering_options(p_rop))
3508 return e_invalid_argument;
3509
3510 return NULL;
3511}
3512#endif
3513
3514#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
3515/*
3516 * The 'rightleftcmd' option is changed.
3517 */
3518 char *
3519did_set_rightleftcmd(optset_T *args)
3520{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003521 char_u **varp = (char_u **)args->os_varp;
3522
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003523 // Currently only "search" is a supported value.
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003524 if (**varp != NUL && STRCMP(*varp, "search") != 0)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003525 return e_invalid_argument;
3526
3527 return NULL;
3528}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003529
3530 int
3531expand_set_rightleftcmd(optexpand_T *args, int *numMatches, char_u ***matches)
3532{
3533 static char *(p_rlc_values[]) = {"search", NULL};
3534 return expand_set_opt_string(
3535 args,
3536 p_rlc_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003537 ARRAY_LENGTH(p_rlc_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003538 numMatches,
3539 matches);
3540}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003541#endif
3542
3543#if defined(FEAT_STL_OPT) || defined(PROTO)
3544/*
3545 * The 'rulerformat' option is changed.
3546 */
3547 char *
3548did_set_rulerformat(optset_T *args)
3549{
3550 return parse_statustabline_rulerformat(args, TRUE);
3551}
3552#endif
3553
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +02003554#if defined(FEAT_TABPANEL)
3555/*
3556 * Process the new 'tabpanelopt' option value.
3557 */
3558 char *
3559did_set_tabpanelopt(optset_T *args)
3560{
3561 if (tabpanelopt_changed() == FAIL)
3562 return e_invalid_argument;
3563
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +02003564 return NULL;
3565}
3566
3567 int
3568expand_set_tabpanelopt(optexpand_T *args, int *numMatches, char_u ***matches)
3569{
3570 return expand_set_opt_string(
3571 args,
3572 p_tpl_values,
3573 ARRAY_LENGTH(p_tpl_values) - 1,
3574 numMatches,
3575 matches);
3576}
3577#endif
3578
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003579/*
3580 * The 'scrollopt' option is changed.
3581 */
3582 char *
3583did_set_scrollopt(optset_T *args UNUSED)
3584{
3585 return did_set_opt_strings(p_sbo, p_scbopt_values, TRUE);
3586}
3587
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003588 int
3589expand_set_scrollopt(optexpand_T *args, int *numMatches, char_u ***matches)
3590{
3591 return expand_set_opt_string(
3592 args,
3593 p_scbopt_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003594 ARRAY_LENGTH(p_scbopt_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003595 numMatches,
3596 matches);
3597}
3598
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003599/*
3600 * The 'selection' option is changed.
3601 */
3602 char *
3603did_set_selection(optset_T *args UNUSED)
3604{
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003605 if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, FALSE) != OK)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003606 return e_invalid_argument;
3607
3608 return NULL;
3609}
3610
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003611 int
3612expand_set_selection(optexpand_T *args, int *numMatches, char_u ***matches)
3613{
3614 return expand_set_opt_string(
3615 args,
3616 p_sel_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003617 ARRAY_LENGTH(p_sel_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003618 numMatches,
3619 matches);
3620}
3621
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003622/*
3623 * The 'selectmode' option is changed.
3624 */
3625 char *
3626did_set_selectmode(optset_T *args UNUSED)
3627{
3628 return did_set_opt_strings(p_slm, p_slm_values, TRUE);
3629}
3630
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003631 int
3632expand_set_selectmode(optexpand_T *args, int *numMatches, char_u ***matches)
3633{
3634 return expand_set_opt_string(
3635 args,
3636 p_slm_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003637 ARRAY_LENGTH(p_slm_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003638 numMatches,
3639 matches);
3640}
3641
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003642#if defined(FEAT_SESSION) || defined(PROTO)
3643/*
3644 * The 'sessionoptions' option is changed.
3645 */
3646 char *
3647did_set_sessionoptions(optset_T *args)
3648{
3649 if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE) != OK)
3650 return e_invalid_argument;
3651 if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR))
3652 {
3653 // Don't allow both "sesdir" and "curdir".
3654 (void)opt_strings_flags(args->os_oldval.string, p_ssop_values,
3655 &ssop_flags, TRUE);
3656 return e_invalid_argument;
3657 }
3658
3659 return NULL;
3660}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003661
3662 int
3663expand_set_sessionoptions(optexpand_T *args, int *numMatches, char_u ***matches)
3664{
3665 return expand_set_opt_string(
3666 args,
3667 p_ssop_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003668 ARRAY_LENGTH(p_ssop_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003669 numMatches,
3670 matches);
3671}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003672#endif
3673
3674/*
3675 * The 'shortmess' option is changed.
3676 */
3677 char *
3678did_set_shortmess(optset_T *args)
3679{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003680 char_u **varp = (char_u **)args->os_varp;
3681
Christian Brabandtb39b2402023-11-29 11:34:05 +01003682 return did_set_option_listflag(*varp, (char_u *)SHM_ALL, args->os_errbuf,
3683 args->os_errbuflen);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003684}
3685
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003686 int
3687expand_set_shortmess(optexpand_T *args, int *numMatches, char_u ***matches)
3688{
3689 return expand_set_opt_listflag(args, (char_u*)SHM_ALL, numMatches, matches);
3690}
3691
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003692#if defined(FEAT_LINEBREAK) || defined(PROTO)
3693/*
3694 * The 'showbreak' option is changed.
3695 */
3696 char *
3697did_set_showbreak(optset_T *args)
3698{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003699 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003700 char_u *s;
3701
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003702 for (s = *varp; *s; )
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003703 {
3704 if (ptr2cells(s) != 1)
3705 return e_showbreak_contains_unprintable_or_wide_character;
3706 MB_PTR_ADV(s);
3707 }
3708
3709 return NULL;
3710}
3711#endif
3712
3713/*
3714 * The 'showcmdloc' option is changed.
3715 */
3716 char *
3717did_set_showcmdloc(optset_T *args UNUSED)
3718{
zeertzjqc27fcf42024-03-01 23:01:43 +01003719 char *errmsg = did_set_opt_strings(p_sloc, p_sloc_values, FALSE);
3720
3721 if (errmsg == NULL)
3722 comp_col();
3723
3724 return errmsg;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003725}
3726
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003727 int
3728expand_set_showcmdloc(optexpand_T *args, int *numMatches, char_u ***matches)
3729{
3730 return expand_set_opt_string(
3731 args,
3732 p_sloc_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003733 ARRAY_LENGTH(p_sloc_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003734 numMatches,
3735 matches);
3736}
3737
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003738#if defined(FEAT_SIGNS) || defined(PROTO)
3739/*
3740 * The 'signcolumn' option is changed.
3741 */
3742 char *
3743did_set_signcolumn(optset_T *args)
3744{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003745 char_u **varp = (char_u **)args->os_varp;
3746
3747 if (check_opt_strings(*varp, p_scl_values, FALSE) != OK)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003748 return e_invalid_argument;
3749 // When changing the 'signcolumn' to or from 'number', recompute the
3750 // width of the number column if 'number' or 'relativenumber' is set.
3751 if (((*args->os_oldval.string == 'n' && args->os_oldval.string[1] == 'u')
3752 || (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) =='u'))
3753 && (curwin->w_p_nu || curwin->w_p_rnu))
3754 curwin->w_nrwidth_line_count = 0;
3755
3756 return NULL;
3757}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003758
3759 int
3760expand_set_signcolumn(optexpand_T *args, int *numMatches, char_u ***matches)
3761{
3762 return expand_set_opt_string(
3763 args,
3764 p_scl_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003765 ARRAY_LENGTH(p_scl_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003766 numMatches,
3767 matches);
3768}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003769#endif
3770
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003771#if defined(FEAT_SPELL) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003772/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003773 * The 'spellcapcheck' option is changed.
3774 */
3775 char *
3776did_set_spellcapcheck(optset_T *args UNUSED)
3777{
3778 // compile the regexp program.
3779 return compile_cap_prog(curwin->w_s);
3780}
3781
3782/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003783 * The 'spellfile' option is changed.
3784 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003785 char *
3786did_set_spellfile(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003787{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003788 char_u **varp = (char_u **)args->os_varp;
3789
3790 if (!valid_spellfile(*varp))
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003791 return e_invalid_argument;
3792
3793 // If there is a window for this buffer in which 'spell' is set load the
3794 // wordlists.
Milly322ad0c2024-10-14 20:21:48 +02003795 return did_set_spell_option();
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003796}
3797
3798/*
3799 * The 'spell' option is changed.
3800 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003801 char *
3802did_set_spelllang(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003803{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003804 char_u **varp = (char_u **)args->os_varp;
3805
3806 if (!valid_spelllang(*varp))
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003807 return e_invalid_argument;
3808
3809 // If there is a window for this buffer in which 'spell' is set load the
3810 // wordlists.
Milly322ad0c2024-10-14 20:21:48 +02003811 return did_set_spell_option();
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003812}
3813
3814/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003815 * The 'spelloptions' option is changed.
3816 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003817 char *
3818did_set_spelloptions(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003819{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00003820 char_u **varp = (char_u **)args->os_varp;
3821
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003822 if (**varp != NUL && STRCMP(*varp, "camel") != 0)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003823 return e_invalid_argument;
3824
3825 return NULL;
3826}
3827
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003828 int
3829expand_set_spelloptions(optexpand_T *args, int *numMatches, char_u ***matches)
3830{
3831 static char *(p_spo_values[]) = {"camel", NULL};
3832 return expand_set_opt_string(
3833 args,
3834 p_spo_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003835 ARRAY_LENGTH(p_spo_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003836 numMatches,
3837 matches);
3838}
3839
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003840/*
3841 * The 'spellsuggest' option is changed.
3842 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003843 char *
3844did_set_spellsuggest(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003845{
3846 if (spell_check_sps() != OK)
3847 return e_invalid_argument;
3848
3849 return NULL;
3850}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003851
3852 int
3853expand_set_spellsuggest(optexpand_T *args, int *numMatches, char_u ***matches)
3854{
3855 return expand_set_opt_string(
3856 args,
3857 p_sps_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003858 ARRAY_LENGTH(p_sps_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003859 numMatches,
3860 matches);
3861}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003862#endif
3863
3864/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003865 * The 'splitkeep' option is changed.
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00003866 */
3867 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003868did_set_splitkeep(optset_T *args UNUSED)
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00003869{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003870 return did_set_opt_strings(p_spk, p_spk_values, FALSE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003871}
3872
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003873 int
3874expand_set_splitkeep(optexpand_T *args, int *numMatches, char_u ***matches)
3875{
3876 return expand_set_opt_string(
3877 args,
3878 p_spk_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003879 ARRAY_LENGTH(p_spk_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003880 numMatches,
3881 matches);
3882}
3883
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00003884#if defined(FEAT_STL_OPT) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003885/*
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003886 * The 'statusline' option is changed.
3887 */
3888 char *
3889did_set_statusline(optset_T *args)
3890{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003891 return parse_statustabline_rulerformat(args, FALSE);
3892}
3893#endif
3894
3895/*
3896 * The 'swapsync' option is changed.
3897 */
3898 char *
3899did_set_swapsync(optset_T *args UNUSED)
3900{
3901 return did_set_opt_strings(p_sws, p_sws_values, FALSE);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003902}
3903
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003904 int
3905expand_set_swapsync(optexpand_T *args, int *numMatches, char_u ***matches)
3906{
3907 return expand_set_opt_string(
3908 args,
3909 p_sws_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003910 ARRAY_LENGTH(p_sws_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003911 numMatches,
3912 matches);
3913}
3914
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003915/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003916 * The 'switchbuf' option is changed.
3917 */
3918 char *
3919did_set_switchbuf(optset_T *args UNUSED)
3920{
3921 return did_set_opt_flags(p_swb, p_swb_values, &swb_flags, TRUE);
3922}
3923
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003924 int
3925expand_set_switchbuf(optexpand_T *args, int *numMatches, char_u ***matches)
3926{
3927 return expand_set_opt_string(
3928 args,
3929 p_swb_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02003930 ARRAY_LENGTH(p_swb_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003931 numMatches,
3932 matches);
3933}
3934
LemonBoy5247b0b2024-07-12 19:30:58 +02003935/*
3936 * The 'tabclose' option is changed.
3937 */
3938 char *
3939did_set_tabclose(optset_T *args UNUSED)
3940{
3941 return did_set_opt_flags(p_tcl, p_tcl_values, &tcl_flags, TRUE);
3942}
3943
3944 int
3945expand_set_tabclose(optexpand_T *args, int *numMatches, char_u ***matches)
3946{
3947 return expand_set_opt_string(
3948 args,
3949 p_tcl_values,
3950 ARRAY_LENGTH(p_tcl_values) - 1,
3951 numMatches,
3952 matches);
3953}
3954
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003955#if defined(FEAT_STL_OPT) || defined(PROTO)
3956/*
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003957 * The 'tabline' option is changed.
3958 */
3959 char *
3960did_set_tabline(optset_T *args)
3961{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00003962 return parse_statustabline_rulerformat(args, FALSE);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003963}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003964#endif
3965
3966/*
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003967 * The 'tagcase' option is changed.
3968 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003969 char *
3970did_set_tagcase(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003971{
3972 unsigned int *flags;
3973 char_u *p;
3974
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003975 if (args->os_flags & OPT_LOCAL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003976 {
3977 p = curbuf->b_p_tc;
3978 flags = &curbuf->b_tc_flags;
3979 }
3980 else
3981 {
3982 p = p_tc;
3983 flags = &tc_flags;
3984 }
3985
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003986 if ((args->os_flags & OPT_LOCAL) && *p == NUL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00003987 // make the local value empty: use the global value
3988 *flags = 0;
3989 else if (*p == NUL
3990 || opt_strings_flags(p, p_tc_values, flags, FALSE) != OK)
3991 return e_invalid_argument;
3992
3993 return NULL;
3994}
3995
Yee Cheng Chin900894b2023-09-29 20:42:32 +02003996 int
3997expand_set_tagcase(optexpand_T *args, int *numMatches, char_u ***matches)
3998{
3999 return expand_set_opt_string(
4000 args,
4001 p_tc_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004002 ARRAY_LENGTH(p_tc_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004003 numMatches,
4004 matches);
4005}
4006
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004007/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004008 * The 'term' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004009 */
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004010 char *
4011did_set_term(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004012{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004013 if (T_NAME[0] == NUL)
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004014 return e_cannot_set_term_to_empty_string;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004015#ifdef FEAT_GUI
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004016 if (gui.in_use)
4017 return e_cannot_change_term_in_GUI;
4018 if (term_is_gui(T_NAME))
4019 return e_use_gui_to_start_GUI;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004020#endif
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004021 if (set_termname(T_NAME) == FAIL)
4022 return e_not_found_in_termcap;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004023
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004024 // Screen colors may have changed.
4025 redraw_later_clear();
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004026
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004027 return NULL;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004028}
4029
4030/*
4031 * Some terminal option (t_xxx) is changed
4032 */
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004033 char *
4034did_set_term_option(optset_T *args)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004035{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004036 char_u **varp = (char_u **)args->os_varp;
4037
4038 if (!full_screen)
4039 return NULL;
4040
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004041 // ":set t_Co=0" and ":set t_Co=1" do ":set t_Co="
4042 if (varp == &T_CCO)
4043 {
4044 int colors = atoi((char *)T_CCO);
4045
4046 // Only reinitialize colors if t_Co value has really changed to
4047 // avoid expensive reload of colorscheme if t_Co is set to the
4048 // same value multiple times.
4049 if (colors != t_colors)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004050 {
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004051 t_colors = colors;
4052 if (t_colors <= 1)
4053 {
4054 vim_free(T_CCO);
4055 T_CCO = empty_option;
4056 }
4057#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
4058 if (is_term_win32())
4059 {
4060 swap_tcap();
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004061 args->os_did_swaptcap = TRUE;
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004062 }
4063#endif
4064 // We now have a different color setup, initialize it again.
4065 init_highlight(TRUE, FALSE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004066 }
4067 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004068 ttest(FALSE);
4069 if (varp == &T_ME)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004070 {
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004071 out_str(T_ME);
4072 redraw_later(UPD_CLEAR);
4073#if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL))
4074 // Since t_me has been set, this probably means that the user
4075 // wants to use this as default colors. Need to reset default
4076 // background/foreground colors.
4077# ifdef VIMDLL
4078 if (!gui.in_use && !gui.starting)
4079# endif
4080 mch_set_normal_colors();
4081#endif
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004082 }
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004083 if (varp == &T_BE && termcap_active)
4084 {
4085 MAY_WANT_TO_LOG_THIS;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004086
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004087 if (*T_BE == NUL)
4088 // When clearing t_BE we assume the user no longer wants
4089 // bracketed paste, thus disable it by writing t_BD.
4090 out_str(T_BD);
4091 else
4092 out_str(T_BE);
4093 }
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004094
4095 return NULL;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004096}
4097
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004098#if defined(FEAT_TERMINAL) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004099/*
4100 * The 'termwinkey' option is changed.
4101 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004102 char *
Milly94606f72024-10-22 22:07:52 +02004103did_set_termwinkey(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004104{
Milly94606f72024-10-22 22:07:52 +02004105 char_u **varp = (char_u **)args->os_varp;
4106
4107 if ((*varp)[0] != NUL && string_to_key(*varp, TRUE) == 0)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004108 return e_invalid_argument;
4109
4110 return NULL;
4111}
4112
4113/*
4114 * The 'termwinsize' option is changed.
4115 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004116 char *
Milly8be10aa2024-10-22 22:01:46 +02004117did_set_termwinsize(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004118{
Milly8be10aa2024-10-22 22:01:46 +02004119 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004120 char_u *p;
4121
Milly8be10aa2024-10-22 22:01:46 +02004122 if ((*varp)[0] == NUL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004123 return NULL;
4124
Milly8be10aa2024-10-22 22:01:46 +02004125 p = skipdigits(*varp);
4126 if (p == *varp || (*p != 'x' && *p != '*') || *skipdigits(p + 1) != NUL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004127 return e_invalid_argument;
4128
4129 return NULL;
4130}
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00004131
4132# if defined(MSWIN) || defined(PROTO)
4133/*
4134 * The 'termwintype' option is changed.
4135 */
4136 char *
4137did_set_termwintype(optset_T *args UNUSED)
4138{
4139 return did_set_opt_strings(p_twt, p_twt_values, FALSE);
4140}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004141
4142 int
4143expand_set_termwintype(optexpand_T *args, int *numMatches, char_u ***matches)
4144{
4145 return expand_set_opt_string(
4146 args,
4147 p_twt_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004148 ARRAY_LENGTH(p_twt_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004149 numMatches,
4150 matches);
4151}
Yegappan Lakshmanan8ad862a2023-02-23 15:05:22 +00004152# endif
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004153#endif
4154
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004155/*
4156 * The 'titlestring' option is changed.
4157 */
4158 char *
4159did_set_titlestring(optset_T *args)
4160{
4161 int flagval = 0;
4162
4163#ifdef FEAT_STL_OPT
4164 flagval = STL_IN_TITLE;
4165#endif
4166 return parse_titleiconstring(args, flagval);
4167}
4168
4169#if (defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)) || defined(PROTO)
4170/*
4171 * The 'toolbar' option is changed.
4172 */
4173 char *
4174did_set_toolbar(optset_T *args UNUSED)
4175{
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004176 if (opt_strings_flags(p_toolbar, p_toolbar_values, &toolbar_flags,
4177 TRUE) != OK)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004178 return e_invalid_argument;
4179
4180 out_flush();
4181 gui_mch_show_toolbar((toolbar_flags &
4182 (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
4183 return NULL;
4184}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004185
4186 int
4187expand_set_toolbar(optexpand_T *args, int *numMatches, char_u ***matches)
4188{
4189 return expand_set_opt_string(
4190 args,
4191 p_toolbar_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004192 ARRAY_LENGTH(p_toolbar_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004193 numMatches,
4194 matches);
4195}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004196#endif
4197
4198#if (defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)) || defined(PROTO)
4199/*
4200 * The 'toolbariconsize' option is changed. GTK+ 2 only.
4201 */
4202 char *
4203did_set_toolbariconsize(optset_T *args UNUSED)
4204{
4205 if (opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE) != OK)
4206 return e_invalid_argument;
4207
4208 out_flush();
4209 gui_mch_show_toolbar((toolbar_flags &
4210 (TOOLBAR_TEXT | TOOLBAR_ICONS)) != 0);
4211 return NULL;
4212}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004213
4214 int
4215expand_set_toolbariconsize(optexpand_T *args, int *numMatches, char_u ***matches)
4216{
4217 return expand_set_opt_string(
4218 args,
4219 p_tbis_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004220 ARRAY_LENGTH(p_tbis_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004221 numMatches,
4222 matches);
4223}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004224#endif
4225
4226#if defined(UNIX) || defined(VMS) || defined(PROTO)
4227/*
4228 * The 'ttymouse' option is changed.
4229 */
4230 char *
4231did_set_ttymouse(optset_T *args UNUSED)
4232{
4233 char *errmsg = NULL;
4234
4235 // Switch the mouse off before changing the escape sequences used for
4236 // that.
4237 mch_setmouse(FALSE);
4238 if (opt_strings_flags(p_ttym, p_ttym_values, &ttym_flags, FALSE) != OK)
4239 errmsg = e_invalid_argument;
4240 else
4241 check_mouse_termcode();
4242 if (termcap_active)
4243 setmouse(); // may switch it on again
4244
4245 return errmsg;
4246}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004247
4248 int
4249expand_set_ttymouse(optexpand_T *args, int *numMatches, char_u ***matches)
4250{
4251 return expand_set_opt_string(
4252 args,
4253 p_ttym_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004254 ARRAY_LENGTH(p_ttym_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004255 numMatches,
4256 matches);
4257}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004258#endif
4259
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004260#if defined(FEAT_VARTABS) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004261/*
4262 * The 'varsofttabstop' option is changed.
4263 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004264 char *
4265did_set_varsofttabstop(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004266{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004267 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004268 char_u *cp;
4269
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004270 if (!((*varp)[0]) || ((*varp)[0] == '0' && !((*varp)[1])))
Yegappan Lakshmanan960dcbd2023-03-07 17:45:11 +00004271 VIM_CLEAR(curbuf->b_p_vsts_array);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004272 else
4273 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004274 for (cp = *varp; *cp; ++cp)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004275 {
4276 if (vim_isdigit(*cp))
4277 continue;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004278 if (*cp == ',' && cp > *varp && *(cp-1) != ',')
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004279 continue;
4280 return e_invalid_argument;
4281 }
4282
4283 int *oldarray = curbuf->b_p_vsts_array;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004284 if (tabstop_set(*varp, &(curbuf->b_p_vsts_array)) == OK)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004285 {
4286 if (oldarray)
4287 vim_free(oldarray);
4288 }
4289 else
4290 return e_invalid_argument;
4291 }
4292
4293 return NULL;
4294}
4295
4296/*
4297 * The 'vartabstop' option is changed.
4298 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004299 char *
4300did_set_vartabstop(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004301{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004302 char_u **varp = (char_u **)args->os_varp;
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004303 char_u *cp;
4304
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004305 if (!((*varp)[0]) || ((*varp)[0] == '0' && !((*varp)[1])))
Yegappan Lakshmanan960dcbd2023-03-07 17:45:11 +00004306 VIM_CLEAR(curbuf->b_p_vts_array);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004307 else
4308 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004309 for (cp = *varp; *cp; ++cp)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004310 {
4311 if (vim_isdigit(*cp))
4312 continue;
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004313 if (*cp == ',' && cp > *varp && *(cp-1) != ',')
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004314 continue;
4315 return e_invalid_argument;
4316 }
4317
4318 int *oldarray = curbuf->b_p_vts_array;
4319
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004320 if (tabstop_set(*varp, &(curbuf->b_p_vts_array)) == OK)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004321 {
4322 vim_free(oldarray);
4323# ifdef FEAT_FOLDING
4324 if (foldmethodIsIndent(curwin))
4325 foldUpdateAll(curwin);
4326# endif
4327 }
4328 else
4329 return e_invalid_argument;
4330 }
4331
4332 return NULL;
4333}
4334#endif
4335
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004336/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004337 * The 'verbosefile' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004338 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004339 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004340did_set_verbosefile(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004341{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004342 verbose_stop();
4343 if (*p_vfile != NUL && verbose_open() == FAIL)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004344 return e_invalid_argument;
4345
4346 return NULL;
4347}
4348
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004349#if defined(FEAT_SESSION) || defined(PROTO)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004350/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004351 * The 'viewoptions' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004352 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004353 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004354did_set_viewoptions(optset_T *args UNUSED)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004355{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004356 return did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004357}
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004358#endif
4359
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004360#if defined(FEAT_VIMINFO) || defined(PROTO)
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004361/*
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004362 * The 'viminfo' option is changed.
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004363 */
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004364 char *
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004365did_set_viminfo(optset_T *args)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004366{
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004367 char_u *s;
4368 char *errmsg = NULL;
4369
4370 for (s = p_viminfo; *s;)
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004371 {
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004372 // Check it's a valid character
4373 if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL)
4374 {
Christian Brabandtb39b2402023-11-29 11:34:05 +01004375 errmsg = illegal_char(args->os_errbuf, args->os_errbuflen, *s);
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004376 break;
4377 }
4378 if (*s == 'n') // name is always last one
4379 break;
4380 else if (*s == 'r') // skip until next ','
4381 {
4382 while (*++s && *s != ',')
4383 ;
4384 }
4385 else if (*s == '%')
4386 {
4387 // optional number
4388 while (vim_isdigit(*++s))
4389 ;
4390 }
4391 else if (*s == '!' || *s == 'h' || *s == 'c')
4392 ++s; // no extra chars
4393 else // must have a number
4394 {
4395 while (vim_isdigit(*++s))
4396 ;
4397
4398 if (!VIM_ISDIGIT(*(s - 1)))
4399 {
4400 if (args->os_errbuf != NULL)
4401 {
Zoltan Arpadffy1c8e2332023-12-05 16:04:23 +01004402 vim_snprintf(args->os_errbuf, args->os_errbuflen,
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004403 _(e_missing_number_after_angle_str_angle),
4404 transchar_byte(*(s - 1)));
4405 errmsg = args->os_errbuf;
4406 }
4407 else
4408 errmsg = "";
4409 break;
4410 }
4411 }
4412 if (*s == ',')
4413 ++s;
4414 else if (*s)
4415 {
4416 if (args->os_errbuf != NULL)
4417 errmsg = e_missing_comma;
4418 else
4419 errmsg = "";
4420 break;
4421 }
4422 }
4423 if (*p_viminfo && errmsg == NULL && get_viminfo_parameter('\'') < 0)
4424 errmsg = e_must_specify_a_value;
4425
4426 return errmsg;
4427}
4428#endif
4429
4430/*
4431 * The 'virtualedit' option is changed.
4432 */
4433 char *
4434did_set_virtualedit(optset_T *args)
4435{
4436 char_u *ve = p_ve;
4437 unsigned int *flags = &ve_flags;
4438
4439 if (args->os_flags & OPT_LOCAL)
4440 {
4441 ve = curwin->w_p_ve;
4442 flags = &curwin->w_ve_flags;
4443 }
4444
4445 if ((args->os_flags & OPT_LOCAL) && *ve == NUL)
4446 // make the local value empty: use the global value
4447 *flags = 0;
4448 else
4449 {
4450 if (opt_strings_flags(ve, p_ve_values, flags, TRUE) != OK)
4451 return e_invalid_argument;
4452 else if (STRCMP(ve, args->os_oldval.string) != 0)
4453 {
4454 // Recompute cursor position in case the new 've' setting
4455 // changes something.
4456 validate_virtcol();
4457 coladvance(curwin->w_virtcol);
4458 }
Yegappan Lakshmananf2e30d02023-01-30 13:04:42 +00004459 }
4460
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004461 return NULL;
4462}
4463
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004464 int
4465expand_set_virtualedit(optexpand_T *args, int *numMatches, char_u ***matches)
4466{
4467 return expand_set_opt_string(
4468 args,
4469 p_ve_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004470 ARRAY_LENGTH(p_ve_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004471 numMatches,
4472 matches);
4473}
4474
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004475/*
4476 * The 'whichwrap' option is changed.
4477 */
4478 char *
4479did_set_whichwrap(optset_T *args)
4480{
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004481 char_u **varp = (char_u **)args->os_varp;
4482
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004483 // Add ',' to the list flags because 'whichwrap' is a flag
4484 // list that is comma-separated.
Christian Brabandtb39b2402023-11-29 11:34:05 +01004485 return did_set_option_listflag(*varp, (char_u *)(WW_ALL ","),
4486 args->os_errbuf, args->os_errbuflen);
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004487}
4488
4489 int
4490expand_set_whichwrap(optexpand_T *args, int *numMatches, char_u ***matches)
4491{
4492 return expand_set_opt_listflag(args, (char_u*)WW_ALL, numMatches, matches);
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004493}
4494
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004495/*
4496 * The 'wildmode' option is changed.
4497 */
4498 char *
4499did_set_wildmode(optset_T *args UNUSED)
4500{
4501 if (check_opt_wim() == FAIL)
4502 return e_invalid_argument;
4503 return NULL;
4504}
4505
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004506 int
4507expand_set_wildmode(optexpand_T *args, int *numMatches, char_u ***matches)
4508{
4509 return expand_set_opt_string(
4510 args,
4511 p_wim_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004512 ARRAY_LENGTH(p_wim_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004513 numMatches,
4514 matches);
4515}
4516
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004517/*
4518 * The 'wildoptions' option is changed.
4519 */
4520 char *
4521did_set_wildoptions(optset_T *args UNUSED)
4522{
4523 return did_set_opt_strings(p_wop, p_wop_values, TRUE);
4524}
4525
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004526 int
4527expand_set_wildoptions(optexpand_T *args, int *numMatches, char_u ***matches)
4528{
4529 return expand_set_opt_string(
4530 args,
4531 p_wop_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004532 ARRAY_LENGTH(p_wop_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004533 numMatches,
4534 matches);
4535}
4536
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004537#if defined(FEAT_WAK) || defined(PROTO)
4538/*
4539 * The 'winaltkeys' option is changed.
4540 */
4541 char *
4542did_set_winaltkeys(optset_T *args UNUSED)
4543{
4544 char *errmsg = NULL;
4545
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004546 if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, FALSE) != OK)
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004547 errmsg = e_invalid_argument;
4548# ifdef FEAT_MENU
4549# if defined(FEAT_GUI_MOTIF)
4550 else if (gui.in_use)
4551 gui_motif_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
4552# elif defined(FEAT_GUI_GTK)
4553 else if (gui.in_use)
4554 gui_gtk_set_mnemonics(p_wak[0] == 'y' || p_wak[0] == 'm');
4555# endif
4556# endif
4557 return errmsg;
4558}
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004559
4560 int
4561expand_set_winaltkeys(optexpand_T *args, int *numMatches, char_u ***matches)
4562{
4563 return expand_set_opt_string(
4564 args,
4565 p_wak_values,
Yee Cheng Chin6d113472023-10-02 21:38:39 +02004566 ARRAY_LENGTH(p_wak_values) - 1,
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004567 numMatches,
4568 matches);
4569}
Yegappan Lakshmananad608982023-03-01 12:44:06 +00004570#endif
4571
4572/*
4573 * The 'wincolor' option is changed.
4574 */
4575 char *
4576did_set_wincolor(optset_T *args UNUSED)
4577{
4578#ifdef FEAT_TERMINAL
4579 term_update_wincolor(curwin);
4580#endif
4581 return NULL;
4582}
4583
Yee Cheng Chin900894b2023-09-29 20:42:32 +02004584 int
4585expand_set_wincolor(optexpand_T *args, int *numMatches, char_u ***matches)
4586{
4587 return expand_set_opt_generic(
4588 args,
4589 get_highlight_name,
4590 numMatches,
4591 matches);
4592}
4593
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004594#ifdef FEAT_SYN_HL
4595/*
4596 * When the 'syntax' option is set, load the syntax of that name.
4597 */
4598 static void
4599do_syntax_autocmd(int value_changed)
4600{
4601 static int syn_recursive = 0;
4602
4603 ++syn_recursive;
4604 // Only pass TRUE for "force" when the value changed or not used
4605 // recursively, to avoid endless recurrence.
4606 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
4607 value_changed || syn_recursive == 1, curbuf);
4608 curbuf->b_flags |= BF_SYN_SET;
4609 --syn_recursive;
4610}
4611#endif
4612
4613/*
4614 * When the 'filetype' option is set, trigger the FileType autocommand.
4615 */
4616 static void
4617do_filetype_autocmd(char_u **varp, int opt_flags, int value_changed)
4618{
4619 // Skip this when called from a modeline and the filetype was already set
4620 // to this value.
4621 if ((opt_flags & OPT_MODELINE) && !value_changed)
4622 return;
4623
4624 static int ft_recursive = 0;
4625 int secure_save = secure;
4626
4627 // Reset the secure flag, since the value of 'filetype' has
4628 // been checked to be safe.
4629 secure = 0;
4630
4631 ++ft_recursive;
zeertzjq5bf6c212024-03-31 18:41:27 +02004632 curbuf->b_did_filetype = TRUE;
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004633 // Only pass TRUE for "force" when the value changed or not
4634 // used recursively, to avoid endless recurrence.
4635 apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname,
4636 value_changed || ft_recursive == 1, curbuf);
4637 --ft_recursive;
4638 // Just in case the old "curbuf" is now invalid.
4639 if (varp != &(curbuf->b_p_ft))
4640 varp = NULL;
4641
4642 secure = secure_save;
4643}
4644
4645#ifdef FEAT_SPELL
4646/*
4647 * When the 'spelllang' option is set, source the spell/LANG.vim file in
4648 * 'runtimepath'.
4649 */
4650 static void
4651do_spelllang_source(void)
4652{
4653 char_u fname[200];
4654 char_u *p;
4655 char_u *q = curwin->w_s->b_p_spl;
4656
4657 // Skip the first name if it is "cjk".
4658 if (STRNCMP(q, "cjk,", 4) == 0)
4659 q += 4;
4660
4661 // They could set 'spellcapcheck' depending on the language. Use the first
4662 // name in 'spelllang' up to '_region' or '.encoding'.
4663 for (p = q; *p != NUL; ++p)
4664 if (!ASCII_ISALNUM(*p) && *p != '-')
4665 break;
4666 if (p > q)
4667 {
4668 vim_snprintf((char *)fname, 200, "spell/%.*s.vim",
4669 (int)(p - q), q);
4670 source_runtime(fname, DIP_ALL);
4671 }
4672}
4673#endif
4674
4675/*
Bram Moolenaardac13472019-09-16 21:06:21 +02004676 * Handle string options that need some action to perform when changed.
zeertzjqf6782732022-07-27 18:26:03 +01004677 * The new value must be allocated.
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004678 * Returns NULL for success, or an untranslated error message for an error.
Bram Moolenaardac13472019-09-16 21:06:21 +02004679 */
4680 char *
4681did_set_string_option(
4682 int opt_idx, // index in options[] table
4683 char_u **varp, // pointer to the option variable
Bram Moolenaardac13472019-09-16 21:06:21 +02004684 char_u *oldval, // previous value of the option
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004685 char_u *value, // new value of the option
Bram Moolenaardac13472019-09-16 21:06:21 +02004686 char *errbuf, // buffer for errors, or NULL
Mike Williams620f0112023-12-05 15:36:06 +01004687 size_t errbuflen, // length of error buffer
Bram Moolenaardac13472019-09-16 21:06:21 +02004688 int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL
Yee Cheng Chin6ee7b522023-10-01 09:13:22 +02004689 set_op_T op, // OP_ADDING/OP_PREPENDING/OP_REMOVING
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004690 int *value_checked) // value was checked to be safe, no
Bram Moolenaardac13472019-09-16 21:06:21 +02004691 // need to set P_INSECURE
4692{
4693 char *errmsg = NULL;
Bram Moolenaardac13472019-09-16 21:06:21 +02004694 long_u free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004695 opt_did_set_cb_T did_set_cb = get_option_did_set_cb(opt_idx);
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004696 optset_T args;
4697
4698 // 'ttytype' is an alias for 'term'. Both 'term' and 'ttytype' point to
4699 // T_NAME. If 'term' or 'ttytype' is modified, then use the index for the
4700 // 'term' option. Only set the P_ALLOCED flag on 'term'.
4701 if (varp == &T_NAME)
4702 {
4703 opt_idx = findoption((char_u *)"term");
4704 if (opt_idx >= 0)
4705 {
4706 free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
4707 did_set_cb = get_option_did_set_cb(opt_idx);
4708 }
4709 }
4710
4711 CLEAR_FIELD(args);
Bram Moolenaardac13472019-09-16 21:06:21 +02004712
Bram Moolenaardac13472019-09-16 21:06:21 +02004713 // Disallow changing some options from secure mode
4714 if ((secure
4715#ifdef HAVE_SANDBOX
4716 || sandbox != 0
4717#endif
4718 ) && (get_option_flags(opt_idx) & P_SECURE))
Bram Moolenaar74409f62022-01-01 15:58:22 +00004719 errmsg = e_not_allowed_here;
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004720 // Check for a "normal" directory or file name in some options.
4721 else if (check_illegal_path_names(opt_idx, varp))
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004722 errmsg = e_invalid_argument;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004723 else if (did_set_cb != NULL)
4724 {
Yegappan Lakshmananc727b192023-03-03 12:26:15 +00004725 args.os_varp = (char_u *)varp;
4726 args.os_idx = opt_idx;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004727 args.os_flags = opt_flags;
Yee Cheng Chin6ee7b522023-10-01 09:13:22 +02004728 args.os_op = op;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004729 args.os_oldval.string = oldval;
4730 args.os_newval.string = value;
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004731 args.os_errbuf = errbuf;
Christian Brabandtb39b2402023-11-29 11:34:05 +01004732 args.os_errbuflen = errbuflen;
Yegappan Lakshmanan5da901b2023-02-27 12:47:47 +00004733 // Invoke the option specific callback function to validate and apply
4734 // the new option value.
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004735 errmsg = did_set_cb(&args);
Yegappan Lakshmanan5da901b2023-02-27 12:47:47 +00004736
Yegappan Lakshmanan5da901b2023-02-27 12:47:47 +00004737 // The 'keymap', 'filetype' and 'syntax' option callback functions
4738 // may change the os_value_checked field.
4739 *value_checked = args.os_value_checked;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004740 }
Bram Moolenaardac13472019-09-16 21:06:21 +02004741
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004742 // If an error is detected, restore the previous value.
Bram Moolenaardac13472019-09-16 21:06:21 +02004743 if (errmsg != NULL)
4744 {
zeertzjqf6782732022-07-27 18:26:03 +01004745 free_string_option(*varp);
Bram Moolenaardac13472019-09-16 21:06:21 +02004746 *varp = oldval;
4747 // When resetting some values, need to act on it.
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004748 if (args.os_restore_chartab)
Bram Moolenaardac13472019-09-16 21:06:21 +02004749 (void)init_chartab();
4750 if (varp == &p_hl)
4751 (void)highlight_changed();
4752 }
4753 else
4754 {
4755#ifdef FEAT_EVAL
4756 // Remember where the option was set.
4757 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
4758#endif
4759 // Free string options that are in allocated memory.
4760 // Use "free_oldval", because recursiveness may change the flags under
4761 // our fingers (esp. init_highlight()).
4762 if (free_oldval)
4763 free_string_option(oldval);
zeertzjqf6782732022-07-27 18:26:03 +01004764 set_option_flag(opt_idx, P_ALLOCED);
Bram Moolenaardac13472019-09-16 21:06:21 +02004765
4766 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
4767 && is_global_local_option(opt_idx))
4768 {
4769 // global option with local value set to use global value; free
4770 // the local value and make it empty
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004771 char_u *p = get_option_varp_scope(opt_idx, OPT_LOCAL);
Bram Moolenaardac13472019-09-16 21:06:21 +02004772 free_string_option(*(char_u **)p);
4773 *(char_u **)p = empty_option;
4774 }
4775
4776 // May set global value for local option.
4777 else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL)
4778 set_string_option_global(opt_idx, varp);
4779
4780 // Trigger the autocommand only after setting the flags.
4781#ifdef FEAT_SYN_HL
Bram Moolenaardac13472019-09-16 21:06:21 +02004782 if (varp == &(curbuf->b_p_syn))
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004783 do_syntax_autocmd(args.os_value_changed);
Bram Moolenaardac13472019-09-16 21:06:21 +02004784#endif
4785 else if (varp == &(curbuf->b_p_ft))
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004786 do_filetype_autocmd(varp, opt_flags, args.os_value_changed);
Bram Moolenaardac13472019-09-16 21:06:21 +02004787#ifdef FEAT_SPELL
4788 if (varp == &(curwin->w_s->b_p_spl))
Yegappan Lakshmanand6e4c752023-01-31 13:25:58 +00004789 do_spelllang_source();
Bram Moolenaardac13472019-09-16 21:06:21 +02004790#endif
4791 }
4792
Bram Moolenaardac13472019-09-16 21:06:21 +02004793 if (varp == &p_mouse)
4794 {
Bram Moolenaardac13472019-09-16 21:06:21 +02004795 if (*p_mouse == NUL)
4796 mch_setmouse(FALSE); // switch mouse off
4797 else
Bram Moolenaardac13472019-09-16 21:06:21 +02004798 setmouse(); // in case 'mouse' changed
4799 }
Bram Moolenaardac13472019-09-16 21:06:21 +02004800
Bram Moolenaar788fbb42020-05-31 14:08:12 +02004801 if (varp == &p_rtp)
Christian Brabandt3e2affc2025-02-28 17:34:46 +01004802 {
4803 export_myvimdir();
4804#if defined(FEAT_LUA) || defined(PROTO)
Bram Moolenaar788fbb42020-05-31 14:08:12 +02004805 update_package_paths_in_lua();
4806#endif
Christian Brabandt3e2affc2025-02-28 17:34:46 +01004807 }
Bram Moolenaar788fbb42020-05-31 14:08:12 +02004808
Bram Moolenaarb2d85e32022-01-07 16:55:32 +00004809#if defined(FEAT_LINEBREAK)
4810 // Changing Formatlistpattern when briopt includes the list setting:
4811 // redraw
4812 if ((varp == &p_flp || varp == &(curbuf->b_p_flp))
4813 && curwin->w_briopt_list)
Bram Moolenaara4d158b2022-08-14 14:17:45 +01004814 redraw_all_later(UPD_NOT_VALID);
Bram Moolenaarb2d85e32022-01-07 16:55:32 +00004815#endif
4816
Bram Moolenaardac13472019-09-16 21:06:21 +02004817 if (curwin->w_curswant != MAXCOL
zeertzjqfcaed6a2024-02-18 09:33:54 +01004818 && (get_option_flags(opt_idx) & (P_CURSWANT | P_RALL)) != 0
4819 && (get_option_flags(opt_idx) & P_HLONLY) == 0)
Bram Moolenaardac13472019-09-16 21:06:21 +02004820 curwin->w_set_curswant = TRUE;
4821
Bram Moolenaar37294bd2021-03-10 13:40:08 +01004822 if ((opt_flags & OPT_NO_REDRAW) == 0)
4823 {
Bram Moolenaardac13472019-09-16 21:06:21 +02004824#ifdef FEAT_GUI
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004825 // set when changing an option that only requires a redraw in the GUI
4826 int redraw_gui_only = FALSE;
4827
4828 if (varp == &p_go // 'guioptions'
4829 || varp == &p_guifont // 'guifont'
4830# ifdef FEAT_GUI_TABLINE
4831 || varp == &p_gtl // 'guitablabel'
4832 || varp == &p_gtt // 'guitabtooltip'
4833# endif
4834# ifdef FEAT_XFONTSET
4835 || varp == &p_guifontset // 'guifontset'
4836# endif
4837 || varp == &p_guifontwide // 'guifontwide'
Erik S. V. Jansson2f026382024-02-26 22:23:05 +01004838# if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MSWIN)
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004839 || varp == &p_guiligatures // 'guiligatures'
4840# endif
4841 )
4842 redraw_gui_only = TRUE;
4843
Bram Moolenaar37294bd2021-03-10 13:40:08 +01004844 // check redraw when it's not a GUI option or the GUI is active.
4845 if (!redraw_gui_only || gui.in_use)
Bram Moolenaardac13472019-09-16 21:06:21 +02004846#endif
Bram Moolenaar37294bd2021-03-10 13:40:08 +01004847 check_redraw(get_option_flags(opt_idx));
4848 }
Bram Moolenaardac13472019-09-16 21:06:21 +02004849
4850#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004851 if (args.os_did_swaptcap)
Bram Moolenaardac13472019-09-16 21:06:21 +02004852 {
4853 set_termname((char_u *)"win32");
4854 init_highlight(TRUE, FALSE);
4855 }
4856#endif
4857
4858 return errmsg;
4859}
4860
4861/*
4862 * Check an option that can be a range of string values.
4863 *
4864 * Return OK for correct value, FAIL otherwise.
4865 * Empty is always OK.
4866 */
4867 static int
4868check_opt_strings(
4869 char_u *val,
4870 char **values,
4871 int list) // when TRUE: accept a list of values
4872{
4873 return opt_strings_flags(val, values, NULL, list);
4874}
4875
4876/*
4877 * Handle an option that can be a range of string values.
4878 * Set a flag in "*flagp" for each string present.
4879 *
4880 * Return OK for correct value, FAIL otherwise.
4881 * Empty is always OK.
4882 */
4883 static int
4884opt_strings_flags(
4885 char_u *val, // new value
4886 char **values, // array of valid string values
4887 unsigned *flagp,
4888 int list) // when TRUE: accept a list of values
4889{
4890 int i;
4891 int len;
4892 unsigned new_flags = 0;
4893
4894 while (*val)
4895 {
4896 for (i = 0; ; ++i)
4897 {
4898 if (values[i] == NULL) // val not found in values[]
4899 return FAIL;
4900
4901 len = (int)STRLEN(values[i]);
4902 if (STRNCMP(values[i], val, len) == 0
4903 && ((list && val[len] == ',') || val[len] == NUL))
4904 {
4905 val += len + (val[len] == ',');
4906 new_flags |= (1 << i);
4907 break; // check next item in val list
4908 }
4909 }
4910 }
4911 if (flagp != NULL)
4912 *flagp = new_flags;
4913
4914 return OK;
4915}
4916
4917/*
4918 * return OK if "p" is a valid fileformat name, FAIL otherwise.
4919 */
4920 int
4921check_ff_value(char_u *p)
4922{
4923 return check_opt_strings(p, p_ff_values, FALSE);
4924}
Christian Brabandt9aee8ec2022-12-16 16:41:23 +00004925
4926/*
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004927 * Save the actual shortmess Flags and clear them temporarily to avoid that
4928 * file messages overwrites any output from the following commands.
Christian Brabandt9aee8ec2022-12-16 16:41:23 +00004929 *
4930 * Caller must make sure to first call save_clear_shm_value() and then
4931 * restore_shm_value() exactly the same number of times.
4932 */
4933 void
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +00004934save_clear_shm_value(void)
Christian Brabandt9aee8ec2022-12-16 16:41:23 +00004935{
4936 if (STRLEN(p_shm) >= SHM_LEN)
4937 {
4938 iemsg(e_internal_error_shortmess_too_long);
4939 return;
4940 }
4941
4942 if (++set_shm_recursive == 1)
4943 {
4944 STRCPY(shm_buf, p_shm);
4945 set_option_value_give_err((char_u *)"shm", 0L, (char_u *)"", 0);
4946 }
4947}
4948
4949/*
4950 * Restore the shortmess Flags set from the save_clear_shm_value() function.
4951 */
4952 void
Yegappan Lakshmanana23a11b2023-02-21 14:27:41 +00004953restore_shm_value(void)
Christian Brabandt9aee8ec2022-12-16 16:41:23 +00004954{
4955 if (--set_shm_recursive == 0)
4956 {
4957 set_option_value_give_err((char_u *)"shm", 0L, shm_buf, 0);
4958 vim_memset(shm_buf, 0, SHM_LEN);
4959 }
4960}
Christian Brabandt3e2affc2025-02-28 17:34:46 +01004961
4962/*
4963 * Export the environment variable $MYVIMDIR to the first item in runtimepath
4964 */
Christian Brabandt1a741d32025-03-01 16:30:33 +01004965 void
Christian Brabandt3e2affc2025-02-28 17:34:46 +01004966export_myvimdir()
4967{
4968 int dofree = FALSE;
4969 char_u *p;
4970 char_u *q = p_rtp;
4971 char_u *buf = alloc(MAXPATHL);
4972
4973 if (buf == NULL)
4974 return;
4975
4976 (void)copy_option_part(&q, buf, MAXPATHL, ",");
4977
4978 p = vim_getenv((char_u *)"MYVIMDIR", &dofree);
4979
4980 if (p == NULL || STRCMP(p, buf) != 0)
4981 {
4982 add_pathsep(buf);
4983#ifdef MSWIN
4984 // normalize path separators
4985 for (q = buf; *q != NUL; q++)
4986 if (*q == '/')
4987 *q = '\\';
4988#endif
4989 vim_setenv((char_u *)"MYVIMDIR", buf);
4990 }
4991 if (dofree)
4992 vim_free(p);
4993 vim_free(buf);
4994}