blob: 0cd2823851eea46dd3c32ec7ca3fa2bce64080a4 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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 * Code to handle user-settable options. This is all pretty much table-
12 * driven. Checklist for adding a new option:
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +000013 * - Put it in the options array in optiondefs.h (copy an existing entry).
Bram Moolenaar071d4272004-06-13 20:20:40 +000014 * - For a global option: Add a variable for it in option.h.
15 * - For a buffer or window local option:
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +000016 * - Add a PV_XX macro definition to the optiondefs.h file.
Bram Moolenaar071d4272004-06-13 20:20:40 +000017 * - Add a variable to the window or buffer struct in structs.h.
18 * - For a window option, add some code to copy_winopt().
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +000019 * - For a window string option, add code to check_win_options() and
20 * clear_winopt().
Bram Moolenaar071d4272004-06-13 20:20:40 +000021 * - For a buffer option, add some code to buf_copy_options().
22 * - For a buffer string option, add code to check_buf_options().
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +000023 * - If it's a numeric option, add any necessary bounds checks to
24 * set_num_option().
25 * - If it's a list of flags, add some code in did_set_string_option(), search
26 * for WW_ALL.
Bram Moolenaar071d4272004-06-13 20:20:40 +000027 * - When adding an option with expansion (P_EXPAND), but with a different
28 * default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
Bram Moolenaarcea912a2016-10-12 14:20:24 +020029 * - Add documentation! One line in doc/quickref.txt, full description in
Bram Moolenaar071d4272004-06-13 20:20:40 +000030 * options.txt, and any other related places.
31 * - Add an entry in runtime/optwin.vim.
32 * When making changes:
33 * - Adjust the help for the option in doc/option.txt.
34 * - When an entry has the P_VIM flag, or is lacking the P_VI_DEF flag, add a
35 * comment at the help for the 'compatible' option.
36 */
37
38#define IN_OPTION_C
39#include "vim.h"
Bram Moolenaar0eddca42019-09-12 22:26:43 +020040#include "optiondefs.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000041
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010042static void set_options_default(int opt_flags);
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +010043static void set_string_default_esc(char *name, char_u *val, int escape);
Bram Moolenaarb00ef052020-09-12 14:53:53 +020044static char_u *find_dup_item(char_u *origval, char_u *newval, long_u flags);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010045static char_u *option_expand(int opt_idx, char_u *val);
46static void didset_options(void);
47static void didset_options2(void);
Bram Moolenaard1f56e62006-02-22 21:25:37 +000048#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010049static long_u *insecure_flag(int opt_idx, int opt_flags);
Bram Moolenaard1f56e62006-02-22 21:25:37 +000050#else
51# define insecure_flag(opt_idx, opt_flags) (&options[opt_idx].flags)
52#endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010053static char *set_bool_option(int opt_idx, char_u *varp, int value, int opt_flags);
54static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, size_t errbuflen, int opt_flags);
Bram Moolenaar9cf4b502018-07-23 04:12:03 +020055static int find_key_option(char_u *arg_arg, int has_lt);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010056static void showoptions(int all, int opt_flags);
Bram Moolenaarcacc6a52019-05-30 15:22:43 +020057static int optval_default(struct vimoption *, char_u *varp, int compatible);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010058static void showoneopt(struct vimoption *, int opt_flags);
Bram Moolenaared18f2c2019-01-24 20:30:52 +010059static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, long_u flags);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010060static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep);
61static int put_setbool(FILE *fd, char *cmd, char *name, int value);
Bram Moolenaardac13472019-09-16 21:06:21 +020062static int istermoption(struct vimoption *p);
Yegappan Lakshmanan64095532021-12-06 11:03:55 +000063static char_u *get_varp_scope(struct vimoption *p, int scope);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010064static char_u *get_varp(struct vimoption *);
Bram Moolenaar5843f5f2019-08-20 20:13:45 +020065static void check_win_options(win_T *win);
Yegappan Lakshmanan64095532021-12-06 11:03:55 +000066static void option_value2string(struct vimoption *, int scope);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010067static void check_winopt(winopt_T *wop);
68static int wc_use_keyname(char_u *varp, long *wcp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010069static void compatible_set(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000070
Christian Brabandt757593c2023-08-22 21:44:10 +020071#if defined(FEAT_EVAL) || defined(PROTO)
72static char *(p_bin_dep_opts[]) = {"textwidth", "wrapmargin", "modeline", "expandtab", NULL};
73static char *(p_paste_dep_opts[]) = {"autoindent", "expandtab", "ruler", "showmatch", "smarttab",
74 "softtabstop", "textwidth", "wrapmargin",
75#ifdef FEAT_RIGHTLEFT
76 "hkmap", "revins",
77#endif
78#ifdef FEAT_VARTABS
79 "varsofttabstop",
80#endif
81 NULL};
82static void didset_options_sctx(int opt_flags, char **buf);
83#endif
84
85
Bram Moolenaar071d4272004-06-13 20:20:40 +000086/*
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +000087 * Initialize the 'shell' option to a default value.
Bram Moolenaar071d4272004-06-13 20:20:40 +000088 */
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +000089 static void
90set_init_default_shell(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +000091{
92 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +000094 // Find default value for 'shell' option.
95 // Don't use it if it is empty.
Bram Moolenaar7c626922005-02-07 22:01:03 +000096 if (((p = mch_getenv((char_u *)"SHELL")) != NULL && *p != NUL)
Bram Moolenaar48e330a2016-02-23 14:53:34 +010097#if defined(MSWIN)
Bram Moolenaar7c626922005-02-07 22:01:03 +000098 || ((p = mch_getenv((char_u *)"COMSPEC")) != NULL && *p != NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +010099 || ((p = (char_u *)default_shell()) != NULL && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +0000101 )
Bram Moolenaar2efc44b2019-10-05 12:09:32 +0200102#if defined(MSWIN)
103 {
104 // For MS-Windows put the path in quotes instead of escaping spaces.
105 char_u *cmd;
106 size_t len;
107
108 if (vim_strchr(p, ' ') != NULL)
109 {
110 len = STRLEN(p) + 3; // two quotes and a trailing NUL
111 cmd = alloc(len);
Bram Moolenaar1671de32019-10-05 21:35:16 +0200112 if (cmd != NULL)
113 {
114 vim_snprintf((char *)cmd, len, "\"%s\"", p);
115 set_string_default("sh", cmd);
116 vim_free(cmd);
117 }
Bram Moolenaar2efc44b2019-10-05 12:09:32 +0200118 }
119 else
120 set_string_default("sh", p);
121 }
122#else
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +0100123 set_string_default_esc("sh", p, TRUE);
Bram Moolenaar2efc44b2019-10-05 12:09:32 +0200124#endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000125}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000127/*
128 * Set the default for 'backupskip' to include environment variables for
129 * temp files.
130 */
131 static void
132set_init_default_backupskip(void)
133{
134 int opt_idx;
135 long_u n;
136 char_u *p;
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100137#ifdef UNIX
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000138 static char *(names[4]) = {"", "TMPDIR", "TEMP", "TMP"};
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100139#else
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000140 static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100141#endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000142 int len;
143 garray_T ga;
Bram Moolenaar14338022023-03-15 22:05:44 +0000144 char_u *item;
Bram Moolenaarb00ef052020-09-12 14:53:53 +0200145
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000146 opt_idx = findoption((char_u *)"backupskip");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000148 ga_init2(&ga, 1, 100);
149 for (n = 0; n < (long)ARRAY_LENGTH(names); ++n)
150 {
Bram Moolenaar14338022023-03-15 22:05:44 +0000151 int mustfree = FALSE;
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100152#ifdef UNIX
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000153 if (*names[n] == NUL)
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100154# ifdef MACOS_X
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000155 p = (char_u *)"/private/tmp";
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100156# else
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000157 p = (char_u *)"/tmp";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158# endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000159 else
Bram Moolenaar074fbd42022-08-26 16:41:14 +0100160#endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000161 p = vim_getenv((char_u *)names[n], &mustfree);
162 if (p != NULL && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 {
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000164 // First time count the NUL, otherwise count the ','.
165 len = (int)STRLEN(p) + 3;
166 item = alloc(len);
Bram Moolenaar14338022023-03-15 22:05:44 +0000167 if (item != NULL)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000168 {
Bram Moolenaar14338022023-03-15 22:05:44 +0000169 STRCPY(item, p);
170 add_pathsep(item);
171 STRCAT(item, "*");
172 if (find_dup_item(ga.ga_data, item, options[opt_idx].flags)
173 == NULL
174 && ga_grow(&ga, len) == OK)
175 {
176 if (ga.ga_len > 0)
177 STRCAT(ga.ga_data, ",");
178 STRCAT(ga.ga_data, item);
179 ga.ga_len += len;
180 }
181 vim_free(item);
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000184 if (mustfree)
185 vim_free(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000187 if (ga.ga_data != NULL)
188 {
189 set_string_default("bsk", ga.ga_data);
190 vim_free(ga.ga_data);
191 }
192}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000193
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000194/*
195 * Initialize the 'maxmemtot' and 'maxmem' options to a default value.
196 * 'maxmemtot' and 'maxmem' may have to be adjusted for available memory.
197 */
198 static void
199set_init_default_maxmemtot(void)
200{
201 int opt_idx;
202 long_u n;
203
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 opt_idx = findoption((char_u *)"maxmemtot");
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000205 if (opt_idx < 0)
206 return;
207
208#if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
209 if (options[opt_idx].def_val[VI_DEFAULT] == (char_u *)0L)
210#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211 {
ichizok02560422022-04-05 14:18:44 +0100212#if defined(HAVE_AVAIL_MEM)
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000213 // Use amount of memory available at this moment.
214 n = (mch_avail_mem(FALSE) >> 1);
ichizok02560422022-04-05 14:18:44 +0100215#elif defined(HAVE_TOTAL_MEM)
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000216 // Use amount of memory available to Vim.
217 n = (mch_total_mem(FALSE) >> 1);
ichizok02560422022-04-05 14:18:44 +0100218#else
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000219 n = (0x7fffffff >> 11);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220#endif
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000221 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
222 opt_idx = findoption((char_u *)"maxmem");
223 if (opt_idx >= 0)
224 {
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000225#if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000226 if ((long)(long_i)options[opt_idx].def_val[VI_DEFAULT] > (long)n
227 || (long)(long_i)options[opt_idx].def_val[VI_DEFAULT] == 0L)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000228#endif
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000229 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000230 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000232}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000234/*
235 * Initialize the 'cdpath' option to a default value.
236 */
237 static void
238set_init_default_cdpath(void)
239{
240 int opt_idx;
241 char_u *cdpath;
242 char_u *buf;
243 int i;
244 int j;
245 int mustfree = FALSE;
246
247 cdpath = vim_getenv((char_u *)"CDPATH", &mustfree);
248 if (cdpath == NULL)
249 return;
250
251 buf = alloc((STRLEN(cdpath) << 1) + 2);
252 if (buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 {
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000254 buf[0] = ','; // start with ",", current dir first
255 j = 1;
256 for (i = 0; cdpath[i] != NUL; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257 {
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000258 if (vim_ispathlistsep(cdpath[i]))
259 buf[j++] = ',';
260 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261 {
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000262 if (cdpath[i] == ' ' || cdpath[i] == ',')
263 buf[j++] = '\\';
264 buf[j++] = cdpath[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 }
266 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000267 buf[j] = NUL;
268 opt_idx = findoption((char_u *)"cdpath");
269 if (opt_idx >= 0)
270 {
271 options[opt_idx].def_val[VI_DEFAULT] = buf;
272 options[opt_idx].flags |= P_DEF_ALLOCED;
273 }
274 else
275 vim_free(buf); // cannot happen
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000277 if (mustfree)
278 vim_free(cdpath);
279}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000281/*
282 * Initialize the 'printencoding' option to a default value.
283 */
284 static void
285set_init_default_printencoding(void)
286{
ichizok02560422022-04-05 14:18:44 +0100287#if defined(FEAT_POSTSCRIPT) && \
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000288 (defined(MSWIN) || defined(VMS) || defined(MAC) || defined(hpux))
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100289 // Set print encoding on platforms that don't default to latin1
Bram Moolenaar071d4272004-06-13 20:20:40 +0000290 set_string_default("penc",
Bram Moolenaare7fedb62015-12-31 19:07:19 +0100291# if defined(MSWIN)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000292 (char_u *)"cp1252"
ichizok02560422022-04-05 14:18:44 +0100293# elif defined(VMS)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000294 (char_u *)"dec-mcs"
ichizok02560422022-04-05 14:18:44 +0100295# elif defined(MAC)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000296 (char_u *)"mac-roman"
ichizok02560422022-04-05 14:18:44 +0100297# else // HPUX
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000298 (char_u *)"hp-roman8"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299# endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000300 );
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301#endif
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000302}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303
304#ifdef FEAT_POSTSCRIPT
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000305/*
306 * Initialize the 'printexpr' option to a default value.
307 */
308 static void
309set_init_default_printexpr(void)
310{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100311 // 'printexpr' must be allocated to be able to evaluate it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 set_string_default("pexpr",
Bram Moolenaar48e330a2016-02-23 14:53:34 +0100313# if defined(MSWIN)
Bram Moolenaared203462004-06-16 11:19:22 +0000314 (char_u *)"system('copy' . ' ' . v:fname_in . (&printdevice == '' ? ' LPT1:' : (' \"' . &printdevice . '\"'))) . delete(v:fname_in)"
ichizok02560422022-04-05 14:18:44 +0100315# elif defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316 (char_u *)"system('print/delete' . (&printdevice == '' ? '' : ' /queue=' . &printdevice) . ' ' . v:fname_in)"
317
ichizok02560422022-04-05 14:18:44 +0100318# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 (char_u *)"system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error"
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320# endif
321 );
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000322}
323#endif
324
325#ifdef UNIX
326/*
327 * Force restricted-mode on for "nologin" or "false" $SHELL
328 */
329 static void
330set_init_restricted_mode(void)
331{
332 char_u *p;
333
334 p = get_isolated_shell_name();
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000335 if (p == NULL)
336 return;
337 if (fnamecmp(p, "nologin") == 0 || fnamecmp(p, "false") == 0)
338 restricted = TRUE;
339 vim_free(p);
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000340}
341#endif
342
343#ifdef CLEAN_RUNTIMEPATH
344/*
345 * When Vim is started with the "--clean" argument, set the default value
346 * for the 'runtimepath' and 'packpath' options.
347 */
348 static void
349set_init_clean_rtp(void)
350{
351 int opt_idx;
352
353 opt_idx = findoption((char_u *)"runtimepath");
354 if (opt_idx >= 0)
355 {
356 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
357 p_rtp = (char_u *)CLEAN_RUNTIMEPATH;
358 }
359 opt_idx = findoption((char_u *)"packpath");
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +0000360 if (opt_idx < 0)
361 return;
362 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
363 p_pp = (char_u *)CLEAN_RUNTIMEPATH;
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000364}
365#endif
366
Luca Saccarolac9df1fb2024-04-14 22:53:22 +0200367#ifdef UNIX
368/*
369 * Change 'runtimepath' and 'packdir' to '$XDG_CONFIG_HOME/vim' if the only
370 * vimrc found is located in '$XDG_CONFIG_HOME/vim/vimrc'.
371 * In case the '$XDG_CONFIG_HOME' variable is not set, '$HOME/.config' is used
372 * as a fallback as is defined in the XDG base dir specification:
373 * <https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html>
374 */
375 static void
376set_init_xdg_rtp(void)
377{
378 int opt_idx;
379 int has_xdg_env = TRUE;
380 int should_free_xdg_dir = FALSE;
381 char_u *vimrc1 = NULL;
382 char_u *vimrc2 = NULL;
383 char_u *xdg_dir = NULL;
384 char_u *xdg_rtp = NULL;
385 char_u *vimrc_xdg = NULL;
386
Christian Brabandtb09fa352024-04-21 14:52:20 +0200387 // initialize chartab, so we can expand $HOME
388 (void)init_chartab();
Luca Saccarolac9df1fb2024-04-14 22:53:22 +0200389 vimrc1 = expand_env_save((char_u *)USR_VIMRC_FILE);
390 vimrc2 = expand_env_save((char_u *)USR_VIMRC_FILE2);
391
392 xdg_dir = mch_getenv("XDG_CONFIG_HOME");
393 if (!xdg_dir)
394 {
395 xdg_dir = expand_env_save((char_u *)"~/.config");
396 should_free_xdg_dir = TRUE;
397 has_xdg_env = FALSE;
398 }
399 vimrc_xdg = concat_fnames(xdg_dir, (char_u *)"vim/vimrc", TRUE);
400
401 if (file_is_readable(vimrc1) || file_is_readable(vimrc2) ||
402 !file_is_readable(vimrc_xdg))
403 goto theend;
404
405 xdg_rtp = has_xdg_env ? (char_u *)XDG_RUNTIMEPATH
406 : (char_u *)XDG_RUNTIMEPATH_FB;
407
408 if ((opt_idx = findoption((char_u *)"runtimepath")) < 0)
409 goto theend;
410
411 options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp;
412 p_rtp = xdg_rtp;
413
414 if ((opt_idx = findoption((char_u *)"packpath")) < 0)
415 goto theend;
416
417 options[opt_idx].def_val[VI_DEFAULT] = xdg_rtp;
418 p_pp = xdg_rtp;
419
420theend:
421 vim_free(vimrc1);
422 vim_free(vimrc2);
423 vim_free(vimrc_xdg);
424 if (should_free_xdg_dir)
425 vim_free(xdg_dir);
426}
427#endif
428
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000429/*
430 * Expand environment variables and things like "~" for the defaults.
431 * If option_expand() returns non-NULL the variable is expanded. This can
432 * only happen for non-indirect options.
433 * Also set the default to the expanded value, so ":set" does not list
434 * them.
435 * Don't set the P_ALLOCED flag, because we don't want to free the
436 * default.
437 */
438 static void
439set_init_expand_env(void)
440{
441 int opt_idx;
442 char_u *p;
443
444 for (opt_idx = 0; !istermoption_idx(opt_idx); opt_idx++)
445 {
446 if ((options[opt_idx].flags & P_GETTEXT)
447 && options[opt_idx].var != NULL)
448 p = (char_u *)_(*(char **)options[opt_idx].var);
449 else
450 p = option_expand(opt_idx, NULL);
451 if (p != NULL && (p = vim_strsave(p)) != NULL)
452 {
453 *(char_u **)options[opt_idx].var = p;
454 // VIMEXP
455 // Defaults for all expanded options are currently the same for Vi
456 // and Vim. When this changes, add some code here! Also need to
457 // split P_DEF_ALLOCED in two.
458 if (options[opt_idx].flags & P_DEF_ALLOCED)
459 vim_free(options[opt_idx].def_val[VI_DEFAULT]);
460 options[opt_idx].def_val[VI_DEFAULT] = p;
461 options[opt_idx].flags |= P_DEF_ALLOCED;
462 }
463 }
464}
465
466/*
467 * Initialize the 'LANG' environment variable to a default value.
468 */
469 static void
470set_init_lang_env(void)
471{
472#if defined(MSWIN) && defined(FEAT_GETTEXT)
473 // If $LANG isn't set, try to get a good value for it. This makes the
474 // right language be used automatically. Don't do this for English.
475 if (mch_getenv((char_u *)"LANG") == NULL)
476 {
477 char buf[20];
478 long_u n;
479
480 // Could use LOCALE_SISO639LANGNAME, but it's not in Win95.
481 // LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use
482 // only the first two.
483 n = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME,
484 (LPTSTR)buf, 20);
485 if (n >= 2 && STRNICMP(buf, "en", 2) != 0)
486 {
487 // There are a few exceptions (probably more)
488 if (STRNICMP(buf, "cht", 3) == 0 || STRNICMP(buf, "zht", 3) == 0)
489 STRCPY(buf, "zh_TW");
490 else if (STRNICMP(buf, "chs", 3) == 0
491 || STRNICMP(buf, "zhc", 3) == 0)
492 STRCPY(buf, "zh_CN");
493 else if (STRNICMP(buf, "jp", 2) == 0)
494 STRCPY(buf, "ja");
495 else
496 buf[2] = NUL; // truncate to two-letter code
497 vim_setenv((char_u *)"LANG", (char_u *)buf);
498 }
499 }
500#elif defined(MACOS_CONVERT)
501 // Moved to os_mac_conv.c to avoid dependency problems.
502 mac_lang_init();
503#endif
504}
505
506/*
507 * Initialize the 'encoding' option to a default value.
508 */
509 static void
510set_init_default_encoding(void)
511{
512 char_u *p;
513 int opt_idx;
514
Igor Todorovski497e5282024-01-12 17:59:18 +0100515# if defined(MSWIN) || defined(__MVS__)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000516 // MS-Windows has builtin support for conversion to and from Unicode, using
517 // "utf-8" for 'encoding' should work best for most users.
Igor Todorovski497e5282024-01-12 17:59:18 +0100518 // z/OS built should default to UTF-8 mode as setlocale does not respect utf-8 environment variable locales
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000519 p = vim_strsave((char_u *)ENC_DFLT);
520# else
521 // enc_locale() will try to find the encoding of the current locale.
522 // This works best for properly configured systems, old and new.
523 p = enc_locale();
524# endif
525 if (p == NULL)
526 return;
527
528 // Try setting 'encoding' and check if the value is valid.
529 // If not, go back to the default encoding.
530 char_u *save_enc = p_enc;
531 p_enc = p;
532 if (STRCMP(p_enc, "gb18030") == 0)
533 {
534 // We don't support "gb18030", but "cp936" is a good substitute
535 // for practical purposes, thus use that. It's not an alias to
536 // still support conversion between gb18030 and utf-8.
537 p_enc = vim_strsave((char_u *)"cp936");
538 vim_free(p);
539 }
540 if (mb_init() == NULL)
541 {
542 opt_idx = findoption((char_u *)"encoding");
543 if (opt_idx >= 0)
544 {
545 options[opt_idx].def_val[VI_DEFAULT] = p_enc;
546 options[opt_idx].flags |= P_DEF_ALLOCED;
547 }
548
549#if defined(MSWIN) || defined(MACOS_X) || defined(VMS)
550 if (STRCMP(p_enc, "latin1") == 0 || enc_utf8)
551 {
552 // Adjust the default for 'isprint' and 'iskeyword' to match
553 // latin1. Also set the defaults for when 'nocompatible' is
554 // set.
555 set_string_option_direct((char_u *)"isp", -1,
556 ISP_LATIN1, OPT_FREE, SID_NONE);
557 set_string_option_direct((char_u *)"isk", -1,
558 ISK_LATIN1, OPT_FREE, SID_NONE);
559 opt_idx = findoption((char_u *)"isp");
560 if (opt_idx >= 0)
561 options[opt_idx].def_val[VIM_DEFAULT] = ISP_LATIN1;
562 opt_idx = findoption((char_u *)"isk");
563 if (opt_idx >= 0)
564 options[opt_idx].def_val[VIM_DEFAULT] = ISK_LATIN1;
565 (void)init_chartab();
566 }
567#endif
568
569#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
570 // Win32 console: When GetACP() returns a different value from
571 // GetConsoleCP() set 'termencoding'.
572 if (
573# ifdef VIMDLL
574 (!gui.in_use && !gui.starting) &&
575# endif
576 GetACP() != GetConsoleCP())
577 {
578 char buf[50];
579
580 // Win32 console: In ConPTY, GetConsoleCP() returns zero.
581 // Use an alternative value.
582 if (GetConsoleCP() == 0)
583 sprintf(buf, "cp%ld", (long)GetACP());
584 else
585 sprintf(buf, "cp%ld", (long)GetConsoleCP());
586 p_tenc = vim_strsave((char_u *)buf);
587 if (p_tenc != NULL)
588 {
589 opt_idx = findoption((char_u *)"termencoding");
590 if (opt_idx >= 0)
591 {
592 options[opt_idx].def_val[VI_DEFAULT] = p_tenc;
593 options[opt_idx].flags |= P_DEF_ALLOCED;
594 }
595 convert_setup(&input_conv, p_tenc, p_enc);
596 convert_setup(&output_conv, p_enc, p_tenc);
597 }
598 else
599 p_tenc = empty_option;
600 }
601#endif
602#if defined(MSWIN)
603 // $HOME may have characters in active code page.
604 init_homedir();
605#endif
606 }
607 else
608 {
609 vim_free(p_enc);
610 p_enc = save_enc;
611 }
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000612}
613
614/*
615 * Initialize the options, first part.
616 *
617 * Called only once from main(), just after creating the first buffer.
618 * If "clean_arg" is TRUE Vim was started with --clean.
619 */
620 void
621set_init_1(int clean_arg)
622{
623#ifdef FEAT_LANGMAP
624 langmap_init();
625#endif
626
627 // Be Vi compatible by default
628 p_cp = TRUE;
629
630 // Use POSIX compatibility when $VIM_POSIX is set.
631 if (mch_getenv((char_u *)"VIM_POSIX") != NULL)
632 {
633 set_string_default("cpo", (char_u *)CPO_ALL);
634 set_string_default("shm", (char_u *)SHM_POSIX);
635 }
636
637 set_init_default_shell();
638 set_init_default_backupskip();
639 set_init_default_maxmemtot();
640 set_init_default_cdpath();
641 set_init_default_printencoding();
642#ifdef FEAT_POSTSCRIPT
643 set_init_default_printexpr();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644#endif
645
646 /*
647 * Set all the options (except the terminal options) to their default
648 * value. Also set the global value for local options.
649 */
650 set_options_default(0);
651
matveytadbb1bf2022-02-01 17:26:12 +0000652#ifdef UNIX
Luca Saccarolac9df1fb2024-04-14 22:53:22 +0200653 set_init_xdg_rtp();
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000654 set_init_restricted_mode();
matveytadbb1bf2022-02-01 17:26:12 +0000655#endif
656
Bram Moolenaar07268702018-03-01 21:57:32 +0100657#ifdef CLEAN_RUNTIMEPATH
658 if (clean_arg)
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000659 set_init_clean_rtp();
Bram Moolenaar07268702018-03-01 21:57:32 +0100660#endif
661
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662#ifdef FEAT_GUI
663 if (found_reverse_arg)
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100664 set_option_value_give_err((char_u *)"bg", 0L, (char_u *)"dark", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665#endif
666
667 curbuf->b_p_initialized = TRUE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100668 curbuf->b_p_ar = -1; // no local 'autoread' value
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +0100669 curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670 check_buf_options(curbuf);
671 check_win_options(curwin);
672 check_options();
673
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100674 // Must be before option_expand(), because that one needs vim_isIDc()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 didset_options();
676
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +0000677#ifdef FEAT_SPELL
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100678 // Use the current chartab for the generic chartab. This is not in
679 // didset_options() because it only depends on 'encoding'.
Bram Moolenaar6bb68362005-03-22 23:03:44 +0000680 init_spell_chartab();
681#endif
682
K.Takatace3189d2023-02-15 19:13:43 +0000683 set_init_default_encoding();
684
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000685 // Expand environment variables and things like "~" for the defaults.
686 set_init_expand_env();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100688 save_file_ff(curbuf); // Buffer is unchanged
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690#if defined(FEAT_ARABIC)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100691 // Detect use of mlterm.
692 // Mlterm is a terminal emulator akin to xterm that has some special
693 // abilities (bidi namely).
694 // NOTE: mlterm's author is being asked to 'set' a variable
695 // instead of an environment variable due to inheritance.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 if (mch_getenv((char_u *)"MLTERM") != NULL)
Bram Moolenaar31e5c602022-04-15 13:53:33 +0100697 set_option_value_give_err((char_u *)"tbidi", 1L, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698#endif
699
Bram Moolenaare68c25c2015-08-25 15:39:55 +0200700 didset_options2();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701
Yegappan Lakshmanan6c41bed2023-02-10 14:50:31 +0000702 set_init_lang_env();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703
704#ifdef FEAT_MULTI_LANG
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100705 // Set the default for 'helplang'.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 set_helplang_default(get_mess_lang());
707#endif
708}
709
Bram Moolenaar5ffefbb2021-06-13 20:27:36 +0200710static char_u *fencs_utf8_default = (char_u *)"ucs-bom,utf-8,default,latin1";
711
712/*
713 * Set the "fileencodings" option to the default value for when 'encoding' is
714 * utf-8.
715 */
716 void
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +0000717set_fencs_unicode(void)
Bram Moolenaar5ffefbb2021-06-13 20:27:36 +0200718{
719 set_string_option_direct((char_u *)"fencs", -1, fencs_utf8_default,
720 OPT_FREE, 0);
721}
722
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723/*
724 * Set an option to its default value.
725 * This does not take care of side effects!
726 */
727 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100728set_option_default(
729 int opt_idx,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100730 int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
731 int compatible) // use Vi default value
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100733 char_u *varp; // pointer to variable for current option
734 int dvi; // index in def_val[]
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 long_u flags;
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000736 long_u *flagsp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
738
739 varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags);
740 flags = options[opt_idx].flags;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100741 if (varp != NULL) // skip hidden option, nothing to do for it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 {
743 dvi = ((flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT;
744 if (flags & P_STRING)
745 {
Bram Moolenaar5ffefbb2021-06-13 20:27:36 +0200746 // 'fencs' default value depends on 'encoding'
747 if (options[opt_idx].var == (char_u *)&p_fencs && enc_utf8)
748 set_fencs_unicode();
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100749 // Use set_string_option_direct() for local options to handle
750 // freeing and allocating the value.
Bram Moolenaar5ffefbb2021-06-13 20:27:36 +0200751 else if (options[opt_idx].indir != PV_NONE)
Bram Moolenaarb833c1e2018-05-05 16:36:06 +0200752 set_string_option_direct(NULL, opt_idx,
753 options[opt_idx].def_val[dvi], opt_flags, 0);
754 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 {
Bram Moolenaarb833c1e2018-05-05 16:36:06 +0200756 if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED))
757 free_string_option(*(char_u **)(varp));
758 *(char_u **)varp = options[opt_idx].def_val[dvi];
759 options[opt_idx].flags &= ~P_ALLOCED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 }
761 }
762 else if (flags & P_NUM)
763 {
Bram Moolenaar5fc1a8b2006-10-17 16:34:24 +0000764 if (options[opt_idx].indir == PV_SCROLL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 win_comp_scroll(curwin);
766 else
767 {
Bram Moolenaar375e3392019-01-31 18:26:10 +0100768 long def_val = (long)(long_i)options[opt_idx].def_val[dvi];
769
770 if ((long *)varp == &curwin->w_p_so
771 || (long *)varp == &curwin->w_p_siso)
772 // 'scrolloff' and 'sidescrolloff' local values have a
773 // different default value than the global default.
774 *(long *)varp = -1;
775 else
776 *(long *)varp = def_val;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100777 // May also set global value for local option.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 if (both)
779 *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
Bram Moolenaar375e3392019-01-31 18:26:10 +0100780 def_val;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 }
782 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100783 else // P_BOOL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100785 // the cast to long is required for Manx C, long_i is needed for
786 // MSVC
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000787 *(int *)varp = (int)(long)(long_i)options[opt_idx].def_val[dvi];
Bram Moolenaar8243a792007-05-01 17:05:03 +0000788#ifdef UNIX
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100789 // 'modeline' defaults to off for root
Bram Moolenaar8243a792007-05-01 17:05:03 +0000790 if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID)
791 *(int *)varp = FALSE;
792#endif
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100793 // May also set global value for local option.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 if (both)
795 *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) =
796 *(int *)varp;
797 }
Bram Moolenaarb71eaae2006-01-20 23:10:18 +0000798
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100799 // The default value is not insecure.
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000800 flagsp = insecure_flag(opt_idx, opt_flags);
801 *flagsp = *flagsp & ~P_INSECURE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 }
803
804#ifdef FEAT_EVAL
Bram Moolenaarf29c1c62018-09-10 21:05:02 +0200805 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806#endif
807}
808
809/*
810 * Set all options (except terminal options) to their default value.
Bram Moolenaarb341dda2015-08-25 12:56:31 +0200811 * When "opt_flags" is non-zero skip 'encoding'.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 */
813 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100814set_options_default(
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100815 int opt_flags) // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816{
817 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +0000819 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820
Bram Moolenaardac13472019-09-16 21:06:21 +0200821 for (i = 0; !istermoption_idx(i); i++)
Bram Moolenaarb341dda2015-08-25 12:56:31 +0200822 if (!(options[i].flags & P_NODEFAULT)
Bram Moolenaare68c25c2015-08-25 15:39:55 +0200823 && (opt_flags == 0
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100824 || (options[i].var != (char_u *)&p_enc
Bram Moolenaar5ea87a02015-08-26 23:24:09 +0200825# if defined(FEAT_CRYPT)
Bram Moolenaare68c25c2015-08-25 15:39:55 +0200826 && options[i].var != (char_u *)&p_cm
Bram Moolenaar80606872015-08-25 21:27:35 +0200827 && options[i].var != (char_u *)&p_key
Bram Moolenaar5ea87a02015-08-26 23:24:09 +0200828# endif
Bram Moolenaarfc3abf42019-01-24 15:54:21 +0100829 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 set_option_default(i, opt_flags, p_cp);
831
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100832 // The 'scroll' option must be computed for all windows.
Bram Moolenaarf740b292006-02-16 22:11:02 +0000833 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 win_comp_scroll(wp);
Bram Moolenaar5a4eceb2014-09-09 17:33:07 +0200835 parse_cino(curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836}
837
838/*
839 * Set the Vi-default value of a string option.
840 * Used for 'sh', 'backupskip' and 'term'.
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +0100841 * When "escape" is TRUE escape spaces with a backslash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842 */
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +0100843 static void
844set_string_default_esc(char *name, char_u *val, int escape)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845{
846 char_u *p;
847 int opt_idx;
848
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +0100849 if (escape && vim_strchr(val, ' ') != NULL)
850 p = vim_strsave_escaped(val, (char_u *)" ");
851 else
852 p = vim_strsave(val);
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000853 if (p == NULL) // we don't want a NULL
854 return;
855
856 opt_idx = findoption((char_u *)name);
857 if (opt_idx < 0)
Christian Brabandt29269a72024-04-16 22:44:31 +0200858 {
859 vim_free(p);
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000860 return;
Christian Brabandt29269a72024-04-16 22:44:31 +0200861 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000862
863 if (options[opt_idx].flags & P_DEF_ALLOCED)
864 vim_free(options[opt_idx].def_val[VI_DEFAULT]);
865 options[opt_idx].def_val[VI_DEFAULT] = p;
866 options[opt_idx].flags |= P_DEF_ALLOCED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867}
868
Bram Moolenaar4bfa8af2018-02-03 15:14:46 +0100869 void
870set_string_default(char *name, char_u *val)
871{
872 set_string_default_esc(name, val, FALSE);
873}
874
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875/*
Bram Moolenaarb00ef052020-09-12 14:53:53 +0200876 * For an option value that contains comma separated items, find "newval" in
877 * "origval". Return NULL if not found.
878 */
879 static char_u *
880find_dup_item(char_u *origval, char_u *newval, long_u flags)
881{
Bram Moolenaar8f13d822020-09-12 21:04:23 +0200882 int bs = 0;
Bram Moolenaarb00ef052020-09-12 14:53:53 +0200883 size_t newlen;
884 char_u *s;
885
886 if (origval == NULL)
887 return NULL;
888
889 newlen = STRLEN(newval);
890 for (s = origval; *s != NUL; ++s)
891 {
892 if ((!(flags & P_COMMA)
893 || s == origval
894 || (s[-1] == ',' && !(bs & 1)))
895 && STRNCMP(s, newval, newlen) == 0
896 && (!(flags & P_COMMA)
897 || s[newlen] == ','
898 || s[newlen] == NUL))
899 return s;
900 // Count backslashes. Only a comma with an even number of backslashes
901 // or a single backslash preceded by a comma before it is recognized as
902 // a separator.
903 if ((s > origval + 1
904 && s[-1] == '\\'
905 && s[-2] != ',')
906 || (s == origval + 1
907 && s[-1] == '\\'))
908 ++bs;
909 else
910 bs = 0;
911 }
912 return NULL;
913}
914
915/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 * Set the Vi-default value of a number option.
917 * Used for 'lines' and 'columns'.
918 */
919 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100920set_number_default(char *name, long val)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921{
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000922 int opt_idx;
923
924 opt_idx = findoption((char_u *)name);
925 if (opt_idx >= 0)
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000926 options[opt_idx].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927}
928
Dominique Pelle748b3082022-01-08 12:41:16 +0000929#if defined(FEAT_PROP_POPUP) || defined(PROTO)
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200930/*
931 * Set all window-local and buffer-local options to the Vim default.
932 * local-global options will use the global value.
Bram Moolenaar46451042019-08-24 15:50:46 +0200933 * When "do_buffer" is FALSE don't set buffer-local options.
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200934 */
935 void
Bram Moolenaar46451042019-08-24 15:50:46 +0200936set_local_options_default(win_T *wp, int do_buffer)
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200937{
938 win_T *save_curwin = curwin;
939 int i;
940
941 curwin = wp;
942 curbuf = curwin->w_buffer;
943 block_autocmds();
944
Bram Moolenaardac13472019-09-16 21:06:21 +0200945 for (i = 0; !istermoption_idx(i); i++)
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200946 {
947 struct vimoption *p = &(options[i]);
948 char_u *varp = get_varp_scope(p, OPT_LOCAL);
949
950 if (p->indir != PV_NONE
Bram Moolenaar46451042019-08-24 15:50:46 +0200951 && (do_buffer || (p->indir & PV_BUF) == 0)
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200952 && !(options[i].flags & P_NODEFAULT)
953 && !optval_default(p, varp, FALSE))
Bram Moolenaar86173482019-10-01 17:02:16 +0200954 set_option_default(i, OPT_FREE|OPT_LOCAL, FALSE);
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200955 }
956
957 unblock_autocmds();
958 curwin = save_curwin;
959 curbuf = curwin->w_buffer;
960}
Dominique Pelle748b3082022-01-08 12:41:16 +0000961#endif
Bram Moolenaarcacc6a52019-05-30 15:22:43 +0200962
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000963#if defined(EXITFREE) || defined(PROTO)
964/*
965 * Free all options.
966 */
967 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100968free_all_options(void)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000969{
970 int i;
971
Bram Moolenaardac13472019-09-16 21:06:21 +0200972 for (i = 0; !istermoption_idx(i); i++)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000973 {
974 if (options[i].indir == PV_NONE)
975 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100976 // global option: free value and default value.
Bram Moolenaar67391142017-02-19 21:07:04 +0100977 if ((options[i].flags & P_ALLOCED) && options[i].var != NULL)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000978 free_string_option(*(char_u **)options[i].var);
979 if (options[i].flags & P_DEF_ALLOCED)
980 free_string_option(options[i].def_val[VI_DEFAULT]);
981 }
982 else if (options[i].var != VAR_WIN
983 && (options[i].flags & P_STRING))
Bram Moolenaar6e0ce172019-12-05 20:12:41 +0100984 // buffer-local option: free global value
Bram Moolenaar77111e22021-07-29 21:11:30 +0200985 clear_string_option((char_u **)options[i].var);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000986 }
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +0000987 free_operatorfunc_option();
Yegappan Lakshmanan19916a82021-11-24 16:32:55 +0000988 free_tagfunc_option();
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000989}
990#endif
991
992
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993/*
994 * Initialize the options, part two: After getting Rows and Columns and
995 * setting 'term'.
996 */
997 void
Bram Moolenaar9b578142016-01-30 19:39:49 +0100998set_init_2(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999{
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001000 int idx;
1001
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001002 // 'scroll' defaults to half the window height. The stored default is zero,
1003 // which results in the actual value computed from the window height.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001004 idx = findoption((char_u *)"scroll");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001005 if (idx >= 0 && !(options[idx].flags & P_WAS_SET))
Bram Moolenaar26a60b42005-02-22 08:49:11 +00001006 set_option_default(idx, OPT_LOCAL, p_cp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007 comp_col();
1008
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001009 // 'window' is only for backwards compatibility with Vi.
1010 // Default is Rows - 1.
Bram Moolenaard68071d2006-05-02 22:08:30 +00001011 if (!option_was_set((char_u *)"window"))
Bram Moolenaar4399ef42005-02-12 14:29:27 +00001012 p_window = Rows - 1;
1013 set_number_default("window", Rows - 1);
1014
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01001015 // For DOS console the default is always black.
Bram Moolenaar4f974752019-02-17 17:44:42 +01001016#if !((defined(MSWIN)) && !defined(FEAT_GUI))
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001017 // If 'background' wasn't set by the user, try guessing the value,
1018 // depending on the terminal name. Only need to check for terminals
1019 // with a dark background, that can handle color.
Bram Moolenaarf740b292006-02-16 22:11:02 +00001020 idx = findoption((char_u *)"bg");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001021 if (idx >= 0 && !(options[idx].flags & P_WAS_SET)
1022 && *term_bg_default() == 'd')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00001024 set_string_option_direct(NULL, idx, (char_u *)"dark", OPT_FREE, 0);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01001025 // don't mark it as set, when starting the GUI it may be
1026 // changed again
Bram Moolenaarf740b292006-02-16 22:11:02 +00001027 options[idx].flags &= ~P_WAS_SET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 }
1029#endif
Bram Moolenaar58d98232005-07-23 22:25:46 +00001030
1031#ifdef CURSOR_SHAPE
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001032 parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
Bram Moolenaar58d98232005-07-23 22:25:46 +00001033#endif
1034#ifdef FEAT_MOUSESHAPE
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001035 parse_shape_opt(SHAPE_MOUSE); // set mouse shapes from 'mouseshape'
Bram Moolenaar58d98232005-07-23 22:25:46 +00001036#endif
1037#ifdef FEAT_PRINTER
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00001038 (void)parse_printoptions(NULL); // parse 'printoptions' default value
Bram Moolenaar58d98232005-07-23 22:25:46 +00001039#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040}
1041
1042/*
1043 * Initialize the options, part three: After reading the .vimrc
1044 */
1045 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001046set_init_3(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047{
Bram Moolenaar4f974752019-02-17 17:44:42 +01001048#if defined(UNIX) || defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049/*
1050 * Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
1051 * This is done after other initializations, where 'shell' might have been
1052 * set, but only if they have not been set before.
1053 */
1054 char_u *p;
1055 int idx_srr;
1056 int do_srr;
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001057# ifdef FEAT_QUICKFIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 int idx_sp;
1059 int do_sp;
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001060# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001061
1062 idx_srr = findoption((char_u *)"srr");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001063 if (idx_srr < 0)
1064 do_srr = FALSE;
1065 else
1066 do_srr = !(options[idx_srr].flags & P_WAS_SET);
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001067# ifdef FEAT_QUICKFIX
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 idx_sp = findoption((char_u *)"sp");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001069 if (idx_sp < 0)
1070 do_sp = FALSE;
1071 else
1072 do_sp = !(options[idx_sp].flags & P_WAS_SET);
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001073# endif
Bram Moolenaar75a8d742014-05-07 15:10:21 +02001074 p = get_isolated_shell_name();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 if (p != NULL)
1076 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001077 // Default for p_sp is "| tee", for p_srr is ">".
1078 // For known shells it is changed here to include stderr.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 if ( fnamecmp(p, "csh") == 0
1080 || fnamecmp(p, "tcsh") == 0
Bram Moolenaar4f974752019-02-17 17:44:42 +01001081# if defined(MSWIN) // also check with .exe extension
Bram Moolenaar071d4272004-06-13 20:20:40 +00001082 || fnamecmp(p, "csh.exe") == 0
1083 || fnamecmp(p, "tcsh.exe") == 0
1084# endif
1085 )
1086 {
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001087# if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 if (do_sp)
1089 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01001090# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 p_sp = (char_u *)">&";
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001092# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 p_sp = (char_u *)"|& tee";
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001094# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095 options[idx_sp].def_val[VI_DEFAULT] = p_sp;
1096 }
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001097# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 if (do_srr)
1099 {
1100 p_srr = (char_u *)">&";
1101 options[idx_srr].def_val[VI_DEFAULT] = p_srr;
1102 }
1103 }
Mike Williams12795022021-06-28 20:53:58 +02001104# ifdef MSWIN
Mike Williamsa3d1b292021-06-30 20:56:00 +02001105 // Windows PowerShell output is UTF-16 with BOM so re-encode to the
1106 // current codepage.
Mike Williams12795022021-06-28 20:53:58 +02001107 else if ( fnamecmp(p, "powershell") == 0
1108 || fnamecmp(p, "powershell.exe") == 0
1109 )
1110 {
1111# if defined(FEAT_QUICKFIX)
1112 if (do_sp)
1113 {
1114 p_sp = (char_u *)"2>&1 | Out-File -Encoding default";
1115 options[idx_sp].def_val[VI_DEFAULT] = p_sp;
1116 }
1117# endif
1118 if (do_srr)
1119 {
1120 p_srr = (char_u *)"2>&1 | Out-File -Encoding default";
1121 options[idx_srr].def_val[VI_DEFAULT] = p_srr;
1122 }
1123 }
1124#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 else
Natanael Copa56318362021-05-06 18:46:35 +02001126 // Always use POSIX shell style redirection if we reach this
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 if ( fnamecmp(p, "sh") == 0
1128 || fnamecmp(p, "ksh") == 0
Bram Moolenaarf1fda2d2011-04-28 12:57:36 +02001129 || fnamecmp(p, "mksh") == 0
1130 || fnamecmp(p, "pdksh") == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 || fnamecmp(p, "zsh") == 0
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001132 || fnamecmp(p, "zsh-beta") == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 || fnamecmp(p, "bash") == 0
Bram Moolenaar75a8d742014-05-07 15:10:21 +02001134 || fnamecmp(p, "fish") == 0
Natanael Copa56318362021-05-06 18:46:35 +02001135 || fnamecmp(p, "ash") == 0
1136 || fnamecmp(p, "dash") == 0
Mike Williamsa3d1b292021-06-30 20:56:00 +02001137 || fnamecmp(p, "pwsh") == 0
Bram Moolenaar4f974752019-02-17 17:44:42 +01001138# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 || fnamecmp(p, "cmd") == 0
1140 || fnamecmp(p, "sh.exe") == 0
1141 || fnamecmp(p, "ksh.exe") == 0
Bram Moolenaarf1fda2d2011-04-28 12:57:36 +02001142 || fnamecmp(p, "mksh.exe") == 0
1143 || fnamecmp(p, "pdksh.exe") == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 || fnamecmp(p, "zsh.exe") == 0
Bram Moolenaarc1e37902006-04-18 21:55:01 +00001145 || fnamecmp(p, "zsh-beta.exe") == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 || fnamecmp(p, "bash.exe") == 0
1147 || fnamecmp(p, "cmd.exe") == 0
Natanael Copa56318362021-05-06 18:46:35 +02001148 || fnamecmp(p, "dash.exe") == 0
Mike Williamsa3d1b292021-06-30 20:56:00 +02001149 || fnamecmp(p, "pwsh.exe") == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150# endif
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001151 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 {
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001153# if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154 if (do_sp)
1155 {
Bram Moolenaar4f974752019-02-17 17:44:42 +01001156# ifdef MSWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 p_sp = (char_u *)">%s 2>&1";
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001158# else
Mike Williamsa3d1b292021-06-30 20:56:00 +02001159 if (fnamecmp(p, "pwsh") == 0)
1160 p_sp = (char_u *)">%s 2>&1";
1161 else
1162 p_sp = (char_u *)"2>&1| tee";
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001163# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001164 options[idx_sp].def_val[VI_DEFAULT] = p_sp;
1165 }
Bram Moolenaare7fedb62015-12-31 19:07:19 +01001166# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 if (do_srr)
1168 {
1169 p_srr = (char_u *)">%s 2>&1";
1170 options[idx_srr].def_val[VI_DEFAULT] = p_srr;
1171 }
1172 }
1173 vim_free(p);
1174 }
1175#endif
1176
Bram Moolenaar4f974752019-02-17 17:44:42 +01001177#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 /*
Bram Moolenaara64ba222012-02-12 23:23:31 +01001179 * Set 'shellcmdflag', 'shellxquote', and 'shellquote' depending on the
1180 * 'shell' option.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 * This is done after other initializations, where 'shell' might have been
Mike Williams12795022021-06-28 20:53:58 +02001182 * set, but only if they have not been set before.
1183 * Default values depend on shell (cmd.exe is default shell):
1184 *
1185 * p_shcf p_sxq
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001186 * cmd.exe - "/c" "("
Mike Williams12795022021-06-28 20:53:58 +02001187 * powershell.exe - "-Command" "\""
Mike Williamsa3d1b292021-06-30 20:56:00 +02001188 * pwsh.exe - "-c" "\""
Mike Williams12795022021-06-28 20:53:58 +02001189 * "sh" like shells - "-c" "\""
1190 *
1191 * For Win32 p_sxq is set instead of p_shq to include shell redirection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 */
Mike Williams12795022021-06-28 20:53:58 +02001193 if (strstr((char *)gettail(p_sh), "powershell") != NULL)
1194 {
1195 int idx_opt;
1196
1197 idx_opt = findoption((char_u *)"shcf");
1198 if (idx_opt >= 0 && !(options[idx_opt].flags & P_WAS_SET))
1199 {
1200 p_shcf = (char_u*)"-Command";
1201 options[idx_opt].def_val[VI_DEFAULT] = p_shcf;
1202 }
1203
1204 idx_opt = findoption((char_u *)"sxq");
1205 if (idx_opt >= 0 && !(options[idx_opt].flags & P_WAS_SET))
1206 {
1207 p_sxq = (char_u*)"\"";
1208 options[idx_opt].def_val[VI_DEFAULT] = p_sxq;
1209 }
1210 }
1211 else if (strstr((char *)gettail(p_sh), "sh") != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001212 {
1213 int idx3;
1214
1215 idx3 = findoption((char_u *)"shcf");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001216 if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217 {
1218 p_shcf = (char_u *)"-c";
1219 options[idx3].def_val[VI_DEFAULT] = p_shcf;
1220 }
1221
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01001222 // Somehow Win32 requires the quotes around the redirection too
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 idx3 = findoption((char_u *)"sxq");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001224 if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225 {
1226 p_sxq = (char_u *)"\"";
1227 options[idx3].def_val[VI_DEFAULT] = p_sxq;
1228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001229 }
Bram Moolenaara64ba222012-02-12 23:23:31 +01001230 else if (strstr((char *)gettail(p_sh), "cmd.exe") != NULL)
1231 {
1232 int idx3;
1233
1234 /*
1235 * cmd.exe on Windows will strip the first and last double quote given
1236 * on the command line, e.g. most of the time things like:
1237 * cmd /c "my path/to/echo" "my args to echo"
1238 * become:
1239 * my path/to/echo" "my args to echo
1240 * when executed.
1241 *
Bram Moolenaar034b1152012-02-19 18:19:30 +01001242 * To avoid this, set shellxquote to surround the command in
1243 * parenthesis. This appears to make most commands work, without
1244 * breaking commands that worked previously, such as
1245 * '"path with spaces/cmd" "a&b"'.
Bram Moolenaara64ba222012-02-12 23:23:31 +01001246 */
Bram Moolenaara64ba222012-02-12 23:23:31 +01001247 idx3 = findoption((char_u *)"sxq");
1248 if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
1249 {
Bram Moolenaar034b1152012-02-19 18:19:30 +01001250 p_sxq = (char_u *)"(";
Bram Moolenaara64ba222012-02-12 23:23:31 +01001251 options[idx3].def_val[VI_DEFAULT] = p_sxq;
1252 }
1253
Bram Moolenaara64ba222012-02-12 23:23:31 +01001254 idx3 = findoption((char_u *)"shcf");
1255 if (idx3 >= 0 && !(options[idx3].flags & P_WAS_SET))
1256 {
Bram Moolenaar034b1152012-02-19 18:19:30 +01001257 p_shcf = (char_u *)"/c";
Bram Moolenaara64ba222012-02-12 23:23:31 +01001258 options[idx3].def_val[VI_DEFAULT] = p_shcf;
1259 }
1260 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001261#endif
1262
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01001263 if (BUFEMPTY())
Bram Moolenaar364fa5c2016-03-20 17:53:25 +01001264 {
1265 int idx_ffs = findoption((char_u *)"ffs");
1266
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01001267 // Apply the first entry of 'fileformats' to the initial buffer.
Bram Moolenaar364fa5c2016-03-20 17:53:25 +01001268 if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET))
1269 set_fileformat(default_fileformat(), OPT_LOCAL);
1270 }
1271
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272 set_title_defaults();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001273}
1274
1275#if defined(FEAT_MULTI_LANG) || defined(PROTO)
1276/*
1277 * When 'helplang' is still at its default value, set it to "lang".
1278 * Only the first two characters of "lang" are used.
1279 */
1280 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001281set_helplang_default(char_u *lang)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001282{
1283 int idx;
1284
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01001285 if (lang == NULL || STRLEN(lang) < 2) // safety check
Bram Moolenaar071d4272004-06-13 20:20:40 +00001286 return;
1287 idx = findoption((char_u *)"hlg");
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001288 if (idx < 0 || (options[idx].flags & P_WAS_SET))
1289 return;
1290
1291 if (options[idx].flags & P_ALLOCED)
1292 free_string_option(p_hlg);
1293 p_hlg = vim_strsave(lang);
1294 if (p_hlg == NULL)
1295 p_hlg = empty_option;
1296 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297 {
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001298 // zh_CN becomes "cn", zh_TW becomes "tw"
1299 if (STRNICMP(p_hlg, "zh_", 3) == 0 && STRLEN(p_hlg) >= 5)
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001300 {
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001301 p_hlg[0] = TOLOWER_ASC(p_hlg[3]);
1302 p_hlg[1] = TOLOWER_ASC(p_hlg[4]);
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00001303 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001304 // any C like setting, such as C.UTF-8, becomes "en"
1305 else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C')
1306 {
1307 p_hlg[0] = 'e';
1308 p_hlg[1] = 'n';
1309 }
1310 p_hlg[2] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001312 options[idx].flags |= P_ALLOCED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313}
1314#endif
1315
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316/*
1317 * 'title' and 'icon' only default to true if they have not been set or reset
1318 * in .vimrc and we can read the old value.
1319 * When 'title' and 'icon' have been reset in .vimrc, we won't even check if
1320 * they can be reset. This reduces startup time when using X on a remote
1321 * machine.
1322 */
1323 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01001324set_title_defaults(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325{
1326 int idx1;
1327 long val;
1328
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001329 // If GUI is (going to be) used, we can always set the window title and
1330 // icon name. Saves a bit of time, because the X11 display server does
1331 // not need to be contacted.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 idx1 = findoption((char_u *)"title");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00001333 if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334 {
1335#ifdef FEAT_GUI
1336 if (gui.starting || gui.in_use)
1337 val = TRUE;
1338 else
1339#endif
1340 val = mch_can_restore_title();
Bram Moolenaareb3593b2006-04-22 22:33:57 +00001341 options[idx1].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001342 p_title = val;
1343 }
1344 idx1 = findoption((char_u *)"icon");
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001345 if (idx1 < 0 || (options[idx1].flags & P_WAS_SET))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001346 {
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001347 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348 }
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00001349
1350#ifdef FEAT_GUI
1351 if (gui.starting || gui.in_use)
1352 val = TRUE;
1353 else
1354#endif
1355 val = mch_can_restore_icon();
1356 options[idx1].def_val[VI_DEFAULT] = (char_u *)(long_i)val;
1357 p_icon = val;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359
Bram Moolenaar6b915c02020-01-18 15:53:19 +01001360 void
1361ex_set(exarg_T *eap)
1362{
1363 int flags = 0;
1364
1365 if (eap->cmdidx == CMD_setlocal)
1366 flags = OPT_LOCAL;
1367 else if (eap->cmdidx == CMD_setglobal)
1368 flags = OPT_GLOBAL;
1369#if defined(FEAT_EVAL) && defined(FEAT_BROWSE)
Bram Moolenaare1004402020-10-24 20:49:43 +02001370 if ((cmdmod.cmod_flags & CMOD_BROWSE) && flags == 0)
Bram Moolenaar6b915c02020-01-18 15:53:19 +01001371 ex_options(eap);
1372 else
1373#endif
1374 {
1375 if (eap->forceit)
1376 flags |= OPT_ONECOLUMN;
1377 (void)do_set(eap->arg, flags);
1378 }
1379}
1380
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00001381/*
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001382 * :set boolean option prefix
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00001383 */
Bram Moolenaar47403942022-09-21 21:12:53 +01001384typedef enum {
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00001385 PREFIX_NO = 0, // "no" prefix
1386 PREFIX_NONE, // no prefix
1387 PREFIX_INV, // "inv" prefix
1388} set_prefix_T;
1389
1390/*
1391 * Return the prefix type for the option name in *argp.
1392 */
1393 static set_prefix_T
1394get_option_prefix(char_u **argp)
1395{
1396 int prefix = PREFIX_NONE;
1397 char_u *arg = *argp;
1398
1399 if (STRNCMP(arg, "no", 2) == 0 && STRNCMP(arg, "novice", 6) != 0)
1400 {
1401 prefix = PREFIX_NO;
1402 arg += 2;
1403 }
1404 else if (STRNCMP(arg, "inv", 3) == 0)
1405 {
1406 prefix = PREFIX_INV;
1407 arg += 3;
1408 }
1409
1410 *argp = arg;
1411 return prefix;
1412}
1413
1414/*
1415 * Parse the option name in "arg" and return the option index in "*opt_idxp",
1416 * and the option name length in "*lenp". For a <t_xx> option, return the key
1417 * number in "*keyp".
1418 *
1419 * Returns FAIL if an option starting with "<" doesn't end with a ">",
1420 * otherwise returns OK.
1421 */
1422 static int
1423parse_option_name(char_u *arg, int *opt_idxp, int *lenp, int *keyp)
1424{
1425 int key = 0;
1426 int len;
1427 int opt_idx;
1428
1429 if (*arg == '<')
1430 {
1431 opt_idx = -1;
1432 // look out for <t_>;>
1433 if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4])
1434 len = 5;
1435 else
1436 {
1437 len = 1;
1438 while (arg[len] != NUL && arg[len] != '>')
1439 ++len;
1440 }
1441 if (arg[len] != '>')
1442 return FAIL;
1443
1444 arg[len] = NUL; // put NUL after name
1445 if (arg[1] == 't' && arg[2] == '_') // could be term code
1446 opt_idx = findoption(arg + 1);
1447 arg[len++] = '>'; // restore '>'
1448 if (opt_idx == -1)
1449 key = find_key_option(arg + 1, TRUE);
1450 }
1451 else
1452 {
1453 int nextchar; // next non-white char after option name
1454
1455 len = 0;
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00001456 // The two characters after "t_" may not be alphanumeric.
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00001457 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
1458 len = 4;
1459 else
1460 while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
1461 ++len;
1462 nextchar = arg[len];
1463 arg[len] = NUL; // put NUL after name
1464 opt_idx = findoption(arg);
1465 arg[len] = nextchar; // restore nextchar
1466 if (opt_idx == -1)
1467 key = find_key_option(arg, FALSE);
1468 }
1469
1470 *keyp = key;
1471 *lenp = len;
1472 *opt_idxp = opt_idx;
1473
1474 return OK;
1475}
1476
1477/*
1478 * Get the option operator (+=, ^=, -=).
1479 */
1480 static set_op_T
1481get_opt_op(char_u *arg)
1482{
1483 set_op_T op = OP_NONE;
1484
1485 if (*arg != NUL && *(arg + 1) == '=')
1486 {
1487 if (*arg == '+')
1488 op = OP_ADDING; // "+="
1489 else if (*arg == '^')
1490 op = OP_PREPENDING; // "^="
1491 else if (*arg == '-')
1492 op = OP_REMOVING; // "-="
1493 }
1494
1495 return op;
1496}
1497
1498/*
1499 * Validate whether the value of the option in "opt_idx" can be changed.
1500 * Returns FAIL if the option can be skipped or cannot be changed. Returns OK
1501 * if it can be changed.
1502 */
1503 static int
1504validate_opt_idx(int opt_idx, int opt_flags, long_u flags, char **errmsg)
1505{
1506 // Skip all options that are not window-local (used when showing
1507 // an already loaded buffer in a window).
1508 if ((opt_flags & OPT_WINONLY)
1509 && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
1510 return FAIL;
1511
1512 // Skip all options that are window-local (used for :vimgrep).
1513 if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
1514 && options[opt_idx].var == VAR_WIN)
1515 return FAIL;
1516
1517 // Disallow changing some options from modelines.
1518 if (opt_flags & OPT_MODELINE)
1519 {
1520 if (flags & (P_SECURE | P_NO_ML))
1521 {
1522 *errmsg = e_not_allowed_in_modeline;
1523 return FAIL;
1524 }
1525 if ((flags & P_MLE) && !p_mle)
1526 {
1527 *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off;
1528 return FAIL;
1529 }
1530#ifdef FEAT_DIFF
1531 // In diff mode some options are overruled. This avoids that
1532 // 'foldmethod' becomes "marker" instead of "diff" and that
1533 // "wrap" gets set.
1534 if (curwin->w_p_diff
1535 && opt_idx >= 0 // shut up coverity warning
1536 && (
1537# ifdef FEAT_FOLDING
1538 options[opt_idx].indir == PV_FDM ||
1539# endif
1540 options[opt_idx].indir == PV_WRAP))
1541 return FAIL;
1542#endif
1543 }
1544
1545#ifdef HAVE_SANDBOX
1546 // Disallow changing some options in the sandbox
1547 if (sandbox != 0 && (flags & P_SECURE))
1548 {
1549 *errmsg = e_not_allowed_in_sandbox;
1550 return FAIL;
1551 }
1552#endif
1553
1554 return OK;
1555}
1556
Bram Moolenaar47403942022-09-21 21:12:53 +01001557/*
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00001558 * Get the Vim/Vi default value for a string option.
1559 */
1560 static char_u *
1561stropt_get_default_val(
1562 int opt_idx,
1563 char_u *varp,
1564 int flags,
1565 int cp_val)
1566{
1567 char_u *newval;
1568
1569 newval = options[opt_idx].def_val[((flags & P_VI_DEF) || cp_val)
1570 ? VI_DEFAULT : VIM_DEFAULT];
1571 if ((char_u **)varp == &p_bg)
1572 {
1573 // guess the value of 'background'
1574#ifdef FEAT_GUI
1575 if (gui.in_use)
1576 newval = gui_bg_default();
1577 else
1578#endif
1579 newval = term_bg_default();
1580 }
1581 else if ((char_u **)varp == &p_fencs && enc_utf8)
1582 newval = fencs_utf8_default;
1583
1584 // expand environment variables and ~ since the default value was
1585 // already expanded, only required when an environment variable was set
1586 // later
1587 if (newval == NULL)
1588 newval = empty_option;
1589 else
1590 {
1591 char_u *s = option_expand(opt_idx, newval);
1592 if (s == NULL)
1593 s = newval;
1594 newval = vim_strsave(s);
1595 }
1596
1597 return newval;
1598}
1599
1600/*
1601 * Convert the 'backspace' option number value to a string: for adding,
1602 * prepending and removing string.
1603 */
1604 static void
1605opt_backspace_nr2str(
1606 char_u *varp,
1607 char_u **origval_p,
1608 char_u **origval_l_p,
1609 char_u **origval_g_p,
1610 char_u **oldval_p)
1611{
1612 int i = getdigits((char_u **)varp);
1613
1614 switch (i)
1615 {
1616 case 0:
1617 *(char_u **)varp = empty_option;
1618 break;
1619 case 1:
1620 *(char_u **)varp = vim_strsave((char_u *)"indent,eol");
1621 break;
1622 case 2:
1623 *(char_u **)varp = vim_strsave((char_u *)"indent,eol,start");
1624 break;
1625 case 3:
1626 *(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop");
1627 break;
1628 }
1629 vim_free(*oldval_p);
1630 if (*origval_p == *oldval_p)
1631 *origval_p = *(char_u **)varp;
1632 if (*origval_l_p == *oldval_p)
1633 *origval_l_p = *(char_u **)varp;
1634 if (*origval_g_p == *oldval_p)
1635 *origval_g_p = *(char_u **)varp;
1636 *oldval_p = *(char_u **)varp;
1637}
1638
1639/*
1640 * Convert the 'whichwrap' option number value to a string, for backwards
1641 * compatibility with Vim 3.0.
1642 * Note: 'argp' is a pointer to a char_u pointer and is updated.
1643 */
1644 static char_u *
1645opt_whichwrap_nr2str(char_u **argp, char_u *whichwrap)
1646{
1647 *whichwrap = NUL;
1648 int i = getdigits(argp);
1649 if (i & 1)
1650 STRCAT(whichwrap, "b,");
1651 if (i & 2)
1652 STRCAT(whichwrap, "s,");
1653 if (i & 4)
1654 STRCAT(whichwrap, "h,l,");
1655 if (i & 8)
1656 STRCAT(whichwrap, "<,>,");
1657 if (i & 16)
1658 STRCAT(whichwrap, "[,],");
1659 if (*whichwrap != NUL) // remove trailing ,
1660 whichwrap[STRLEN(whichwrap) - 1] = NUL;
1661
1662 return whichwrap;
1663}
1664
1665/*
1666 * Copy the new string value into allocated memory for the option.
1667 * Can't use set_string_option_direct(), because we need to remove the
1668 * backslashes.
1669 */
1670 static char_u *
1671stropt_copy_value(
1672 char_u *origval,
1673 char_u **argp,
1674 set_op_T op,
1675 int flags UNUSED)
1676{
1677 char_u *arg = *argp;
1678 unsigned newlen;
1679 char_u *newval;
1680 char_u *s = NULL;
1681
1682 // get a bit too much
1683 newlen = (unsigned)STRLEN(arg) + 1;
1684 if (op != OP_NONE)
1685 newlen += (unsigned)STRLEN(origval) + 1;
1686 newval = alloc(newlen);
1687 if (newval == NULL) // out of mem, don't change
1688 return NULL;
1689 s = newval;
1690
1691 // Copy the string, skip over escaped chars.
1692 // For MS-DOS and WIN32 backslashes before normal file name characters
1693 // are not removed, and keep backslash at start, for "\\machine\path",
1694 // but do remove it for "\\\\machine\\path".
Yee Cheng Chin900894b2023-09-29 20:42:32 +02001695 // The reverse is found in escape_option_str_cmdline().
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00001696 while (*arg != NUL && !VIM_ISWHITE(*arg))
1697 {
1698 int i;
1699
1700 if (*arg == '\\' && arg[1] != NUL
1701#ifdef BACKSLASH_IN_FILENAME
1702 && !((flags & P_EXPAND)
1703 && vim_isfilec(arg[1])
1704 && !VIM_ISWHITE(arg[1])
1705 && (arg[1] != '\\'
1706 || (s == newval && arg[2] != '\\')))
1707#endif
1708 )
1709 ++arg; // remove backslash
1710 if (has_mbyte && (i = (*mb_ptr2len)(arg)) > 1)
1711 {
1712 // copy multibyte char
1713 mch_memmove(s, arg, (size_t)i);
1714 arg += i;
1715 s += i;
1716 }
1717 else
1718 *s++ = *arg++;
1719 }
1720 *s = NUL;
1721
1722 *argp = arg;
1723 return newval;
1724}
1725
1726/*
1727 * Expand environment variables and ~ in string option value 'newval'.
1728 */
1729 static char_u *
1730stropt_expand_envvar(
1731 int opt_idx,
1732 char_u *origval,
1733 char_u *newval,
1734 set_op_T op)
1735{
1736 char_u *s = option_expand(opt_idx, newval);
1737 if (s == NULL)
1738 return newval;
1739
1740 vim_free(newval);
1741 unsigned newlen = (unsigned)STRLEN(s) + 1;
1742 if (op != OP_NONE)
1743 newlen += (unsigned)STRLEN(origval) + 1;
1744
1745 newval = alloc(newlen);
1746 if (newval == NULL)
1747 return NULL;
1748
1749 STRCPY(newval, s);
1750
1751 return newval;
1752}
1753
1754/*
1755 * Concatenate the original and new values of a string option, adding a "," if
1756 * needed.
1757 */
1758 static void
1759stropt_concat_with_comma(
1760 char_u *origval,
1761 char_u *newval,
1762 set_op_T op,
1763 int flags)
1764{
1765 int len = 0;
1766
1767 int comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL);
1768 if (op == OP_ADDING)
1769 {
1770 len = (int)STRLEN(origval);
1771 // strip a trailing comma, would get 2
1772 if (comma && len > 1
1773 && (flags & P_ONECOMMA) == P_ONECOMMA
1774 && origval[len - 1] == ','
1775 && origval[len - 2] != '\\')
1776 len--;
1777 mch_memmove(newval + len + comma, newval, STRLEN(newval) + 1);
1778 mch_memmove(newval, origval, (size_t)len);
1779 }
1780 else
1781 {
1782 len = (int)STRLEN(newval);
1783 STRMOVE(newval + len + comma, origval);
1784 }
1785 if (comma)
1786 newval[len] = ',';
1787}
1788
1789/*
1790 * Remove a value from a string option. Copy string option value in "origval"
1791 * to "newval" and then remove the string "strval" of length "len".
1792 */
1793 static void
1794stropt_remove_val(
1795 char_u *origval,
1796 char_u *newval,
1797 int flags,
1798 char_u *strval,
1799 int len)
1800{
1801 // Remove newval[] from origval[]. (Note: "len" has been set above
1802 // and is used here).
1803 STRCPY(newval, origval);
1804 if (*strval)
1805 {
1806 // may need to remove a comma
1807 if (flags & P_COMMA)
1808 {
1809 if (strval == origval)
1810 {
1811 // include comma after string
1812 if (strval[len] == ',')
1813 ++len;
1814 }
1815 else
1816 {
1817 // include comma before string
1818 --strval;
1819 ++len;
1820 }
1821 }
1822 STRMOVE(newval + (strval - origval), strval + len);
1823 }
1824}
1825
1826/*
1827 * Remove flags that appear twice in the string option value 'newval'.
1828 */
1829 static void
1830stropt_remove_dupflags(char_u *newval, int flags)
1831{
1832 char_u *s = newval;
1833
1834 // Remove flags that appear twice.
1835 while (*s)
1836 {
1837 // if options have P_FLAGLIST and P_ONECOMMA such as 'whichwrap'
1838 if (flags & P_ONECOMMA)
1839 {
1840 if (*s != ',' && *(s + 1) == ',' && vim_strchr(s + 2, *s) != NULL)
1841 {
1842 // Remove the duplicated value and the next comma.
1843 STRMOVE(s, s + 2);
1844 continue;
1845 }
1846 }
1847 else
1848 {
1849 if ((!(flags & P_COMMA) || *s != ',')
1850 && vim_strchr(s + 1, *s) != NULL)
1851 {
1852 STRMOVE(s, s + 1);
1853 continue;
1854 }
1855 }
1856 ++s;
1857 }
1858}
1859
1860/*
1861 * Get the string value specified for a ":set" command. The following set
1862 * options are supported:
1863 * set {opt}&
1864 * set {opt}<
1865 * set {opt}={val}
1866 * set {opt}:{val}
1867 */
1868 static char_u *
1869stropt_get_newval(
1870 int nextchar,
1871 int opt_idx,
1872 char_u **argp,
1873 char_u *varp,
1874 char_u **origval_arg,
1875 char_u **origval_l_arg,
1876 char_u **origval_g_arg,
1877 char_u **oldval_arg,
1878 set_op_T *op_arg,
1879 int flags,
1880 int cp_val)
1881{
1882 char_u *arg = *argp;
1883 char_u *origval = *origval_arg;
1884 char_u *origval_l = *origval_l_arg;
1885 char_u *origval_g = *origval_g_arg;
1886 char_u *oldval = *oldval_arg;
1887 set_op_T op = *op_arg;
1888 char_u *save_arg = NULL;
1889 char_u *newval;
1890 char_u *s = NULL;
1891 char_u whichwrap[80];
1892
1893 if (nextchar == '&') // set to default val
1894 newval = stropt_get_default_val(opt_idx, varp, flags, cp_val);
1895 else if (nextchar == '<') // set to global val
1896 newval = vim_strsave(*(char_u **)get_varp_scope(
1897 &(options[opt_idx]), OPT_GLOBAL));
1898 else
1899 {
Yee Cheng Chin6d113472023-10-02 21:38:39 +02001900 ++arg; // jump to after the '=' or ':'
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00001901
1902 // Set 'keywordprg' to ":help" if an empty
1903 // value was passed to :set by the user.
1904 if (varp == (char_u *)&p_kp && (*arg == NUL || *arg == ' '))
1905 {
1906 save_arg = arg;
1907 arg = (char_u *)":help";
1908 }
1909 // Convert 'backspace' number to string
1910 else if (varp == (char_u *)&p_bs && VIM_ISDIGIT(**(char_u **)varp))
1911 opt_backspace_nr2str(varp, &origval, &origval_l, &origval_g,
1912 &oldval);
1913 else if (varp == (char_u *)&p_ww && VIM_ISDIGIT(*arg))
1914 {
1915 // Convert 'whichwrap' number to string, for backwards
1916 // compatibility with Vim 3.0.
1917 char_u *t = opt_whichwrap_nr2str(&arg, whichwrap);
1918 save_arg = arg;
1919 arg = t;
1920 }
1921 // Remove '>' before 'dir' and 'bdir', for backwards compatibility with
1922 // version 3.0
1923 else if (*arg == '>' && (varp == (char_u *)&p_dir
1924 || varp == (char_u *)&p_bdir))
1925 ++arg;
1926
1927 // Copy the new string into allocated memory.
1928 newval = stropt_copy_value(origval, &arg, op, flags);
1929 if (newval == NULL)
1930 goto done;
1931
1932 // Expand environment variables and ~.
1933 // Don't do it when adding without inserting a comma.
1934 if (op == OP_NONE || (flags & P_COMMA))
1935 {
1936 newval = stropt_expand_envvar(opt_idx, origval, newval, op);
1937 if (newval == NULL)
1938 goto done;
1939 }
1940
1941 // locate newval[] in origval[] when removing it and when adding to
1942 // avoid duplicates
1943 int len = 0;
1944 if (op == OP_REMOVING || (flags & P_NODUP))
1945 {
1946 len = (int)STRLEN(newval);
1947 s = find_dup_item(origval, newval, flags);
1948
1949 // do not add if already there
1950 if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL)
1951 {
1952 op = OP_NONE;
1953 STRCPY(newval, origval);
1954 }
1955
1956 // if no duplicate, move pointer to end of original value
1957 if (s == NULL)
1958 s = origval + (int)STRLEN(origval);
1959 }
1960
1961 // concatenate the two strings; add a ',' if needed
1962 if (op == OP_ADDING || op == OP_PREPENDING)
1963 stropt_concat_with_comma(origval, newval, op, flags);
1964 else if (op == OP_REMOVING)
1965 // Remove newval[] from origval[]. (Note: "len" has been set above
1966 // and is used here).
1967 stropt_remove_val(origval, newval, flags, s, len);
1968
1969 if (flags & P_FLAGLIST)
1970 // Remove flags that appear twice.
1971 stropt_remove_dupflags(newval, flags);
1972 }
1973
1974done:
1975 if (save_arg != NULL)
1976 arg = save_arg; // arg was temporarily changed, restore it
1977 *argp = arg;
1978 *origval_arg = origval;
1979 *origval_l_arg = origval_l;
1980 *origval_g_arg = origval_g;
1981 *oldval_arg = oldval;
1982 *op_arg = op;
1983
1984 return newval;
1985}
1986
1987/*
Bram Moolenaar47403942022-09-21 21:12:53 +01001988 * Part of do_set() for string options.
1989 * Returns FAIL on failure, do not process further options.
1990 */
1991 static int
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00001992do_set_option_string(
Bram Moolenaar47403942022-09-21 21:12:53 +01001993 int opt_idx,
1994 int opt_flags,
Bram Moolenaar6f981142022-09-22 12:48:58 +01001995 char_u **argp,
Bram Moolenaar47403942022-09-21 21:12:53 +01001996 int nextchar,
1997 set_op_T op_arg,
Yee Cheng Chin6ee7b522023-10-01 09:13:22 +02001998 long_u flags,
Bram Moolenaar47403942022-09-21 21:12:53 +01001999 int cp_val,
2000 char_u *varp_arg,
2001 char *errbuf,
Mike Williams620f0112023-12-05 15:36:06 +01002002 size_t errbuflen,
Bram Moolenaar47403942022-09-21 21:12:53 +01002003 int *value_checked,
2004 char **errmsg)
2005{
Bram Moolenaar6f981142022-09-22 12:48:58 +01002006 char_u *arg = *argp;
Bram Moolenaar47403942022-09-21 21:12:53 +01002007 set_op_T op = op_arg;
2008 char_u *varp = varp_arg;
Bram Moolenaar47403942022-09-21 21:12:53 +01002009 char_u *oldval = NULL; // previous value if *varp
2010 char_u *newval;
2011 char_u *origval = NULL;
2012 char_u *origval_l = NULL;
2013 char_u *origval_g = NULL;
2014#if defined(FEAT_EVAL)
2015 char_u *saved_origval = NULL;
2016 char_u *saved_origval_l = NULL;
2017 char_u *saved_origval_g = NULL;
2018 char_u *saved_newval = NULL;
2019#endif
Bram Moolenaar47403942022-09-21 21:12:53 +01002020
2021 // When using ":set opt=val" for a global option
2022 // with a local value the local value will be
2023 // reset, use the global value here.
2024 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
2025 && ((int)options[opt_idx].indir & PV_BOTH))
2026 varp = options[opt_idx].var;
2027
2028 // The old value is kept until we are sure that the new value is valid.
2029 oldval = *(char_u **)varp;
2030
2031 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
2032 {
2033 origval_l = *(char_u **)get_varp_scope(
2034 &(options[opt_idx]), OPT_LOCAL);
2035 origval_g = *(char_u **)get_varp_scope(
2036 &(options[opt_idx]), OPT_GLOBAL);
2037
2038 // A global-local string option might have an empty option as value to
2039 // indicate that the global value should be used.
2040 if (((int)options[opt_idx].indir & PV_BOTH)
2041 && origval_l == empty_option)
2042 origval_l = origval_g;
2043 }
2044
2045 // When setting the local value of a global option, the old value may be
2046 // the global value.
2047 if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL))
2048 origval = *(char_u **)get_varp(&options[opt_idx]);
2049 else
2050 origval = oldval;
2051
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00002052 // Get the new value for the option
2053 newval = stropt_get_newval(nextchar, opt_idx, &arg, varp, &origval,
2054 &origval_l, &origval_g, &oldval, &op, flags,
2055 cp_val);
Bram Moolenaar47403942022-09-21 21:12:53 +01002056
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00002057 // Set the new value.
Bram Moolenaar47403942022-09-21 21:12:53 +01002058 *(char_u **)(varp) = newval;
Bram Moolenaar339e1142023-02-15 14:26:25 +00002059 if (newval == NULL)
2060 *(char_u **)(varp) = empty_option;
Bram Moolenaar47403942022-09-21 21:12:53 +01002061
2062#if defined(FEAT_EVAL)
2063 if (!starting
2064# ifdef FEAT_CRYPT
2065 && options[opt_idx].indir != PV_KEY
2066# endif
2067 && origval != NULL && newval != NULL)
2068 {
2069 // origval may be freed by did_set_string_option(), make a copy.
2070 saved_origval = vim_strsave(origval);
2071 // newval (and varp) may become invalid if the buffer is closed by
2072 // autocommands.
2073 saved_newval = vim_strsave(newval);
2074 if (origval_l != NULL)
2075 saved_origval_l = vim_strsave(origval_l);
2076 if (origval_g != NULL)
2077 saved_origval_g = vim_strsave(origval_g);
2078 }
2079#endif
2080
2081 {
2082 long_u *p = insecure_flag(opt_idx, opt_flags);
2083 int secure_saved = secure;
2084
2085 // When an option is set in the sandbox, from a modeline or in secure
2086 // mode, then deal with side effects in secure mode. Also when the
2087 // value was set with the P_INSECURE flag and is not completely
2088 // replaced.
2089 if ((opt_flags & OPT_MODELINE)
2090#ifdef HAVE_SANDBOX
2091 || sandbox != 0
2092#endif
2093 || (op != OP_NONE && (*p & P_INSECURE)))
2094 secure = 1;
2095
2096 // Handle side effects, and set the global value for ":set" on local
2097 // options. Note: when setting 'syntax' or 'filetype' autocommands may
2098 // be triggered that can cause havoc.
2099 *errmsg = did_set_string_option(
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002100 opt_idx, (char_u **)varp, oldval, newval, errbuf,
Christian Brabandtb39b2402023-11-29 11:34:05 +01002101 errbuflen, opt_flags, op, value_checked);
Bram Moolenaar47403942022-09-21 21:12:53 +01002102
2103 secure = secure_saved;
2104 }
2105
2106#if defined(FEAT_EVAL)
2107 if (*errmsg == NULL)
zeertzjq269aa2b2022-11-28 11:36:50 +00002108 trigger_optionset_string(opt_idx, opt_flags, saved_origval,
Bram Moolenaar47403942022-09-21 21:12:53 +01002109 saved_origval_l, saved_origval_g, saved_newval);
2110 vim_free(saved_origval);
2111 vim_free(saved_origval_l);
2112 vim_free(saved_origval_g);
2113 vim_free(saved_newval);
2114#endif
2115
Bram Moolenaar6f981142022-09-22 12:48:58 +01002116 *argp = arg;
Bram Moolenaar47403942022-09-21 21:12:53 +01002117 return *errmsg == NULL ? OK : FAIL;
2118}
2119
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120/*
Bram Moolenaar546933f2023-02-06 16:40:49 +00002121 * Set a boolean option.
2122 * Returns an untranslated error message or NULL.
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002123 */
2124 static char *
2125do_set_option_bool(
2126 int opt_idx,
2127 int opt_flags,
2128 set_prefix_T prefix,
2129 long_u flags,
2130 char_u *varp,
2131 int nextchar,
2132 int afterchar,
2133 int cp_val)
2134
2135{
2136 varnumber_T value;
2137
2138 if (nextchar == '=' || nextchar == ':')
2139 return e_invalid_argument;
Bram Moolenaar546933f2023-02-06 16:40:49 +00002140 if (opt_idx < 0 || varp == NULL)
2141 return NULL; // "cannot happen"
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002142
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002143 // ":set opt!": invert
2144 // ":set opt&": reset to default value
2145 // ":set opt<": reset to global value
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002146 if (nextchar == '!')
2147 value = *(int *)(varp) ^ 1;
2148 else if (nextchar == '&')
2149 value = (int)(long)(long_i)options[opt_idx].def_val[
2150 ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
2151 else if (nextchar == '<')
2152 {
2153 // For 'autoread' -1 means to use global value.
2154 if ((int *)varp == &curbuf->b_p_ar && opt_flags == OPT_LOCAL)
2155 value = -1;
2156 else
2157 value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
2158 }
2159 else
2160 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002161 // ":set invopt": invert
2162 // ":set opt" or ":set noopt": set or reset
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002163 if (nextchar != NUL && !VIM_ISWHITE(afterchar))
2164 return e_trailing_characters;
2165 if (prefix == PREFIX_INV)
2166 value = *(int *)(varp) ^ 1;
2167 else
2168 value = prefix == PREFIX_NO ? 0 : 1;
2169 }
2170
2171 return set_bool_option(opt_idx, varp, (int)value, opt_flags);
2172}
2173
2174/*
Bram Moolenaar546933f2023-02-06 16:40:49 +00002175 * Set a numeric option.
2176 * Returns an untranslated error message or NULL.
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002177 */
2178 static char *
2179do_set_option_numeric(
2180 int opt_idx,
2181 int opt_flags,
2182 char_u **argp,
2183 int nextchar,
2184 set_op_T op,
2185 long_u flags,
2186 int cp_val,
2187 char_u *varp,
2188 char *errbuf,
2189 size_t errbuflen)
2190{
2191 char_u *arg = *argp;
2192 varnumber_T value;
2193 int i;
2194 char *errmsg = NULL;
2195
Bram Moolenaar546933f2023-02-06 16:40:49 +00002196 if (opt_idx < 0 || varp == NULL)
2197 return NULL; // "cannot happen"
2198 //
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002199 /*
2200 * Different ways to set a number option:
2201 * & set to default value
2202 * < set to global value
2203 * <xx> accept special key codes for 'wildchar'
2204 * c accept any non-digit for 'wildchar'
2205 * [-]0-9 set number
2206 * other error
2207 */
2208 ++arg;
2209 if (nextchar == '&')
2210 value = (long)(long_i)options[opt_idx].def_val[
2211 ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
2212 else if (nextchar == '<')
2213 {
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002214 if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL)
Bram Moolenaarbf5f1892023-06-27 21:51:07 +01002215 // for 'undolevels' NO_LOCAL_UNDOLEVEL means using the global value
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002216 value = NO_LOCAL_UNDOLEVEL;
Bram Moolenaarbf5f1892023-06-27 21:51:07 +01002217 else if (opt_flags == OPT_LOCAL
2218 && ((long *)varp == &curwin->w_p_siso
2219 || (long *)varp == &curwin->w_p_so))
2220 // for 'scrolloff'/'sidescrolloff' -1 means using the global value
2221 value = -1;
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002222 else
2223 value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
2224 }
2225 else if (((long *)varp == &p_wc || (long *)varp == &p_wcm)
2226 && (*arg == '<'
2227 || *arg == '^'
2228 || (*arg != NUL
2229 && (!arg[1] || VIM_ISWHITE(arg[1]))
2230 && !VIM_ISDIGIT(*arg))))
2231 {
2232 value = string_to_key(arg, FALSE);
2233 if (value == 0 && (long *)varp != &p_wcm)
2234 {
2235 errmsg = e_invalid_argument;
2236 goto skip;
2237 }
2238 }
2239 else if (*arg == '-' || VIM_ISDIGIT(*arg))
2240 {
2241 // Allow negative (for 'undolevels'), octal and hex numbers.
Bram Moolenaar5fb78c32023-03-04 20:47:39 +00002242 vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE, NULL);
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002243 if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
2244 {
2245 errmsg = e_number_required_after_equal;
2246 goto skip;
2247 }
2248 }
2249 else
2250 {
2251 errmsg = e_number_required_after_equal;
2252 goto skip;
2253 }
2254
2255 if (op == OP_ADDING)
2256 value = *(long *)varp + value;
2257 else if (op == OP_PREPENDING)
2258 value = *(long *)varp * value;
2259 else if (op == OP_REMOVING)
2260 value = *(long *)varp - value;
2261
2262 errmsg = set_num_option(opt_idx, varp, value, errbuf, errbuflen,
2263 opt_flags);
2264
2265skip:
2266 *argp = arg;
2267 return errmsg;
2268}
2269
2270/*
2271 * Set a key code (t_xx) option
2272 */
2273 static char *
2274do_set_option_keycode(char_u **argp, char_u *key_name, int nextchar)
2275{
2276 char_u *arg = *argp;
2277 char_u *p;
2278
2279 if (nextchar == '&')
2280 {
2281 if (add_termcap_entry(key_name, TRUE) == FAIL)
2282 return e_not_found_in_termcap;
2283 }
2284 else
2285 {
2286 ++arg; // jump to after the '=' or ':'
2287 for (p = arg; *p && !VIM_ISWHITE(*p); ++p)
2288 if (*p == '\\' && p[1] != NUL)
2289 ++p;
2290 nextchar = *p;
2291 *p = NUL;
2292 add_termcode(key_name, arg, FALSE);
2293 *p = nextchar;
2294 }
2295 if (full_screen)
2296 ttest(FALSE);
2297 redraw_all_later(UPD_CLEAR);
2298
2299 *argp = arg;
2300 return NULL;
2301}
2302
2303/*
2304 * Set an option to a new value.
2305 */
2306 static char *
2307do_set_option_value(
2308 int opt_idx,
2309 int opt_flags,
2310 char_u **argp,
2311 set_prefix_T prefix,
2312 set_op_T op,
2313 long_u flags,
2314 char_u *varp,
2315 char_u *key_name,
2316 int nextchar,
2317 int afterchar,
2318 int cp_val,
2319 int *stopopteval,
2320 char *errbuf,
2321 size_t errbuflen)
2322{
2323 int value_checked = FALSE;
2324 char *errmsg = NULL;
2325 char_u *arg = *argp;
2326
2327 if (flags & P_BOOL)
2328 {
2329 // boolean option
2330 errmsg = do_set_option_bool(opt_idx, opt_flags, prefix, flags, varp,
2331 nextchar, afterchar, cp_val);
2332 if (errmsg != NULL)
2333 goto skip;
2334 }
2335 else
2336 {
2337 // numeric or string option
2338 if (vim_strchr((char_u *)"=:&<", nextchar) == NULL
2339 || prefix != PREFIX_NONE)
2340 {
2341 errmsg = e_invalid_argument;
2342 goto skip;
2343 }
2344
2345 if (flags & P_NUM)
2346 {
2347 // numeric option
2348 errmsg = do_set_option_numeric(opt_idx, opt_flags, &arg, nextchar,
2349 op, flags, cp_val, varp,
2350 errbuf, errbuflen);
2351 if (errmsg != NULL)
2352 goto skip;
2353 }
2354 else if (opt_idx >= 0)
2355 {
2356 // string option
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00002357 if (do_set_option_string(opt_idx, opt_flags, &arg, nextchar, op,
Christian Brabandtb39b2402023-11-29 11:34:05 +01002358 flags, cp_val, varp, errbuf, errbuflen,
Yegappan Lakshmanan1a647642023-02-14 13:07:18 +00002359 &value_checked, &errmsg) == FAIL)
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002360 {
2361 if (errmsg != NULL)
2362 goto skip;
2363 *stopopteval = TRUE;
2364 goto skip;
2365 }
2366 }
2367 else
2368 {
2369 // key code option
2370 errmsg = do_set_option_keycode(&arg, key_name, nextchar);
2371 if (errmsg != NULL)
2372 goto skip;
2373 }
2374 }
2375
2376 if (opt_idx >= 0)
2377 did_set_option(opt_idx, opt_flags, op == OP_NONE, value_checked);
2378
2379skip:
2380 *argp = arg;
2381 return errmsg;
2382}
2383
2384/*
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002385 * Set an option to a new value.
2386 * Return NULL if OK, return an untranslated error message when something is
2387 * wrong. "errbuf[errbuflen]" can be used to create the error message.
2388 */
2389 static char *
2390do_set_option(
2391 int opt_flags,
2392 char_u **argp,
2393 char_u *arg_start,
2394 char_u **startarg,
2395 int *did_show,
2396 int *stopopteval,
2397 char *errbuf,
2398 size_t errbuflen)
2399{
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002400 int opt_idx;
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002401 char_u *arg;
2402 set_prefix_T prefix; // no prefix, "no" prefix or "inv" prefix
2403 set_op_T op;
2404 long_u flags; // flags for current option
2405 char_u *varp; // pointer to variable for current option
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002406 char_u key_name[2];
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002407 int nextchar; // next non-white char after option name
2408 int afterchar; // character just after option name
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002409 char *errmsg = NULL;
2410 int key;
2411 int len;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002412
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002413 prefix = get_option_prefix(argp);
2414 arg = *argp;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002415
2416 // find end of name
2417 key = 0;
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002418 if (parse_option_name(arg, &opt_idx, &len, &key) == FAIL)
2419 return e_invalid_argument;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002420
2421 // remember character after option name
2422 afterchar = arg[len];
2423
2424 if (in_vim9script())
2425 {
2426 char_u *p = skipwhite(arg + len);
2427
2428 // disallow white space before =val, +=val, -=val, ^=val
2429 if (p > arg + len && (p[0] == '='
2430 || (vim_strchr((char_u *)"+-^", p[0]) != NULL
2431 && p[1] == '=')))
2432 {
2433 errmsg = e_no_white_space_allowed_between_option_and;
2434 arg = p;
2435 *startarg = p;
2436 goto skip;
2437 }
2438 }
2439 else
2440 // skip white space, allow ":set ai ?", ":set hlsearch !"
2441 while (VIM_ISWHITE(arg[len]))
2442 ++len;
2443
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002444 op = get_opt_op(arg + len);
2445 if (op != OP_NONE)
2446 len++;
2447
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002448 nextchar = arg[len];
2449
2450 if (opt_idx == -1 && key == 0) // found a mismatch: skip
2451 {
2452 if (in_vim9script() && arg > arg_start
2453 && vim_strchr((char_u *)"!&<", *arg) != NULL)
2454 errmsg = e_no_white_space_allowed_between_option_and;
2455 else
2456 errmsg = e_unknown_option;
2457 goto skip;
2458 }
2459
2460 if (opt_idx >= 0)
2461 {
2462 if (options[opt_idx].var == NULL) // hidden option: skip
2463 {
2464 // Only give an error message when requesting the value of
2465 // a hidden option, ignore setting it.
2466 if (vim_strchr((char_u *)"=:!&<", nextchar) == NULL
2467 && (!(options[opt_idx].flags & P_BOOL)
2468 || nextchar == '?'))
2469 errmsg = e_option_not_supported;
2470 goto skip;
2471 }
2472
2473 flags = options[opt_idx].flags;
2474 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
2475 }
2476 else
2477 {
2478 flags = P_STRING;
Bram Moolenaar40b48722023-02-05 17:04:50 +00002479 varp = NULL;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002480 if (key < 0)
2481 {
2482 key_name[0] = KEY2TERMCAP0(key);
2483 key_name[1] = KEY2TERMCAP1(key);
2484 }
2485 else
2486 {
2487 key_name[0] = KS_KEY;
2488 key_name[1] = (key & 0xff);
2489 }
2490 }
2491
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002492 // Make sure the option value can be changed.
2493 if (validate_opt_idx(opt_idx, opt_flags, flags, &errmsg) == FAIL)
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002494 goto skip;
2495
Bram Moolenaar40b48722023-02-05 17:04:50 +00002496 int cp_val = p_cp;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002497 if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL)
2498 {
2499 arg += len;
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002500 if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i')
2501 {
2502 if (arg[3] == 'm') // "opt&vim": set to Vim default
2503 {
2504 cp_val = FALSE;
2505 arg += 3;
2506 }
2507 else // "opt&vi": set to Vi default
2508 {
2509 cp_val = TRUE;
2510 arg += 2;
2511 }
2512 }
2513 if (vim_strchr((char_u *)"?!&<", nextchar) != NULL
2514 && arg[1] != NUL && !VIM_ISWHITE(arg[1]))
2515 {
2516 errmsg = e_trailing_characters;
2517 goto skip;
2518 }
2519 }
2520
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002521 // Allow '=' and ':' for historical reasons (MSDOS command.com).
2522 // Allows only one '=' character per "set" command line. grrr. (jw)
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002523 if (nextchar == '?'
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002524 || (prefix == PREFIX_NONE
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002525 && vim_strchr((char_u *)"=:&<", nextchar) == NULL
2526 && !(flags & P_BOOL)))
2527 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002528 // print value
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002529 if (*did_show)
2530 msg_putchar('\n'); // cursor below last one
2531 else
2532 {
2533 gotocmdline(TRUE); // cursor at status line
2534 *did_show = TRUE; // remember that we did a line
2535 }
2536 if (opt_idx >= 0)
2537 {
2538 showoneopt(&options[opt_idx], opt_flags);
2539#ifdef FEAT_EVAL
2540 if (p_verbose > 0)
2541 {
2542 // Mention where the option was last set.
2543 if (varp == options[opt_idx].var)
2544 last_set_msg(options[opt_idx].script_ctx);
2545 else if ((int)options[opt_idx].indir & PV_WIN)
2546 last_set_msg(curwin->w_p_script_ctx[
2547 (int)options[opt_idx].indir & PV_MASK]);
2548 else if ((int)options[opt_idx].indir & PV_BUF)
2549 last_set_msg(curbuf->b_p_script_ctx[
2550 (int)options[opt_idx].indir & PV_MASK]);
2551 }
2552#endif
2553 }
2554 else
2555 {
2556 char_u *p;
2557
2558 p = find_termcode(key_name);
2559 if (p == NULL)
2560 {
2561 errmsg = e_key_code_not_set;
2562 goto skip;
2563 }
2564 else
2565 (void)show_one_termcode(key_name, p, TRUE);
2566 }
2567 if (nextchar != '?'
2568 && nextchar != NUL && !VIM_ISWHITE(afterchar))
2569 errmsg = e_trailing_characters;
2570 }
2571 else
2572 {
Yegappan Lakshmananc72078b2023-02-05 16:02:35 +00002573 errmsg = do_set_option_value(opt_idx, opt_flags, &arg, prefix, op,
2574 flags, varp, key_name, nextchar,
2575 afterchar, cp_val, stopopteval, errbuf,
2576 errbuflen);
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002577 }
2578
2579skip:
2580 *argp = arg;
2581 return errmsg;
2582}
2583
2584/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 * Parse 'arg' for option settings.
2586 *
2587 * 'arg' may be IObuff, but only when no errors can be present and option
2588 * does not need to be expanded with option_expand().
2589 * "opt_flags":
2590 * 0 for ":set"
Bram Moolenaar15a24f02021-12-03 20:43:24 +00002591 * OPT_GLOBAL for ":setglobal"
2592 * OPT_LOCAL for ":setlocal" and a modeline
2593 * OPT_MODELINE for a modeline
2594 * OPT_WINONLY to only set window-local options
2595 * OPT_NOWIN to skip setting window-local options
2596 * OPT_ONECOLUMN do not use multiple columns
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 *
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002598 * Returns FAIL if an error is detected, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599 */
2600 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002601do_set(
Bram Moolenaar1594f312021-07-08 16:40:13 +02002602 char_u *arg_start, // option string (may be written to!)
Bram Moolenaar9b578142016-01-30 19:39:49 +01002603 int opt_flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002604{
Bram Moolenaar1594f312021-07-08 16:40:13 +02002605 char_u *arg = arg_start;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 int i;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002607 int did_show = FALSE; // already showed one value
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608
2609 if (*arg == NUL)
2610 {
2611 showoptions(0, opt_flags);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002612 did_show = TRUE;
2613 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 }
2615
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002616 while (*arg != NUL) // loop to process all options
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 {
zeertzjq0ef9a5c2023-01-17 21:38:25 +00002618 if (STRNCMP(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3])
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002619 && !(opt_flags & OPT_MODELINE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002621 // ":set all" show all options.
2622 // ":set all&" set all options to their default value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 arg += 3;
2624 if (*arg == '&')
2625 {
2626 ++arg;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002627 // Only for :set command set global value of local options.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 set_options_default(OPT_FREE | opt_flags);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002629 didset_options();
2630 didset_options2();
Bram Moolenaara4d158b2022-08-14 14:17:45 +01002631 redraw_all_later(UPD_CLEAR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632 }
2633 else
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002634 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635 showoptions(1, opt_flags);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002636 did_show = TRUE;
2637 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002639 else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 {
2641 showoptions(2, opt_flags);
Bram Moolenaar15a24f02021-12-03 20:43:24 +00002642 show_termcodes(opt_flags);
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002643 did_show = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 arg += 7;
2645 }
2646 else
2647 {
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002648 int stopopteval = FALSE;
2649 char *errmsg = NULL;
Christian Brabandtb39b2402023-11-29 11:34:05 +01002650 char errbuf[ERR_BUFLEN];
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002651 char_u *startarg = arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002653 errmsg = do_set_option(opt_flags, &arg, arg_start, &startarg,
2654 &did_show, &stopopteval, errbuf,
Christian Brabandtb39b2402023-11-29 11:34:05 +01002655 ERR_BUFLEN);
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002656 if (stopopteval)
2657 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002659 // Advance to next argument.
2660 // - skip until a blank found, taking care of backslashes
2661 // - skip blanks
2662 // - skip one "=val" argument (for hidden options ":set gfn =xx")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 for (i = 0; i < 2 ; ++i)
2664 {
Bram Moolenaar1c465442017-03-12 20:10:05 +01002665 while (*arg != NUL && !VIM_ISWHITE(*arg))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666 if (*arg++ == '\\' && *arg != NUL)
2667 ++arg;
2668 arg = skipwhite(arg);
2669 if (*arg != '=')
2670 break;
2671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002673 if (errmsg != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 {
Yegappan Lakshmanan78012f52023-02-02 16:34:11 +00002675 vim_strncpy(IObuff, (char_u *)_(errmsg), IOSIZE - 1);
2676 i = (int)STRLEN(IObuff) + 2;
2677 if (i + (arg - startarg) < IOSIZE)
2678 {
2679 // append the argument with the error
2680 STRCAT(IObuff, ": ");
2681 mch_memmove(IObuff + i, startarg, (arg - startarg));
2682 IObuff[i + (arg - startarg)] = NUL;
2683 }
2684 // make sure all characters are printable
2685 trans_characters(IObuff, IOSIZE);
2686
2687 ++no_wait_return; // wait_return() done later
2688 emsg((char *)IObuff); // show error highlighted
2689 --no_wait_return;
2690
2691 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 }
2694
2695 arg = skipwhite(arg);
2696 }
2697
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002698theend:
2699 if (silent_mode && did_show)
2700 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002701 // After displaying option values in silent mode.
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002702 silent_mode = FALSE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002703 info_message = TRUE; // use mch_msg(), not mch_errmsg()
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002704 msg_putchar('\n');
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002705 cursor_on(); // msg_start() switches it off
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002706 out_flush();
2707 silent_mode = TRUE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002708 info_message = FALSE; // use mch_msg(), not mch_errmsg()
Bram Moolenaar26a60b42005-02-22 08:49:11 +00002709 }
2710
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711 return OK;
2712}
2713
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002714/*
2715 * Call this when an option has been given a new value through a user command.
2716 * Sets the P_WAS_SET flag and takes care of the P_INSECURE flag.
2717 */
Bram Moolenaardac13472019-09-16 21:06:21 +02002718 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002719did_set_option(
2720 int opt_idx,
Bram Moolenaar916a8182018-11-25 02:18:29 +01002721 int opt_flags, // possibly with OPT_MODELINE
2722 int new_value, // value was replaced completely
2723 int value_checked) // value was checked to be safe, no need to set the
2724 // P_INSECURE flag.
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002725{
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002726 long_u *p;
2727
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002728 options[opt_idx].flags |= P_WAS_SET;
2729
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002730 // When an option is set in the sandbox, from a modeline or in secure mode
2731 // set the P_INSECURE flag. Otherwise, if a new value is stored reset the
2732 // flag.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002733 p = insecure_flag(opt_idx, opt_flags);
Bram Moolenaar916a8182018-11-25 02:18:29 +01002734 if (!value_checked && (secure
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002735#ifdef HAVE_SANDBOX
2736 || sandbox != 0
2737#endif
Bram Moolenaar916a8182018-11-25 02:18:29 +01002738 || (opt_flags & OPT_MODELINE)))
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002739 *p = *p | P_INSECURE;
2740 else if (new_value)
2741 *p = *p & ~P_INSECURE;
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002742}
2743
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744/*
2745 * Convert a key name or string into a key value.
2746 * Used for 'wildchar' and 'cedit' options.
Bram Moolenaardbe948d2017-07-23 22:50:51 +02002747 * When "multi_byte" is TRUE allow for multi-byte characters.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 */
Bram Moolenaardbe948d2017-07-23 22:50:51 +02002749 int
2750string_to_key(char_u *arg, int multi_byte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751{
2752 if (*arg == '<')
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02002753 return find_key_option(arg + 1, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754 if (*arg == '^')
2755 return Ctrl_chr(arg[1]);
Bram Moolenaardbe948d2017-07-23 22:50:51 +02002756 if (multi_byte)
2757 return PTR2CHAR(arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758 return *arg;
2759}
2760
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761/*
2762 * When changing 'title', 'titlestring', 'icon' or 'iconstring', call
2763 * maketitle() to create and display it.
2764 * When switching the title or icon off, call mch_restore_title() to get
2765 * the old value back.
2766 */
Bram Moolenaardac13472019-09-16 21:06:21 +02002767 void
Bram Moolenaar84a93082018-06-16 22:58:15 +02002768did_set_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769{
2770 if (starting != NO_SCREEN
2771#ifdef FEAT_GUI
2772 && !gui.starting
2773#endif
2774 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 maketitle();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777
2778/*
2779 * set_options_bin - called when 'bin' changes value.
2780 */
2781 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002782set_options_bin(
2783 int oldval,
2784 int newval,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002785 int opt_flags) // OPT_LOCAL and/or OPT_GLOBAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786{
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00002787 // The option values that are changed when 'bin' changes are
2788 // copied when 'bin is set and restored when 'bin' is reset.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789 if (newval)
2790 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002791 if (!oldval) // switched on
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 {
2793 if (!(opt_flags & OPT_GLOBAL))
2794 {
2795 curbuf->b_p_tw_nobin = curbuf->b_p_tw;
2796 curbuf->b_p_wm_nobin = curbuf->b_p_wm;
2797 curbuf->b_p_ml_nobin = curbuf->b_p_ml;
2798 curbuf->b_p_et_nobin = curbuf->b_p_et;
2799 }
2800 if (!(opt_flags & OPT_LOCAL))
2801 {
2802 p_tw_nobin = p_tw;
2803 p_wm_nobin = p_wm;
2804 p_ml_nobin = p_ml;
2805 p_et_nobin = p_et;
2806 }
2807 }
2808
2809 if (!(opt_flags & OPT_GLOBAL))
2810 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002811 curbuf->b_p_tw = 0; // no automatic line wrap
2812 curbuf->b_p_wm = 0; // no automatic line wrap
2813 curbuf->b_p_ml = 0; // no modelines
2814 curbuf->b_p_et = 0; // no expandtab
Bram Moolenaar071d4272004-06-13 20:20:40 +00002815 }
2816 if (!(opt_flags & OPT_LOCAL))
2817 {
2818 p_tw = 0;
2819 p_wm = 0;
2820 p_ml = FALSE;
2821 p_et = FALSE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002822 p_bin = TRUE; // needed when called for the "-b" argument
Bram Moolenaar071d4272004-06-13 20:20:40 +00002823 }
2824 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002825 else if (oldval) // switched off
Bram Moolenaar071d4272004-06-13 20:20:40 +00002826 {
2827 if (!(opt_flags & OPT_GLOBAL))
2828 {
2829 curbuf->b_p_tw = curbuf->b_p_tw_nobin;
2830 curbuf->b_p_wm = curbuf->b_p_wm_nobin;
2831 curbuf->b_p_ml = curbuf->b_p_ml_nobin;
2832 curbuf->b_p_et = curbuf->b_p_et_nobin;
2833 }
2834 if (!(opt_flags & OPT_LOCAL))
2835 {
2836 p_tw = p_tw_nobin;
2837 p_wm = p_wm_nobin;
2838 p_ml = p_ml_nobin;
2839 p_et = p_et_nobin;
2840 }
2841 }
Christian Brabandt757593c2023-08-22 21:44:10 +02002842#if defined(FEAT_EVAL) || defined(PROTO)
2843 // Remember where the dependent option were reset
2844 didset_options_sctx(opt_flags, p_bin_dep_opts);
2845#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002846}
2847
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848/*
2849 * Expand environment variables for some string options.
2850 * These string options cannot be indirect!
2851 * If "val" is NULL expand the current value of the option.
2852 * Return pointer to NameBuff, or NULL when not expanded.
2853 */
2854 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01002855option_expand(int opt_idx, char_u *val)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002857 // if option doesn't need expansion nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL)
2859 return NULL;
2860
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002861 // If val is longer than MAXPATHL no meaningful expansion can be done,
2862 // expand_env() would truncate the string.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 if (val != NULL && STRLEN(val) > MAXPATHL)
2864 return NULL;
2865
2866 if (val == NULL)
2867 val = *(char_u **)options[opt_idx].var;
2868
2869 /*
2870 * Expanding this with NameBuff, expand_env() must not be passed IObuff.
2871 * Escape spaces when expanding 'tags', they are used to separate file
2872 * names.
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00002873 * For 'spellsuggest' expand after "file:".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874 */
2875 expand_env_esc(val, NameBuff, MAXPATHL,
Bram Moolenaar9f0545d2007-09-26 20:36:32 +00002876 (char_u **)options[opt_idx].var == &p_tags, FALSE,
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002877#ifdef FEAT_SPELL
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00002878 (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" :
2879#endif
2880 NULL);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002881 if (STRCMP(NameBuff, val) == 0) // they are the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 return NULL;
2883
2884 return NameBuff;
2885}
2886
2887/*
2888 * After setting various option values: recompute variables that depend on
2889 * option values.
2890 */
2891 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002892didset_options(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002894 // initialize the table for 'iskeyword' et.al.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 (void)init_chartab();
2896
Bram Moolenaardac13472019-09-16 21:06:21 +02002897 didset_string_options();
2898
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00002899#ifdef FEAT_SPELL
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00002900 (void)spell_check_msm();
Bram Moolenaar24bbcfe2005-06-28 23:32:02 +00002901 (void)spell_check_sps();
Bram Moolenaar860cae12010-06-05 23:22:07 +02002902 (void)compile_cap_prog(curwin->w_s);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002903 (void)did_set_spell_option(TRUE);
Bram Moolenaard857f0e2005-06-21 22:37:39 +00002904#endif
Bram Moolenaar010ee962019-09-25 20:37:36 +02002905 // set cedit_key
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002906 (void)did_set_cedit(NULL);
Bram Moolenaar597a4222014-06-25 14:39:50 +02002907#ifdef FEAT_LINEBREAK
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002908 // initialize the table for 'breakat'.
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002909 did_set_breakat(NULL);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002910#endif
Bram Moolenaar010ee962019-09-25 20:37:36 +02002911 after_copy_winopt(curwin);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002912}
2913
2914/*
2915 * More side effects of setting options.
2916 */
2917 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002918didset_options2(void)
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002919{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002920 // Initialize the highlight_attr[] table.
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002921 (void)highlight_changed();
2922
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002923 // Parse default for 'wildmode'
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002924 check_opt_wim();
2925
Bram Moolenaareed9d462021-02-15 20:38:25 +01002926 // Parse default for 'listchars'.
zeertzjq6a8d2e12024-01-17 20:54:49 +01002927 (void)set_listchars_option(curwin, curwin->w_p_lcs, TRUE, NULL, 0);
Bram Moolenaareed9d462021-02-15 20:38:25 +01002928
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002929 // Parse default for 'fillchars'.
zeertzjq6a8d2e12024-01-17 20:54:49 +01002930 (void)set_fillchars_option(curwin, curwin->w_p_fcs, TRUE, NULL, 0);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002931
2932#ifdef FEAT_CLIPBOARD
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01002933 // Parse default for 'clipboard'
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00002934 (void)did_set_clipboard(NULL);
Bram Moolenaare68c25c2015-08-25 15:39:55 +02002935#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02002936#ifdef FEAT_VARTABS
Bram Moolenaar55c77cf2019-02-16 19:05:11 +01002937 vim_free(curbuf->b_p_vsts_array);
Bram Moolenaarb7081e12021-09-04 18:47:28 +02002938 (void)tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array);
Bram Moolenaar55c77cf2019-02-16 19:05:11 +01002939 vim_free(curbuf->b_p_vts_array);
Bram Moolenaarb7081e12021-09-04 18:47:28 +02002940 (void)tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02002941#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942}
2943
2944/*
2945 * Check for string options that are NULL (normally only termcap options).
2946 */
2947 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01002948check_options(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002949{
2950 int opt_idx;
2951
2952 for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++)
2953 if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL)
2954 check_string_option((char_u **)get_varp(&(options[opt_idx])));
2955}
2956
2957/*
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02002958 * Return the option index found by a pointer into term_strings[].
2959 * Return -1 if not found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 */
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02002961 int
2962get_term_opt_idx(char_u **p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963{
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02002964 int opt_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002965
2966 for (opt_idx = 1; options[opt_idx].fullname != NULL; opt_idx++)
2967 if (options[opt_idx].var == (char_u *)p)
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02002968 return opt_idx;
2969 return -1; // cannot happen: didn't find it!
2970}
2971
2972/*
2973 * Mark a terminal option as allocated, found by a pointer into term_strings[].
2974 * Return the option index or -1 if not found.
2975 */
2976 int
2977set_term_option_alloced(char_u **p)
2978{
2979 int opt_idx = get_term_opt_idx(p);
2980
2981 if (opt_idx >= 0)
2982 options[opt_idx].flags |= P_ALLOCED;
2983 return opt_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002984}
2985
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002986#if defined(FEAT_EVAL) || defined(PROTO)
2987/*
2988 * Return TRUE when option "opt" was set from a modeline or in secure mode.
2989 * Return FALSE when it wasn't.
2990 * Return -1 for an unknown option.
2991 */
2992 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01002993was_set_insecurely(char_u *opt, int opt_flags)
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002994{
2995 int idx = findoption(opt);
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002996 long_u *flagp;
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00002997
2998 if (idx >= 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00002999 {
3000 flagp = insecure_flag(idx, opt_flags);
3001 return (*flagp & P_INSECURE) != 0;
3002 }
Bram Moolenaar95f09602016-11-10 20:01:45 +01003003 internal_error("was_set_insecurely()");
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00003004 return -1;
3005}
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003006
3007/*
3008 * Get a pointer to the flags used for the P_INSECURE flag of option
3009 * "opt_idx". For some local options a local flags field is used.
Bram Moolenaard5e8c922021-02-02 21:10:01 +01003010 * NOTE: Caller must make sure that "curwin" is set to the window from which
3011 * the option is used.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003012 */
3013 static long_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01003014insecure_flag(int opt_idx, int opt_flags)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003015{
3016 if (opt_flags & OPT_LOCAL)
3017 switch ((int)options[opt_idx].indir)
3018 {
3019#ifdef FEAT_STL_OPT
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003020 case PV_STL: return &curwin->w_p_stl_flags;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003021#endif
3022#ifdef FEAT_EVAL
Bram Moolenaar2e978902006-05-13 12:37:50 +00003023# ifdef FEAT_FOLDING
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003024 case PV_FDE: return &curwin->w_p_fde_flags;
3025 case PV_FDT: return &curwin->w_p_fdt_flags;
Bram Moolenaar2e978902006-05-13 12:37:50 +00003026# endif
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003027# ifdef FEAT_BEVAL
3028 case PV_BEXPR: return &curbuf->b_p_bexpr_flags;
3029# endif
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003030 case PV_INDE: return &curbuf->b_p_inde_flags;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003031 case PV_FEX: return &curbuf->b_p_fex_flags;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003032# ifdef FEAT_FIND_ID
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003033 case PV_INEX: return &curbuf->b_p_inex_flags;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003034# endif
3035#endif
3036 }
3037
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01003038 // Nothing special, return global flags field.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003039 return &options[opt_idx].flags;
3040}
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00003041#endif
3042
Bram Moolenaar1f26d2f2009-02-11 10:35:36 +00003043/*
3044 * Redraw the window title and/or tab page text later.
3045 */
Yegappan Lakshmananeb91e242023-08-31 18:10:46 +02003046 void
3047redraw_titles(void)
Bram Moolenaar1f26d2f2009-02-11 10:35:36 +00003048{
3049 need_maketitle = TRUE;
Bram Moolenaar1f26d2f2009-02-11 10:35:36 +00003050 redraw_tabline = TRUE;
Bram Moolenaar1f26d2f2009-02-11 10:35:36 +00003051}
Bram Moolenaar1f26d2f2009-02-11 10:35:36 +00003052
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053/*
Bram Moolenaar8f130ed2019-04-10 22:15:19 +02003054 * Return TRUE if "val" is a valid name: only consists of alphanumeric ASCII
3055 * characters or characters in "allowed".
3056 */
Bram Moolenaare677df82019-09-02 22:31:11 +02003057 int
Bram Moolenaar8f130ed2019-04-10 22:15:19 +02003058valid_name(char_u *val, char *allowed)
3059{
3060 char_u *s;
3061
3062 for (s = val; *s != NUL; ++s)
3063 if (!ASCII_ISALNUM(*s) && vim_strchr((char_u *)allowed, *s) == NULL)
3064 return FALSE;
3065 return TRUE;
3066}
3067
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003068#if defined(FEAT_EVAL) || defined(PROTO)
3069/*
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003070 * Set the script_ctx for an option, taking care of setting the buffer- or
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003071 * window-local value.
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003072 */
Bram Moolenaardac13472019-09-16 21:06:21 +02003073 void
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003074set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003075{
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003076 int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
3077 int indir = (int)options[opt_idx].indir;
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003078 sctx_T new_script_ctx = script_ctx;
3079
Bram Moolenaar51258742020-05-03 17:19:33 +02003080 // Modeline already has the line number set.
3081 if (!(opt_flags & OPT_MODELINE))
3082 new_script_ctx.sc_lnum += SOURCING_LNUM;
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003083
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01003084 // Remember where the option was set. For local options need to do that
3085 // in the buffer or window structure.
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003086 if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0)
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003087 options[opt_idx].script_ctx = new_script_ctx;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003088 if (both || (opt_flags & OPT_LOCAL))
3089 {
3090 if (indir & PV_BUF)
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003091 curbuf->b_p_script_ctx[indir & PV_MASK] = new_script_ctx;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003092 else if (indir & PV_WIN)
Bram Moolenaare70dd112022-01-21 16:31:11 +00003093 {
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003094 curwin->w_p_script_ctx[indir & PV_MASK] = new_script_ctx;
Bram Moolenaare70dd112022-01-21 16:31:11 +00003095 if (both)
3096 // also setting the "all buffers" value
3097 curwin->w_allbuf_opt.wo_script_ctx[indir & PV_MASK] =
3098 new_script_ctx;
3099 }
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00003100 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003101}
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02003102
3103/*
Bram Moolenaar5600a702022-01-22 15:09:36 +00003104 * Get the script context of global option "name".
3105 *
3106 */
3107 sctx_T *
3108get_option_sctx(char *name)
3109{
3110 int idx = findoption((char_u *)name);
3111
3112 if (idx >= 0)
3113 return &options[idx].script_ctx;
3114 siemsg("no such option: %s", name);
3115 return NULL;
3116}
3117
3118/*
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02003119 * Set the script_ctx for a termcap option.
3120 * "name" must be the two character code, e.g. "RV".
3121 * When "name" is NULL use "opt_idx".
3122 */
3123 void
3124set_term_option_sctx_idx(char *name, int opt_idx)
3125{
3126 char_u buf[5];
3127 int idx;
3128
3129 if (name == NULL)
3130 idx = opt_idx;
3131 else
3132 {
3133 buf[0] = 't';
3134 buf[1] = '_';
3135 buf[2] = name[0];
3136 buf[3] = name[1];
3137 buf[4] = 0;
3138 idx = findoption(buf);
3139 }
3140 if (idx >= 0)
3141 set_option_sctx_idx(idx, OPT_GLOBAL, current_sctx);
3142}
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003143#endif
3144
Bram Moolenaarf4140482020-02-15 23:06:45 +01003145#if defined(FEAT_EVAL)
3146/*
3147 * Apply the OptionSet autocommand.
3148 */
3149 static void
3150apply_optionset_autocmd(
3151 int opt_idx,
3152 long opt_flags,
3153 long oldval,
3154 long oldval_g,
3155 long newval,
3156 char *errmsg)
3157{
3158 char_u buf_old[12], buf_old_global[12], buf_new[12], buf_type[12];
3159
3160 // Don't do this while starting up, failure or recursively.
3161 if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL)
3162 return;
3163
3164 vim_snprintf((char *)buf_old, sizeof(buf_old), "%ld", oldval);
3165 vim_snprintf((char *)buf_old_global, sizeof(buf_old_global), "%ld",
3166 oldval_g);
3167 vim_snprintf((char *)buf_new, sizeof(buf_new), "%ld", newval);
3168 vim_snprintf((char *)buf_type, sizeof(buf_type), "%s",
3169 (opt_flags & OPT_LOCAL) ? "local" : "global");
3170 set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
3171 set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
3172 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
3173 if (opt_flags & OPT_LOCAL)
3174 {
3175 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1);
3176 set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
3177 }
3178 if (opt_flags & OPT_GLOBAL)
3179 {
3180 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1);
3181 set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1);
3182 }
3183 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
3184 {
3185 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1);
3186 set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
3187 set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1);
3188 }
3189 if (opt_flags & OPT_MODELINE)
3190 {
3191 set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1);
3192 set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
3193 }
3194 apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname,
3195 NULL, FALSE, NULL);
3196 reset_v_option_vars();
3197}
3198#endif
3199
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003200#if defined(FEAT_ARABIC) || defined(PROTO)
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003201/*
3202 * Process the updated 'arabic' option value.
3203 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003204 char *
3205did_set_arabic(optset_T *args UNUSED)
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003206{
3207 char *errmsg = NULL;
3208
3209 if (curwin->w_p_arab)
3210 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00003211 // 'arabic' is set, handle various sub-settings.
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003212 if (!p_tbidi)
3213 {
3214 // set rightleft mode
3215 if (!curwin->w_p_rl)
3216 {
3217 curwin->w_p_rl = TRUE;
3218 changed_window_setting();
3219 }
3220
3221 // Enable Arabic shaping (major part of what Arabic requires)
3222 if (!p_arshape)
3223 {
3224 p_arshape = TRUE;
3225 redraw_later_clear();
3226 }
3227 }
3228
3229 // Arabic requires a utf-8 encoding, inform the user if it's not
3230 // set.
3231 if (STRCMP(p_enc, "utf-8") != 0)
3232 {
3233 static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
3234
3235 msg_source(HL_ATTR(HLF_W));
3236 msg_attr(_(w_arabic), HL_ATTR(HLF_W));
3237#ifdef FEAT_EVAL
3238 set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_arabic), -1);
3239#endif
3240 }
3241
3242 // set 'delcombine'
3243 p_deco = TRUE;
3244
3245# ifdef FEAT_KEYMAP
3246 // Force-set the necessary keymap for arabic
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003247 errmsg = set_option_value((char_u *)"keymap", 0L, (char_u *)"arabic",
3248 OPT_LOCAL);
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003249# endif
3250 }
3251 else
3252 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00003253 // 'arabic' is reset, handle various sub-settings.
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003254 if (!p_tbidi)
3255 {
3256 // reset rightleft mode
3257 if (curwin->w_p_rl)
3258 {
3259 curwin->w_p_rl = FALSE;
3260 changed_window_setting();
3261 }
3262
3263 // 'arabicshape' isn't reset, it is a global option and
3264 // another window may still need it "on".
3265 }
3266
3267 // 'delcombine' isn't reset, it is a global option and another
3268 // window may still want it "on".
3269
3270# ifdef FEAT_KEYMAP
3271 // Revert to the default keymap
3272 curbuf->b_p_iminsert = B_IMODE_NONE;
3273 curbuf->b_p_imsearch = B_IMODE_USE_INSERT;
3274# endif
3275 }
3276
3277 return errmsg;
3278}
3279#endif
3280
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003281#if defined(FEAT_AUTOCHDIR) || defined(PROTO)
3282/*
3283 * Process the updated 'autochdir' option value.
3284 */
3285 char *
3286did_set_autochdir(optset_T *args UNUSED)
3287{
3288 // Change directories when the 'acd' option is set now.
3289 DO_AUTOCHDIR;
3290 return NULL;
3291}
3292#endif
3293
3294#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
3295/*
3296 * Process the updated 'ballooneval' option value.
3297 */
3298 char *
3299did_set_ballooneval(optset_T *args)
3300{
3301 if (balloonEvalForTerm)
3302 return NULL;
3303
3304 if (p_beval && !args->os_oldval.boolean)
3305 gui_mch_enable_beval_area(balloonEval);
3306 else if (!p_beval && args->os_oldval.boolean)
3307 gui_mch_disable_beval_area(balloonEval);
3308
3309 return NULL;
3310}
3311#endif
3312
3313#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
3314/*
3315 * Process the updated 'balloonevalterm' option value.
3316 */
3317 char *
3318did_set_balloonevalterm(optset_T *args UNUSED)
3319{
3320 mch_bevalterm_changed();
3321 return NULL;
3322}
3323#endif
3324
3325/*
3326 * Process the updated 'binary' option value.
3327 */
3328 char *
3329did_set_binary(optset_T *args)
3330{
3331 // when 'bin' is set also set some other options
3332 set_options_bin(args->os_oldval.boolean, curbuf->b_p_bin, args->os_flags);
3333 redraw_titles();
3334
3335 return NULL;
3336}
3337
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003338/*
3339 * Process the updated 'buflisted' option value.
3340 */
3341 char *
3342did_set_buflisted(optset_T *args)
3343{
3344 // when 'buflisted' changes, trigger autocommands
3345 if (args->os_oldval.boolean != curbuf->b_p_bl)
3346 apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
3347 NULL, NULL, TRUE, curbuf);
3348 return NULL;
3349}
3350
3351/*
3352 * Process the new 'cmdheight' option value.
3353 */
3354 char *
3355did_set_cmdheight(optset_T *args)
3356{
3357 long old_value = args->os_oldval.number;
3358 char *errmsg = NULL;
3359
3360 // if p_ch changed value, change the command line height
3361 if (p_ch < 1)
3362 {
3363 errmsg = e_argument_must_be_positive;
3364 p_ch = 1;
3365 }
3366 if (p_ch > Rows - min_rows() + 1)
3367 p_ch = Rows - min_rows() + 1;
3368
3369 // Only compute the new window layout when startup has been
3370 // completed. Otherwise the frame sizes may be wrong.
3371 if ((p_ch != old_value
3372 || tabline_height() + topframe->fr_height != Rows - p_ch)
3373 && full_screen
3374#ifdef FEAT_GUI
3375 && !gui.starting
3376#endif
3377 )
3378 command_height();
3379
3380 return errmsg;
3381}
3382
3383/*
3384 * Process the updated 'compatible' option value.
3385 */
3386 char *
3387did_set_compatible(optset_T *args UNUSED)
3388{
3389 compatible_set();
3390 return NULL;
3391}
3392
3393#if defined(FEAT_CONCEAL) || defined(PROTO)
3394/*
3395 * Process the new 'conceallevel' option value.
3396 */
3397 char *
3398did_set_conceallevel(optset_T *args UNUSED)
3399{
3400 char *errmsg = NULL;
3401
3402 if (curwin->w_p_cole < 0)
3403 {
3404 errmsg = e_argument_must_be_positive;
3405 curwin->w_p_cole = 0;
3406 }
3407 else if (curwin->w_p_cole > 3)
3408 {
3409 errmsg = e_invalid_argument;
3410 curwin->w_p_cole = 3;
3411 }
3412
3413 return errmsg;
3414}
3415#endif
3416
3417#if defined(FEAT_DIFF) || defined(PROTO)
3418/*
3419 * Process the updated 'diff' option value.
3420 */
3421 char *
3422did_set_diff(optset_T *args UNUSED)
3423{
3424 // May add or remove the buffer from the list of diff buffers.
3425 diff_buf_adjust(curwin);
3426# ifdef FEAT_FOLDING
3427 if (foldmethodIsDiff(curwin))
3428 foldUpdateAll(curwin);
3429# endif
3430 return NULL;
3431}
3432#endif
3433
3434/*
3435 * Process the updated 'endoffile' or 'endofline' or 'fixendofline' or 'bomb'
3436 * option value.
3437 */
3438 char *
3439did_set_eof_eol_fixeol_bomb(optset_T *args UNUSED)
3440{
3441 // redraw the window title and tab page text
3442 redraw_titles();
3443 return NULL;
3444}
3445
3446/*
3447 * Process the updated 'equalalways' option value.
3448 */
3449 char *
3450did_set_equalalways(optset_T *args)
3451{
3452 if (p_ea && !args->os_oldval.boolean)
3453 win_equal(curwin, FALSE, 0);
3454
3455 return NULL;
3456}
3457
3458#if defined(FEAT_FOLDING) || defined(PROTO)
3459/*
3460 * Process the new 'foldcolumn' option value.
3461 */
3462 char *
3463did_set_foldcolumn(optset_T *args UNUSED)
3464{
3465 char *errmsg = NULL;
3466
3467 if (curwin->w_p_fdc < 0)
3468 {
3469 errmsg = e_argument_must_be_positive;
3470 curwin->w_p_fdc = 0;
3471 }
3472 else if (curwin->w_p_fdc > 12)
3473 {
3474 errmsg = e_invalid_argument;
3475 curwin->w_p_fdc = 12;
3476 }
3477
3478 return errmsg;
3479}
3480
3481/*
3482 * Process the new 'foldlevel' option value.
3483 */
3484 char *
3485did_set_foldlevel(optset_T *args UNUSED)
3486{
3487 if (curwin->w_p_fdl < 0)
3488 curwin->w_p_fdl = 0;
3489 newFoldLevel();
3490 return NULL;
3491}
3492
3493/*
3494 * Process the new 'foldminlines' option value.
3495 */
3496 char *
3497did_set_foldminlines(optset_T *args UNUSED)
3498{
3499 foldUpdateAll(curwin);
3500 return NULL;
3501}
3502
3503/*
3504 * Process the new 'foldnestmax' option value.
3505 */
3506 char *
3507did_set_foldnestmax(optset_T *args UNUSED)
3508{
3509 if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
3510 foldUpdateAll(curwin);
3511 return NULL;
3512}
3513#endif
3514
3515#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
3516/*
3517 * Process the updated 'hlsearch' option value.
3518 */
3519 char *
3520did_set_hlsearch(optset_T *args UNUSED)
3521{
3522 // when 'hlsearch' is set or reset: reset no_hlsearch
3523 set_no_hlsearch(FALSE);
3524 return NULL;
3525}
3526#endif
3527
3528/*
3529 * Process the updated 'ignorecase' option value.
3530 */
3531 char *
3532did_set_ignorecase(optset_T *args UNUSED)
3533{
3534 // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
3535 if (p_hls)
3536 redraw_all_later(UPD_SOME_VALID);
3537 return NULL;
3538}
3539
3540#if defined(HAVE_INPUT_METHOD) || defined(PROTO)
3541/*
3542 * Process the updated 'imdisable' option value.
3543 */
3544 char *
3545did_set_imdisable(optset_T *args UNUSED)
3546{
3547 // Only de-activate it here, it will be enabled when changing mode.
3548 if (p_imdisable)
3549 im_set_active(FALSE);
3550 else if (State & MODE_INSERT)
3551 // When the option is set from an autocommand, it may need to take
3552 // effect right away.
3553 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
3554 return NULL;
3555}
3556#endif
3557
3558/*
3559 * Process the new 'iminsert' option value.
3560 */
3561 char *
3562did_set_iminsert(optset_T *args UNUSED)
3563{
3564 char *errmsg = NULL;
3565
3566 if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST)
3567 {
3568 errmsg = e_invalid_argument;
3569 curbuf->b_p_iminsert = B_IMODE_NONE;
3570 }
3571 p_iminsert = curbuf->b_p_iminsert;
3572 if (termcap_active) // don't do this in the alternate screen
3573 showmode();
3574#if defined(FEAT_KEYMAP)
3575 // Show/unshow value of 'keymap' in status lines.
3576 status_redraw_curbuf();
3577#endif
3578
3579 return errmsg;
3580}
3581
3582/*
3583 * Process the new 'imsearch' option value.
3584 */
3585 char *
3586did_set_imsearch(optset_T *args UNUSED)
3587{
3588 char *errmsg = NULL;
3589
3590 if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST)
3591 {
3592 errmsg = e_invalid_argument;
3593 curbuf->b_p_imsearch = B_IMODE_NONE;
3594 }
3595 p_imsearch = curbuf->b_p_imsearch;
3596
3597 return errmsg;
3598}
3599
3600#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
3601/*
3602 * Process the new 'imstyle' option value.
3603 */
3604 char *
3605did_set_imstyle(optset_T *args UNUSED)
3606{
3607 char *errmsg = NULL;
3608
3609 if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
3610 errmsg = e_invalid_argument;
3611
3612 return errmsg;
3613}
3614#endif
3615
3616/*
3617 * Process the updated 'insertmode' option value.
3618 */
3619 char *
3620did_set_insertmode(optset_T *args)
3621{
3622 // when 'insertmode' is set from an autocommand need to do work here
3623 if (p_im)
3624 {
3625 if ((State & MODE_INSERT) == 0)
3626 need_start_insertmode = TRUE;
3627 stop_insert_mode = FALSE;
3628 }
3629 // only reset if it was set previously
3630 else if (args->os_oldval.boolean)
3631 {
3632 need_start_insertmode = FALSE;
3633 stop_insert_mode = TRUE;
3634 if (restart_edit != 0 && mode_displayed)
3635 clear_cmdline = TRUE; // remove "(insert)"
3636 restart_edit = 0;
3637 }
3638
3639 return NULL;
3640}
3641
3642#if defined(FEAT_LANGMAP) || defined(PROTO)
3643/*
3644 * Process the updated 'langnoremap' option value.
3645 */
3646 char *
3647did_set_langnoremap(optset_T *args UNUSED)
3648{
3649 // 'langnoremap' -> !'langremap'
3650 p_lrm = !p_lnr;
3651 return NULL;
3652}
3653
3654/*
3655 * Process the updated 'langremap' option value.
3656 */
3657 char *
3658did_set_langremap(optset_T *args UNUSED)
3659{
3660 // 'langremap' -> !'langnoremap'
3661 p_lnr = !p_lrm;
3662 return NULL;
3663}
3664#endif
3665
3666/*
3667 * Process the new 'laststatus' option value.
3668 */
3669 char *
3670did_set_laststatus(optset_T *args UNUSED)
3671{
3672 last_status(FALSE); // (re)set last window status line
3673 return NULL;
3674}
3675
3676#if defined(FEAT_GUI) || defined(PROTO)
3677/*
3678 * Process the new 'linespace' option value.
3679 */
3680 char *
3681did_set_linespace(optset_T *args UNUSED)
3682{
3683 // Recompute gui.char_height and resize the Vim window to keep the
3684 // same number of lines.
3685 if (gui.in_use && gui_mch_adjust_charheight() == OK)
3686 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
3687 return NULL;
3688}
3689#endif
3690
3691/*
3692 * Process the updated 'lisp' option value.
3693 */
3694 char *
3695did_set_lisp(optset_T *args UNUSED)
3696{
3697 // When 'lisp' option changes include/exclude '-' in keyword characters.
3698 (void)buf_init_chartab(curbuf, FALSE); // ignore errors
3699 return NULL;
3700}
3701
3702/*
3703 * Process the new 'maxcombine' option value.
3704 */
3705 char *
3706did_set_maxcombine(optset_T *args UNUSED)
3707{
3708 if (p_mco > MAX_MCO)
3709 p_mco = MAX_MCO;
3710 else if (p_mco < 0)
3711 p_mco = 0;
3712 screenclear(); // will re-allocate the screen
3713 return NULL;
3714}
3715
3716/*
3717 * Process the updated 'modifiable' option value.
3718 */
3719 char *
3720did_set_modifiable(optset_T *args UNUSED)
3721{
3722 // when 'modifiable' is changed, redraw the window title
3723
3724# ifdef FEAT_TERMINAL
3725 // Cannot set 'modifiable' when in Terminal mode.
3726 if (curbuf->b_p_ma && (term_in_normal_mode() || (bt_terminal(curbuf)
3727 && curbuf->b_term != NULL && !term_is_finished(curbuf))))
3728 {
3729 curbuf->b_p_ma = FALSE;
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003730 return e_cannot_make_terminal_with_running_job_modifiable;
3731 }
3732# endif
3733 redraw_titles();
3734
3735 return NULL;
3736}
3737
3738/*
3739 * Process the updated 'modified' option value.
3740 */
3741 char *
3742did_set_modified(optset_T *args)
3743{
3744 if (!args->os_newval.boolean)
3745 save_file_ff(curbuf); // Buffer is unchanged
3746 redraw_titles();
zeertzjq5bf6c212024-03-31 18:41:27 +02003747 curbuf->b_modified_was_set = args->os_newval.boolean;
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003748 return NULL;
3749}
3750
3751#if defined(FEAT_GUI) || defined(PROTO)
3752/*
3753 * Process the updated 'mousehide' option value.
3754 */
3755 char *
3756did_set_mousehide(optset_T *args UNUSED)
3757{
3758 if (!p_mh)
3759 gui_mch_mousehide(FALSE);
3760 return NULL;
3761}
3762#endif
3763
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003764/*
3765 * Process the updated 'number' or 'relativenumber' option value.
3766 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003767 char *
3768did_set_number_relativenumber(optset_T *args UNUSED)
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003769{
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003770#if (defined(FEAT_SIGNS) && defined(FEAT_GUI)) || defined(PROTO)
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003771 if (gui.in_use
3772 && (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u')
3773 && curbuf->b_signlist != NULL)
3774 {
3775 // If the 'number' or 'relativenumber' options are modified and
3776 // 'signcolumn' is set to 'number', then clear the screen for a full
3777 // refresh. Otherwise the sign icons are not displayed properly in the
3778 // number column. If the 'number' option is set and only the
3779 // 'relativenumber' option is toggled, then don't refresh the screen
3780 // (optimization).
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003781 if (!(curwin->w_p_nu && ((int *)args->os_varp == &curwin->w_p_rnu)))
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003782 redraw_all_later(UPD_CLEAR);
3783 }
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003784#endif
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00003785 return NULL;
3786}
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00003787
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003788#if defined(FEAT_LINEBREAK) || defined(PROTO)
3789/*
3790 * Process the new 'numberwidth' option value.
3791 */
3792 char *
3793did_set_numberwidth(optset_T *args UNUSED)
3794{
3795 char *errmsg = NULL;
3796
3797 // 'numberwidth' must be positive
3798 if (curwin->w_p_nuw < 1)
3799 {
3800 errmsg = e_argument_must_be_positive;
3801 curwin->w_p_nuw = 1;
3802 }
3803 if (curwin->w_p_nuw > 20)
3804 {
3805 errmsg = e_invalid_argument;
3806 curwin->w_p_nuw = 20;
3807 }
3808 curwin->w_nrwidth_line_count = 0; // trigger a redraw
3809
3810 return errmsg;
3811}
3812#endif
3813
3814/*
3815 * Process the updated 'paste' option value. Called after p_paste was set or
3816 * reset. When 'paste' is set or reset also change other options.
3817 */
3818 char *
3819did_set_paste(optset_T *args UNUSED)
3820{
3821 static int old_p_paste = FALSE;
3822 static int save_sm = 0;
3823 static int save_sta = 0;
3824 static int save_ru = 0;
3825#ifdef FEAT_RIGHTLEFT
3826 static int save_ri = 0;
3827 static int save_hkmap = 0;
3828#endif
3829 buf_T *buf;
3830
3831 if (p_paste)
3832 {
3833 // Paste switched from off to on.
3834 // Save the current values, so they can be restored later.
3835 if (!old_p_paste)
3836 {
3837 // save options for each buffer
3838 FOR_ALL_BUFFERS(buf)
3839 {
3840 buf->b_p_tw_nopaste = buf->b_p_tw;
3841 buf->b_p_wm_nopaste = buf->b_p_wm;
3842 buf->b_p_sts_nopaste = buf->b_p_sts;
3843 buf->b_p_ai_nopaste = buf->b_p_ai;
3844 buf->b_p_et_nopaste = buf->b_p_et;
3845#ifdef FEAT_VARTABS
3846 if (buf->b_p_vsts_nopaste)
3847 vim_free(buf->b_p_vsts_nopaste);
3848 buf->b_p_vsts_nopaste =
3849 buf->b_p_vsts && buf->b_p_vsts != empty_option
3850 ? vim_strsave(buf->b_p_vsts) : NULL;
3851#endif
3852 }
3853
3854 // save global options
3855 save_sm = p_sm;
3856 save_sta = p_sta;
3857 save_ru = p_ru;
3858#ifdef FEAT_RIGHTLEFT
3859 save_ri = p_ri;
3860 save_hkmap = p_hkmap;
3861#endif
3862 // save global values for local buffer options
3863 p_ai_nopaste = p_ai;
3864 p_et_nopaste = p_et;
3865 p_sts_nopaste = p_sts;
3866 p_tw_nopaste = p_tw;
3867 p_wm_nopaste = p_wm;
3868#ifdef FEAT_VARTABS
3869 if (p_vsts_nopaste)
3870 vim_free(p_vsts_nopaste);
3871 p_vsts_nopaste = p_vsts && p_vsts != empty_option
3872 ? vim_strsave(p_vsts) : NULL;
3873#endif
3874 }
3875
3876 // Always set the option values, also when 'paste' is set when it is
3877 // already on. Set options for each buffer.
3878 FOR_ALL_BUFFERS(buf)
3879 {
3880 buf->b_p_tw = 0; // textwidth is 0
3881 buf->b_p_wm = 0; // wrapmargin is 0
3882 buf->b_p_sts = 0; // softtabstop is 0
3883 buf->b_p_ai = 0; // no auto-indent
3884 buf->b_p_et = 0; // no expandtab
3885#ifdef FEAT_VARTABS
3886 if (buf->b_p_vsts)
3887 free_string_option(buf->b_p_vsts);
3888 buf->b_p_vsts = empty_option;
3889 VIM_CLEAR(buf->b_p_vsts_array);
3890#endif
3891 }
3892
3893 // set global options
3894 p_sm = 0; // no showmatch
3895 p_sta = 0; // no smarttab
3896 if (p_ru)
3897 status_redraw_all(); // redraw to remove the ruler
3898 p_ru = 0; // no ruler
3899#ifdef FEAT_RIGHTLEFT
3900 p_ri = 0; // no reverse insert
3901 p_hkmap = 0; // no Hebrew keyboard
3902#endif
3903 // set global values for local buffer options
3904 p_tw = 0;
3905 p_wm = 0;
3906 p_sts = 0;
3907 p_ai = 0;
Christian Brabandt757593c2023-08-22 21:44:10 +02003908 p_et = 0;
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003909#ifdef FEAT_VARTABS
3910 if (p_vsts)
3911 free_string_option(p_vsts);
3912 p_vsts = empty_option;
3913#endif
3914 }
3915
3916 // Paste switched from on to off: Restore saved values.
3917 else if (old_p_paste)
3918 {
3919 // restore options for each buffer
3920 FOR_ALL_BUFFERS(buf)
3921 {
3922 buf->b_p_tw = buf->b_p_tw_nopaste;
3923 buf->b_p_wm = buf->b_p_wm_nopaste;
3924 buf->b_p_sts = buf->b_p_sts_nopaste;
3925 buf->b_p_ai = buf->b_p_ai_nopaste;
3926 buf->b_p_et = buf->b_p_et_nopaste;
3927#ifdef FEAT_VARTABS
3928 if (buf->b_p_vsts)
3929 free_string_option(buf->b_p_vsts);
3930 buf->b_p_vsts = buf->b_p_vsts_nopaste
3931 ? vim_strsave(buf->b_p_vsts_nopaste) : empty_option;
3932 vim_free(buf->b_p_vsts_array);
3933 if (buf->b_p_vsts && buf->b_p_vsts != empty_option)
3934 (void)tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array);
3935 else
3936 buf->b_p_vsts_array = NULL;
3937#endif
3938 }
3939
3940 // restore global options
3941 p_sm = save_sm;
3942 p_sta = save_sta;
3943 if (p_ru != save_ru)
3944 status_redraw_all(); // redraw to draw the ruler
3945 p_ru = save_ru;
3946#ifdef FEAT_RIGHTLEFT
3947 p_ri = save_ri;
3948 p_hkmap = save_hkmap;
3949#endif
3950 // set global values for local buffer options
3951 p_ai = p_ai_nopaste;
3952 p_et = p_et_nopaste;
3953 p_sts = p_sts_nopaste;
3954 p_tw = p_tw_nopaste;
3955 p_wm = p_wm_nopaste;
3956#ifdef FEAT_VARTABS
3957 if (p_vsts)
3958 free_string_option(p_vsts);
3959 p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option;
3960#endif
3961 }
3962
3963 old_p_paste = p_paste;
3964
Christian Brabandt757593c2023-08-22 21:44:10 +02003965#if defined(FEAT_EVAL) || defined(PROTO)
3966 // Remember where the dependent options were reset
3967 didset_options_sctx((OPT_LOCAL | OPT_GLOBAL), p_paste_dep_opts);
3968#endif
3969
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003970 return NULL;
3971}
3972
3973
3974#ifdef FEAT_QUICKFIX
3975/*
3976 * Process the updated 'previewwindow' option value.
3977 */
3978 char *
Yegappan Lakshmanan3ee25962023-12-04 20:31:14 +01003979did_set_previewwindow(optset_T *args UNUSED)
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003980{
3981 if (!curwin->w_p_pvw)
3982 return NULL;
3983
3984 // There can be only one window with 'previewwindow' set.
3985 win_T *win;
3986
3987 FOR_ALL_WINDOWS(win)
3988 if (win->w_p_pvw && win != curwin)
3989 {
3990 curwin->w_p_pvw = FALSE;
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00003991 return e_preview_window_already_exists;
3992 }
3993
3994 return NULL;
3995}
3996#endif
3997
3998#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
3999/*
4000 * Process the new 'pyxversion' option value.
4001 */
4002 char *
4003did_set_pyxversion(optset_T *args UNUSED)
4004{
4005 char *errmsg = NULL;
4006
4007 if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
4008 errmsg = e_invalid_argument;
4009
4010 return errmsg;
4011}
4012#endif
4013
4014/*
4015 * Process the updated 'readonly' option value.
4016 */
4017 char *
4018did_set_readonly(optset_T *args)
4019{
4020 // when 'readonly' is reset globally, also reset readonlymode
4021 if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0)
4022 readonlymode = FALSE;
4023
4024 // when 'readonly' is set may give W10 again
4025 if (curbuf->b_p_ro)
4026 curbuf->b_did_warn = FALSE;
4027
4028 redraw_titles();
4029
4030 return NULL;
4031}
4032
4033/*
4034 * Process the updated 'scrollbind' option value.
4035 */
4036 char *
4037did_set_scrollbind(optset_T *args UNUSED)
4038{
4039 // when 'scrollbind' is set: snapshot the current position to avoid a jump
4040 // at the end of normal_cmd()
4041 if (!curwin->w_p_scb)
4042 return NULL;
4043
4044 do_check_scrollbind(FALSE);
4045 curwin->w_scbind_pos = curwin->w_topline;
4046 return NULL;
4047}
4048
4049#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4050/*
4051 * Process the updated 'shellslash' option value.
4052 */
4053 char *
4054did_set_shellslash(optset_T *args UNUSED)
4055{
4056 if (p_ssl)
4057 {
4058 psepc = '/';
4059 psepcN = '\\';
4060 pseps[0] = '/';
4061 }
4062 else
4063 {
4064 psepc = '\\';
4065 psepcN = '/';
4066 pseps[0] = '\\';
4067 }
4068
4069 // need to adjust the file name arguments and buffer names.
4070 buflist_slash_adjust();
4071 alist_slash_adjust();
4072# ifdef FEAT_EVAL
4073 scriptnames_slash_adjust();
4074# endif
4075 return NULL;
4076}
4077#endif
4078
4079/*
4080 * Process the new 'shiftwidth' or the 'tabstop' option value.
4081 */
4082 char *
4083did_set_shiftwidth_tabstop(optset_T *args)
4084{
4085 long *pp = (long *)args->os_varp;
4086 char *errmsg = NULL;
4087
4088 if (curbuf->b_p_sw < 0)
4089 {
4090 errmsg = e_argument_must_be_positive;
4091#ifdef FEAT_VARTABS
4092 // Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
4093 curbuf->b_p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
4094 ? tabstop_first(curbuf->b_p_vts_array)
4095 : curbuf->b_p_ts;
4096#else
4097 curbuf->b_p_sw = curbuf->b_p_ts;
4098#endif
4099 }
4100
4101#ifdef FEAT_FOLDING
4102 if (foldmethodIsIndent(curwin))
4103 foldUpdateAll(curwin);
4104#endif
4105 // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
4106 // parse 'cinoptions'.
4107 if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
4108 parse_cino(curbuf);
4109
4110 return errmsg;
4111}
4112
4113/*
4114 * Process the new 'showtabline' option value.
4115 */
4116 char *
4117did_set_showtabline(optset_T *args UNUSED)
4118{
4119 shell_new_rows(); // recompute window positions and heights
4120 return NULL;
4121}
4122
4123/*
4124 * Process the updated 'smoothscroll' option value.
4125 */
4126 char *
4127did_set_smoothscroll(optset_T *args UNUSED)
4128{
Luuk van Baal1bf1bf52023-10-28 21:43:31 +02004129 if (!curwin->w_p_sms)
4130 curwin->w_skipcol = 0;
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004131
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004132 return NULL;
4133}
4134
4135#if defined(FEAT_SPELL) || defined(PROTO)
4136/*
4137 * Process the updated 'spell' option value.
4138 */
4139 char *
4140did_set_spell(optset_T *args UNUSED)
4141{
4142 if (curwin->w_p_spell)
4143 return parse_spelllang(curwin);
4144
4145 return NULL;
4146}
4147#endif
4148
4149/*
4150 * Process the updated 'swapfile' option value.
4151 */
4152 char *
4153did_set_swapfile(optset_T *args UNUSED)
4154{
4155 // when 'swf' is set, create swapfile, when reset remove swapfile
4156 if (curbuf->b_p_swf && p_uc)
4157 ml_open_file(curbuf); // create the swap file
4158 else
4159 // no need to reset curbuf->b_may_swap, ml_open_file() will check
4160 // buf->b_p_swf
4161 mf_close_file(curbuf, TRUE); // remove the swap file
4162 return NULL;
4163}
4164
4165#if defined(FEAT_TERMGUICOLORS) || defined(PROTO)
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004166 char *
4167did_set_termguicolors(optset_T *args UNUSED)
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00004168{
4169# ifdef FEAT_VTP
4170 // Do not turn on 'tgc' when 24-bit colors are not supported.
4171 if (
4172# ifdef VIMDLL
4173 !gui.in_use && !gui.starting &&
4174# endif
4175 !has_vtp_working())
4176 {
4177 p_tgc = 0;
Yegappan Lakshmanan80b817b2023-02-09 22:08:52 +00004178 return e_24_bit_colors_are_not_supported_on_this_environment;
4179 }
4180 if (is_term_win32())
4181 swap_tcap();
4182# endif
4183# ifdef FEAT_GUI
4184 if (!gui.in_use && !gui.starting)
4185# endif
4186 highlight_gui_started();
4187# ifdef FEAT_VTP
4188 // reset t_Co
4189 if (is_term_win32())
4190 {
4191 control_console_color_rgb();
4192 set_termname(T_NAME);
4193 init_highlight(TRUE, FALSE);
4194 }
4195# endif
4196# ifdef FEAT_TERMINAL
4197 term_update_colors_all();
4198 term_update_palette_all();
4199 term_update_wincolor_all();
4200# endif
4201
4202 return NULL;
4203}
4204#endif
4205
4206/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004207 * Process the updated 'terse' option value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004208 */
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004209 char *
4210did_set_terse(optset_T *args UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211{
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004212 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004213
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004214 // when 'terse' is set change 'shortmess'
4215 p = vim_strchr(p_shm, SHM_SEARCH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004217 // insert 's' in p_shm
4218 if (p_terse && p == NULL)
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004219 {
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004220 STRCPY(IObuff, p_shm);
4221 STRCAT(IObuff, "s");
4222 set_string_option_direct((char_u *)"shm", -1, IObuff, OPT_FREE, 0);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004223 }
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004224 // remove 's' from p_shm
4225 else if (!p_terse && p != NULL)
4226 STRMOVE(p, p + 1);
4227 return NULL;
4228}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004230/*
4231 * Process the updated 'textauto' option value.
4232 */
4233 char *
4234did_set_textauto(optset_T *args)
4235{
4236 // when 'textauto' is set or reset also change 'fileformats'
4237 set_string_option_direct((char_u *)"ffs", -1,
4238 p_ta ? (char_u *)DFLT_FFS_VIM : (char_u *)"",
4239 OPT_FREE | args->os_flags, 0);
Bram Moolenaar53744302015-07-17 17:38:22 +02004240
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004241 return NULL;
4242}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004244/*
4245 * Process the updated 'textmode' option value.
4246 */
4247 char *
4248did_set_textmode(optset_T *args)
4249{
4250 // when 'textmode' is set or reset also change 'fileformat'
4251 set_fileformat(curbuf->b_p_tx ? EOL_DOS : EOL_UNIX, args->os_flags);
4252
4253 return NULL;
4254}
4255
4256/*
4257 * Process the new 'textwidth' option value.
4258 */
4259 char *
4260did_set_textwidth(optset_T *args UNUSED)
4261{
4262 char *errmsg = NULL;
4263
4264 if (curbuf->b_p_tw < 0)
4265 {
4266 errmsg = e_argument_must_be_positive;
4267 curbuf->b_p_tw = 0;
4268 }
4269#ifdef FEAT_SYN_HL
4270 {
4271 win_T *wp;
4272 tabpage_T *tp;
4273
4274 FOR_ALL_TAB_WINDOWS(tp, wp)
4275 check_colorcolumn(wp);
4276 }
Bram Moolenaar53744302015-07-17 17:38:22 +02004277#endif
4278
Bram Moolenaar31e5c602022-04-15 13:53:33 +01004279 return errmsg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280}
4281
4282/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004283 * Process the updated 'title' or the 'icon' option value.
4284 */
4285 char *
4286did_set_title_icon(optset_T *args UNUSED)
4287{
4288 // when 'title' changed, may need to change the title; same for 'icon'
4289 did_set_title();
4290 return NULL;
4291}
4292
4293/*
4294 * Process the new 'titlelen' option value.
4295 */
4296 char *
4297did_set_titlelen(optset_T *args)
4298{
4299 long old_value = args->os_oldval.number;
4300 char *errmsg = NULL;
4301
4302 // if 'titlelen' has changed, redraw the title
4303 if (p_titlelen < 0)
4304 {
4305 errmsg = e_argument_must_be_positive;
4306 p_titlelen = 85;
4307 }
4308 if (starting != NO_SCREEN && old_value != p_titlelen)
4309 need_maketitle = TRUE;
4310
4311 return errmsg;
4312}
4313
4314#if defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
4315/*
4316 * Process the updated 'undofile' option value.
4317 */
4318 char *
4319did_set_undofile(optset_T *args)
4320{
4321 // Only take action when the option was set.
4322 if (!curbuf->b_p_udf && !p_udf)
4323 return NULL;
4324
4325 // When reset we do not delete the undo file, the option may be set again
4326 // without making any changes in between.
4327 char_u hash[UNDO_HASH_SIZE];
4328 buf_T *save_curbuf = curbuf;
4329
4330 FOR_ALL_BUFFERS(curbuf)
4331 {
4332 // When 'undofile' is set globally: for every buffer, otherwise
4333 // only for the current buffer: Try to read in the undofile,
4334 // if one exists, the buffer wasn't changed and the buffer was
4335 // loaded
4336 if ((curbuf == save_curbuf
4337 || (args->os_flags & OPT_GLOBAL)
4338 || args->os_flags == 0)
4339 && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
4340 {
4341#ifdef FEAT_CRYPT
Christian Brabandtaae58342023-04-23 17:50:22 +01004342 if (crypt_method_is_sodium(crypt_get_method_nr(curbuf)))
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004343 continue;
4344#endif
4345 u_compute_hash(hash);
4346 u_read_undo(NULL, hash, curbuf->b_fname);
4347 }
4348 }
4349 curbuf = save_curbuf;
4350
4351 return NULL;
4352}
4353#endif
4354
4355/*
4356 * Process the new global 'undolevels' option value.
4357 */
4358 static void
4359update_global_undolevels(long value, long old_value)
4360{
4361 // sync undo before 'undolevels' changes
4362
4363 // use the old value, otherwise u_sync() may not work properly
4364 p_ul = old_value;
4365 u_sync(TRUE);
4366 p_ul = value;
4367}
4368
4369/*
4370 * Process the new buffer local 'undolevels' option value.
4371 */
4372 static void
4373update_buflocal_undolevels(long value, long old_value)
4374{
4375 // use the old value, otherwise u_sync() may not work properly
4376 curbuf->b_p_ul = old_value;
4377 u_sync(TRUE);
4378 curbuf->b_p_ul = value;
4379}
4380
4381/*
4382 * Process the new 'undolevels' option value.
4383 */
4384 char *
4385did_set_undolevels(optset_T *args)
4386{
4387 long *pp = (long *)args->os_varp;
4388
4389 if (pp == &p_ul) // global 'undolevels'
4390 update_global_undolevels(args->os_newval.number,
4391 args->os_oldval.number);
4392 else if (pp == &curbuf->b_p_ul) // buffer local 'undolevels'
4393 update_buflocal_undolevels(args->os_newval.number,
4394 args->os_oldval.number);
4395
4396 return NULL;
4397}
4398
4399/*
4400 * Process the new 'updatecount' option value.
4401 */
4402 char *
4403did_set_updatecount(optset_T *args)
4404{
4405 long old_value = args->os_oldval.number;
4406 char *errmsg = NULL;
4407
4408 // when 'updatecount' changes from zero to non-zero, open swap files
4409 if (p_uc < 0)
4410 {
4411 errmsg = e_argument_must_be_positive;
4412 p_uc = 100;
4413 }
4414 if (p_uc && !old_value)
4415 ml_open_files();
4416
4417 return errmsg;
4418}
4419
4420/*
4421 * Process the updated 'weirdinvert' option value.
4422 */
4423 char *
4424did_set_weirdinvert(optset_T *args)
4425{
4426 // When 'weirdinvert' changed, set/reset 't_xs'.
4427 // Then set 'weirdinvert' according to value of 't_xs'.
4428 if (p_wiv && !args->os_oldval.boolean)
4429 T_XS = (char_u *)"y";
4430 else if (!p_wiv && args->os_oldval.boolean)
4431 T_XS = empty_option;
4432 p_wiv = (*T_XS != NUL);
4433
4434 return NULL;
4435}
4436
4437/*
Yee Cheng Chin8f4fb002023-10-17 10:06:56 +02004438 * Process the new 'wildchar' / 'wildcharm' option value.
4439 */
4440 char *
4441did_set_wildchar(optset_T *args)
4442{
4443 long c = *(long *)args->os_varp;
4444
4445 // Don't allow key values that wouldn't work as wildchar.
4446 if (c == Ctrl_C || c == '\n' || c == '\r' || c == K_KENTER)
4447 return e_invalid_argument;
4448
4449 return NULL;
4450}
4451
4452/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004453 * Process the new 'window' option value.
4454 */
4455 char *
4456did_set_window(optset_T *args UNUSED)
4457{
4458 if (p_window < 1)
4459 p_window = 1;
4460 else if (p_window >= Rows)
4461 p_window = Rows - 1;
4462 return NULL;
4463}
4464
4465/*
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004466 * Process the new 'winheight' or the 'helpheight' option value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004468 char *
4469did_set_winheight_helpheight(optset_T *args)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470{
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004471 long *pp = (long *)args->os_varp;
4472 char *errmsg = NULL;
4473
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004474 if (p_wh < 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004476 errmsg = e_argument_must_be_positive;
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004477 p_wh = 1;
4478 }
4479 if (p_wmh > p_wh)
4480 {
4481 errmsg = e_winheight_cannot_be_smaller_than_winminheight;
4482 p_wh = p_wmh;
4483 }
4484 if (p_hh < 0)
4485 {
4486 errmsg = e_argument_must_be_positive;
4487 p_hh = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 }
4489
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004490 // Change window height NOW
4491 if (!ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004492 {
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004493 if (pp == &p_wh && curwin->w_height < p_wh)
4494 win_setheight((int)p_wh);
4495 if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
4496 win_setheight((int)p_hh);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004499 return errmsg;
4500}
4501
4502/*
4503 * Process the new 'winminheight' option value.
4504 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004505 char *
4506did_set_winminheight(optset_T *args UNUSED)
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004507{
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004508 char *errmsg = NULL;
4509
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004510 if (p_wmh < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 {
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004512 errmsg = e_argument_must_be_positive;
4513 p_wmh = 0;
4514 }
4515 if (p_wmh > p_wh)
4516 {
4517 errmsg = e_winheight_cannot_be_smaller_than_winminheight;
4518 p_wmh = p_wh;
4519 }
4520 win_setminheight();
4521
4522 return errmsg;
4523}
4524
4525/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004526 * Process the new 'winminwidth' option value.
4527 */
4528 char *
4529did_set_winminwidth(optset_T *args UNUSED)
4530{
4531 char *errmsg = NULL;
4532
4533 if (p_wmw < 0)
4534 {
4535 errmsg = e_argument_must_be_positive;
4536 p_wmw = 0;
4537 }
4538 if (p_wmw > p_wiw)
4539 {
4540 errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
4541 p_wmw = p_wiw;
4542 }
4543 win_setminwidth();
4544
4545 return errmsg;
4546}
4547
4548/*
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004549 * Process the new 'winwidth' option value.
4550 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004551 char *
4552did_set_winwidth(optset_T *args UNUSED)
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004553{
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004554 char *errmsg = NULL;
4555
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004556 if (p_wiw < 1)
4557 {
4558 errmsg = e_argument_must_be_positive;
4559 p_wiw = 1;
4560 }
4561 if (p_wmw > p_wiw)
4562 {
4563 errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
4564 p_wiw = p_wmw;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 }
Bram Moolenaar4c7ed462006-02-15 22:18:42 +00004566
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004567 // Change window width NOW
4568 if (!ONE_WINDOW && curwin->w_width < p_wiw)
4569 win_setwidth((int)p_wiw);
4570
4571 return errmsg;
4572}
4573
4574/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004575 * Process the updated 'wrap' option value.
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004576 */
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004577 char *
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004578did_set_wrap(optset_T *args UNUSED)
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004579{
Luuk van Baal1bf1bf52023-10-28 21:43:31 +02004580 // Set w_leftcol or w_skipcol to zero.
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004581 if (curwin->w_p_wrap)
4582 curwin->w_leftcol = 0;
Luuk van Baal1bf1bf52023-10-28 21:43:31 +02004583 else
4584 curwin->w_skipcol = 0;
4585
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004586 return NULL;
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004587}
4588
4589/*
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004590 * Set the value of a boolean option, and take care of side effects.
4591 * Returns NULL for success, or an error message for an error.
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004592 */
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004593 static char *
4594set_bool_option(
4595 int opt_idx, // index in options[] table
4596 char_u *varp, // pointer to the option variable
4597 int value, // new value
4598 int opt_flags) // OPT_LOCAL and/or OPT_GLOBAL
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004599{
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004600 int old_value = *(int *)varp;
4601#if defined(FEAT_EVAL)
4602 int old_global_value = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603#endif
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004604 char *errmsg = NULL;
4605
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004606 // Disallow changing some options from secure mode
4607 if ((secure
4608#ifdef HAVE_SANDBOX
4609 || sandbox != 0
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004610#endif
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004611 ) && (options[opt_idx].flags & P_SECURE))
4612 return e_not_allowed_here;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004613
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004614#if defined(FEAT_EVAL)
4615 // Save the global value before changing anything. This is needed as for
4616 // a global-only option setting the "local value" in fact sets the global
4617 // value (since there is only one value).
4618 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
4619 old_global_value = *(int *)get_varp_scope(&(options[opt_idx]),
4620 OPT_GLOBAL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621#endif
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004622
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004623 *(int *)varp = value; // set the new value
4624#ifdef FEAT_EVAL
4625 // Remember where the option was set.
4626 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02004627#endif
4628
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629#ifdef FEAT_GUI
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004630 need_mouse_correct = TRUE;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004631#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004633 // May set global value for local option.
4634 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
4635 *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004636
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004637 // Handle side effects of changing a bool option.
4638 if (options[opt_idx].opt_did_set_cb != NULL)
4639 {
4640 optset_T args;
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004641
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004642 CLEAR_FIELD(args);
4643 args.os_varp = varp;
4644 args.os_flags = opt_flags;
4645 args.os_oldval.boolean = old_value;
4646 args.os_newval.boolean = value;
4647 args.os_errbuf = NULL;
4648 errmsg = options[opt_idx].opt_did_set_cb(&args);
zeertzjqdeba02d2023-11-02 21:01:19 +01004649 if (errmsg != NULL)
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004650 return errmsg;
4651 }
4652
4653 // after handling side effects, call autocommand
4654
4655 options[opt_idx].flags |= P_WAS_SET;
4656
4657#if defined(FEAT_EVAL)
4658 apply_optionset_autocmd(opt_idx, opt_flags,
4659 (long)(old_value ? TRUE : FALSE),
4660 (long)(old_global_value ? TRUE : FALSE),
4661 (long)(value ? TRUE : FALSE), NULL);
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004662#endif
4663
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004664 comp_col(); // in case 'ruler' or 'showcmd' changed
zeertzjqfcaed6a2024-02-18 09:33:54 +01004665
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004666 if (curwin->w_curswant != MAXCOL
zeertzjqfcaed6a2024-02-18 09:33:54 +01004667 && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0
4668 && (options[opt_idx].flags & P_HLONLY) == 0)
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004669 curwin->w_set_curswant = TRUE;
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004670
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004671 if ((opt_flags & OPT_NO_REDRAW) == 0)
4672 check_redraw(options[opt_idx].flags);
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004673
4674 return errmsg;
4675}
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004676
4677/*
4678 * Check the bounds of numeric options.
4679 */
4680 static char *
4681check_num_option_bounds(
4682 long *pp,
4683 long old_value,
4684 long old_Rows,
4685 long old_Columns,
4686 char *errbuf,
4687 size_t errbuflen,
4688 char *errmsg)
4689{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 if (Rows < min_rows() && full_screen)
4691 {
4692 if (errbuf != NULL)
4693 {
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00004694 vim_snprintf(errbuf, errbuflen,
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004695 _(e_need_at_least_nr_lines), min_rows());
Bram Moolenaar071d4272004-06-13 20:20:40 +00004696 errmsg = errbuf;
4697 }
4698 Rows = min_rows();
4699 }
4700 if (Columns < MIN_COLUMNS && full_screen)
4701 {
4702 if (errbuf != NULL)
4703 {
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00004704 vim_snprintf(errbuf, errbuflen,
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004705 _(e_need_at_least_nr_columns), MIN_COLUMNS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706 errmsg = errbuf;
4707 }
4708 Columns = MIN_COLUMNS;
4709 }
Bram Moolenaare057d402013-06-30 17:51:51 +02004710 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00004712 // If the screen (shell) height has been changed, assume it is the
4713 // physical screenheight.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 if (old_Rows != Rows || old_Columns != Columns)
4715 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004716 // Changing the screen size is not allowed while updating the screen.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717 if (updating_screen)
4718 *pp = old_value;
4719 else if (full_screen
4720#ifdef FEAT_GUI
4721 && !gui.starting
4722#endif
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004723 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724 set_shellsize((int)Columns, (int)Rows, TRUE);
4725 else
4726 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004727 // Postpone the resizing; check the size and cmdline position for
4728 // messages.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729 check_shellsize();
4730 if (cmdline_row > Rows - p_ch && Rows > p_ch)
4731 cmdline_row = Rows - p_ch;
4732 }
Bram Moolenaard68071d2006-05-02 22:08:30 +00004733 if (p_window >= Rows || !option_was_set((char_u *)"window"))
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004734 p_window = Rows - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 }
4736
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737 if (curbuf->b_p_ts <= 0)
4738 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004739 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 curbuf->b_p_ts = 8;
4741 }
Bram Moolenaar652dee42022-01-28 20:47:49 +00004742 else if (curbuf->b_p_ts > TABSTOP_MAX)
4743 {
4744 errmsg = e_invalid_argument;
4745 curbuf->b_p_ts = 8;
4746 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747 if (p_tm < 0)
4748 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004749 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 p_tm = 0;
4751 }
4752 if ((curwin->w_p_scr <= 0
4753 || (curwin->w_p_scr > curwin->w_height
4754 && curwin->w_height > 0))
4755 && full_screen)
4756 {
4757 if (pp == &(curwin->w_p_scr))
4758 {
4759 if (curwin->w_p_scr != 0)
Bram Moolenaard8e44472021-07-21 22:20:33 +02004760 errmsg = e_invalid_scroll_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761 win_comp_scroll(curwin);
4762 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004763 // If 'scroll' became invalid because of a side effect silently adjust
4764 // it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004765 else if (curwin->w_p_scr <= 0)
4766 curwin->w_p_scr = 1;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004767 else // curwin->w_p_scr > curwin->w_height
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 curwin->w_p_scr = curwin->w_height;
4769 }
Bram Moolenaar991e10f2008-10-02 20:48:41 +00004770 if (p_hi < 0)
4771 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004772 errmsg = e_argument_must_be_positive;
Bram Moolenaar991e10f2008-10-02 20:48:41 +00004773 p_hi = 0;
4774 }
Bram Moolenaar78159bb2014-06-25 11:48:54 +02004775 else if (p_hi > 10000)
4776 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004777 errmsg = e_invalid_argument;
Bram Moolenaar78159bb2014-06-25 11:48:54 +02004778 p_hi = 10000;
4779 }
Bram Moolenaarfbc0d2e2013-05-19 19:40:29 +02004780 if (p_re < 0 || p_re > 2)
4781 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00004782 errmsg = e_invalid_argument;
Bram Moolenaarfbc0d2e2013-05-19 19:40:29 +02004783 p_re = 0;
4784 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 if (p_report < 0)
4786 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004787 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788 p_report = 1;
4789 }
Bram Moolenaar1e015462005-09-25 22:16:38 +00004790 if ((p_sj < -100 || p_sj >= Rows) && full_screen)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004792 if (Rows != old_Rows) // Rows changed, just adjust p_sj
Bram Moolenaar071d4272004-06-13 20:20:40 +00004793 p_sj = Rows / 2;
4794 else
4795 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02004796 errmsg = e_invalid_scroll_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 p_sj = 1;
4798 }
4799 }
4800 if (p_so < 0 && full_screen)
4801 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004802 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 p_so = 0;
4804 }
4805 if (p_siso < 0 && full_screen)
4806 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004807 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 p_siso = 0;
4809 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 if (p_cwh < 1)
4811 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004812 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 p_cwh = 1;
4814 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 if (p_ut < 0)
4816 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004817 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818 p_ut = 2000;
4819 }
4820 if (p_ss < 0)
4821 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004822 errmsg = e_argument_must_be_positive;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 p_ss = 0;
4824 }
4825
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004826 return errmsg;
4827}
4828
4829/*
4830 * Set the value of a number option, and take care of side effects.
4831 * Returns NULL for success, or an error message for an error.
4832 */
4833 static char *
4834set_num_option(
4835 int opt_idx, // index in options[] table
4836 char_u *varp, // pointer to the option variable
4837 long value, // new value
4838 char *errbuf, // buffer for error messages
4839 size_t errbuflen, // length of "errbuf"
4840 int opt_flags) // OPT_LOCAL, OPT_GLOBAL,
4841 // OPT_MODELINE, etc.
4842{
4843 char *errmsg = NULL;
4844 long old_value = *(long *)varp;
4845#if defined(FEAT_EVAL)
4846 long old_global_value = 0; // only used when setting a local and
4847 // global option
4848#endif
4849 long old_Rows = Rows; // remember old Rows
4850 long old_Columns = Columns; // remember old Columns
4851 long *pp = (long *)varp;
4852
4853 // Disallow changing some options from secure mode.
4854 if ((secure
4855#ifdef HAVE_SANDBOX
4856 || sandbox != 0
4857#endif
4858 ) && (options[opt_idx].flags & P_SECURE))
4859 return e_not_allowed_here;
4860
4861#if defined(FEAT_EVAL)
4862 // Save the global value before changing anything. This is needed as for
4863 // a global-only option setting the "local value" in fact sets the global
4864 // value (since there is only one value).
4865 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
4866 old_global_value = *(long *)get_varp_scope(&(options[opt_idx]),
4867 OPT_GLOBAL);
4868#endif
4869
4870 *pp = value;
4871#ifdef FEAT_EVAL
4872 // Remember where the option was set.
4873 set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
4874#endif
4875#ifdef FEAT_GUI
4876 need_mouse_correct = TRUE;
4877#endif
4878
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004879 // Invoke the option specific callback function to validate and apply the
4880 // new value.
4881 if (options[opt_idx].opt_did_set_cb != NULL)
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004882 {
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004883 optset_T args;
4884
Yegappan Lakshmanan5284b232023-03-04 19:57:32 +00004885 CLEAR_FIELD(args);
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004886 args.os_varp = varp;
4887 args.os_flags = opt_flags;
4888 args.os_oldval.number = old_value;
4889 args.os_newval.number = value;
Yegappan Lakshmanan6d611de2023-02-25 11:59:33 +00004890 args.os_errbuf = NULL;
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004891 errmsg = options[opt_idx].opt_did_set_cb(&args);
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004892 }
4893
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00004894 // Check the bounds for numeric options here
Yegappan Lakshmanan0caaf1e2023-02-09 12:23:17 +00004895 errmsg = check_num_option_bounds(pp, old_value, old_Rows, old_Columns,
4896 errbuf, errbuflen, errmsg);
4897
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004898 // May set global value for local option.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004899 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
4900 *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
4901
4902 options[opt_idx].flags |= P_WAS_SET;
4903
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004904#if defined(FEAT_EVAL)
Bram Moolenaarf4140482020-02-15 23:06:45 +01004905 apply_optionset_autocmd(opt_idx, opt_flags, old_value, old_global_value,
4906 value, errmsg);
Bram Moolenaar53744302015-07-17 17:38:22 +02004907#endif
4908
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004909 comp_col(); // in case 'columns' or 'ls' changed
zeertzjqfcaed6a2024-02-18 09:33:54 +01004910
Bram Moolenaar913077c2012-03-28 19:59:04 +02004911 if (curwin->w_curswant != MAXCOL
zeertzjqfcaed6a2024-02-18 09:33:54 +01004912 && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0
4913 && (options[opt_idx].flags & P_HLONLY) == 0)
Bram Moolenaar913077c2012-03-28 19:59:04 +02004914 curwin->w_set_curswant = TRUE;
zeertzjqfcaed6a2024-02-18 09:33:54 +01004915
Bram Moolenaar37294bd2021-03-10 13:40:08 +01004916 if ((opt_flags & OPT_NO_REDRAW) == 0)
4917 check_redraw(options[opt_idx].flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918
4919 return errmsg;
4920}
4921
4922/*
4923 * Called after an option changed: check if something needs to be redrawn.
4924 */
Bram Moolenaardac13472019-09-16 21:06:21 +02004925 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01004926check_redraw(long_u flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004928 // Careful: P_RCLR and P_RALL are a combination of other P_ flags
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004929 int doclear = (flags & P_RCLR) == P_RCLR;
4930 int all = ((flags & P_RALL) == P_RALL || doclear);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004931
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004932 if ((flags & P_RSTAT) || all) // mark all status lines dirty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 status_redraw_all();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934
4935 if ((flags & P_RBUF) || (flags & P_RWIN) || all)
zeertzjqfcaed6a2024-02-18 09:33:54 +01004936 {
4937 if (flags & P_HLONLY)
4938 redraw_later(UPD_NOT_VALID);
4939 else
4940 changed_window_setting();
4941 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942 if (flags & P_RBUF)
Bram Moolenaara4d158b2022-08-14 14:17:45 +01004943 redraw_curbuf_later(UPD_NOT_VALID);
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004944 if (doclear)
Bram Moolenaara4d158b2022-08-14 14:17:45 +01004945 redraw_all_later(UPD_CLEAR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004946 else if (all)
Bram Moolenaara4d158b2022-08-14 14:17:45 +01004947 redraw_all_later(UPD_NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004948}
4949
4950/*
4951 * Find index for option 'arg'.
4952 * Return -1 if not found.
4953 */
Bram Moolenaardac13472019-09-16 21:06:21 +02004954 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01004955findoption(char_u *arg)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956{
4957 int opt_idx;
4958 char *s, *p;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004959 static short quick_tab[27] = {0, 0}; // quick access table
Bram Moolenaar071d4272004-06-13 20:20:40 +00004960 int is_term_opt;
4961
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00004962 // For first call: Initialize the quick-access table.
4963 // It contains the index for the first option that starts with a certain
4964 // letter. There are 26 letters, plus the first "t_" option.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 if (quick_tab[1] == 0)
4966 {
4967 p = options[0].fullname;
4968 for (opt_idx = 1; (s = options[opt_idx].fullname) != NULL; opt_idx++)
4969 {
4970 if (s[0] != p[0])
4971 {
4972 if (s[0] == 't' && s[1] == '_')
4973 quick_tab[26] = opt_idx;
4974 else
4975 quick_tab[CharOrdLow(s[0])] = opt_idx;
4976 }
4977 p = s;
4978 }
4979 }
4980
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00004981 // Check for name starting with an illegal character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004982 if (arg[0] < 'a' || arg[0] > 'z')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004983 return -1;
4984
4985 is_term_opt = (arg[0] == 't' && arg[1] == '_');
4986 if (is_term_opt)
4987 opt_idx = quick_tab[26];
4988 else
4989 opt_idx = quick_tab[CharOrdLow(arg[0])];
zeertzjqf48558e2023-12-08 21:34:31 +01004990 for (; (s = options[opt_idx].fullname) != NULL && s[0] == arg[0]; opt_idx++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01004992 if (STRCMP(arg, s) == 0) // match full name
Bram Moolenaar071d4272004-06-13 20:20:40 +00004993 break;
4994 }
zeertzjqf48558e2023-12-08 21:34:31 +01004995 if (s != NULL && s[0] != arg[0])
4996 s = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997 if (s == NULL && !is_term_opt)
4998 {
4999 opt_idx = quick_tab[CharOrdLow(arg[0])];
5000 for ( ; options[opt_idx].fullname != NULL; opt_idx++)
5001 {
5002 s = options[opt_idx].shortname;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005003 if (s != NULL && STRCMP(arg, s) == 0) // match short name
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004 break;
5005 s = NULL;
5006 }
5007 }
5008 if (s == NULL)
5009 opt_idx = -1;
5010 return opt_idx;
5011}
5012
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00005013#if defined(FEAT_EVAL) || defined(FEAT_TCL) || defined(FEAT_MZSCHEME) \
5014 || defined(FEAT_SPELL) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015/*
5016 * Get the value for an option.
5017 *
5018 * Returns:
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005019 * Number option: gov_number, *numval gets value.
Bram Moolenaara7251492021-01-02 16:53:13 +01005020 * Toggle option: gov_bool, *numval gets value.
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005021 * String option: gov_string, *stringval gets allocated string.
5022 * Hidden Number option: gov_hidden_number.
5023 * Hidden Toggle option: gov_hidden_bool.
5024 * Hidden String option: gov_hidden_string.
5025 * Unknown option: gov_unknown.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00005026 *
5027 * "flagsp" (if not NULL) is set to the option flags (P_xxxx).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005028 */
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005029 getoption_T
Bram Moolenaar9b578142016-01-30 19:39:49 +01005030get_option_value(
5031 char_u *name,
5032 long *numval,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005033 char_u **stringval, // NULL when only checking existence
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00005034 int *flagsp,
5035 int scope)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036{
5037 int opt_idx;
5038 char_u *varp;
5039
5040 opt_idx = findoption(name);
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005041 if (opt_idx < 0) // option not in the table
Bram Moolenaare353c402017-02-04 19:49:16 +01005042 {
5043 int key;
5044
5045 if (STRLEN(name) == 4 && name[0] == 't' && name[1] == '_'
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005046 && (key = find_key_option(name, FALSE)) != 0)
Bram Moolenaare353c402017-02-04 19:49:16 +01005047 {
5048 char_u key_name[2];
5049 char_u *p;
5050
Bram Moolenaar10c75c42021-12-28 20:53:30 +00005051 if (flagsp != NULL)
5052 *flagsp = 0; // terminal option has no flags
5053
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005054 // check for a terminal option
Bram Moolenaare353c402017-02-04 19:49:16 +01005055 if (key < 0)
5056 {
5057 key_name[0] = KEY2TERMCAP0(key);
5058 key_name[1] = KEY2TERMCAP1(key);
5059 }
5060 else
5061 {
5062 key_name[0] = KS_KEY;
5063 key_name[1] = (key & 0xff);
5064 }
5065 p = find_termcode(key_name);
5066 if (p != NULL)
5067 {
5068 if (stringval != NULL)
5069 *stringval = vim_strsave(p);
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005070 return gov_string;
Bram Moolenaare353c402017-02-04 19:49:16 +01005071 }
5072 }
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005073 return gov_unknown;
Bram Moolenaare353c402017-02-04 19:49:16 +01005074 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005075
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00005076 varp = get_varp_scope(&(options[opt_idx]), scope);
5077
5078 if (flagsp != NULL)
5079 // Return the P_xxxx option flags.
5080 *flagsp = options[opt_idx].flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005081
5082 if (options[opt_idx].flags & P_STRING)
5083 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005084 if (varp == NULL) // hidden option
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005085 return gov_hidden_string;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 if (stringval != NULL)
5087 {
zeertzjq51f0bc32022-05-09 13:33:39 +01005088 if ((char_u **)varp == &p_pt) // 'pastetoggle'
zeertzjqcdc83932022-09-12 13:38:41 +01005089 *stringval = str2special_save(*(char_u **)(varp), FALSE,
5090 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091#ifdef FEAT_CRYPT
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005092 // never return the value of the crypt key
zeertzjq51f0bc32022-05-09 13:33:39 +01005093 else if ((char_u **)varp == &curbuf->b_p_key
Bram Moolenaarc1a11ed2008-06-24 22:09:24 +00005094 && **(char_u **)(varp) != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095 *stringval = vim_strsave((char_u *)"*****");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096#endif
zeertzjq51f0bc32022-05-09 13:33:39 +01005097 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 *stringval = vim_strsave(*(char_u **)(varp));
5099 }
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005100 return gov_string;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 }
5102
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005103 if (varp == NULL) // hidden option
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005104 return (options[opt_idx].flags & P_NUM)
5105 ? gov_hidden_number : gov_hidden_bool;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106 if (options[opt_idx].flags & P_NUM)
5107 *numval = *(long *)varp;
5108 else
5109 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005110 // Special case: 'modified' is b_changed, but we also want to consider
5111 // it set when 'ff' or 'fenc' changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112 if ((int *)varp == &curbuf->b_changed)
5113 *numval = curbufIsChanged();
5114 else
Bram Moolenaar2acfbed2016-07-01 23:14:02 +02005115 *numval = (long) *(int *)varp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116 }
Bram Moolenaardd1f4262020-12-31 17:41:01 +01005117 return (options[opt_idx].flags & P_NUM) ? gov_number : gov_bool;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118}
5119#endif
5120
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005121#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005122/*
5123 * Returns the option attributes and its value. Unlike the above function it
5124 * will return either global value or local value of the option depending on
5125 * what was requested, but it will never return global value if it was
5126 * requested to return local one and vice versa. Neither it will return
5127 * buffer-local value if it was requested to return window-local one.
5128 *
5129 * Pretends that option is absent if it is not present in the requested scope
5130 * (i.e. has no global, window-local or buffer-local value depending on
5131 * opt_type). Uses
5132 *
5133 * Returned flags:
Bram Moolenaar75a8d742014-05-07 15:10:21 +02005134 * 0 hidden or unknown option, also option that does not have requested
5135 * type (see SREQ_* in vim.h)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005136 * see SOPT_* in vim.h for other flags
5137 *
5138 * Possible opt_type values: see SREQ_* in vim.h
5139 */
5140 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005141get_option_value_strict(
5142 char_u *name,
5143 long *numval,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005144 char_u **stringval, // NULL when only obtaining attributes
Bram Moolenaar9b578142016-01-30 19:39:49 +01005145 int opt_type,
5146 void *from)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005147{
5148 int opt_idx;
Bram Moolenaar68001862013-05-11 13:45:05 +02005149 char_u *varp = NULL;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005150 struct vimoption *p;
5151 int r = 0;
5152
5153 opt_idx = findoption(name);
5154 if (opt_idx < 0)
5155 return 0;
5156
5157 p = &(options[opt_idx]);
5158
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005159 // Hidden option
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005160 if (p->var == NULL)
5161 return 0;
5162
5163 if (p->flags & P_BOOL)
5164 r |= SOPT_BOOL;
5165 else if (p->flags & P_NUM)
5166 r |= SOPT_NUM;
5167 else if (p->flags & P_STRING)
5168 r |= SOPT_STRING;
5169
5170 if (p->indir == PV_NONE)
5171 {
5172 if (opt_type == SREQ_GLOBAL)
5173 r |= SOPT_GLOBAL;
5174 else
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005175 return 0; // Did not request global-only option
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005176 }
5177 else
5178 {
5179 if (p->indir & PV_BOTH)
5180 r |= SOPT_GLOBAL;
5181 else if (opt_type == SREQ_GLOBAL)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005182 return 0; // Requested global option
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005183
5184 if (p->indir & PV_WIN)
5185 {
5186 if (opt_type == SREQ_BUF)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005187 return 0; // Did not request window-local option
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005188 else
5189 r |= SOPT_WIN;
5190 }
5191 else if (p->indir & PV_BUF)
5192 {
5193 if (opt_type == SREQ_WIN)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005194 return 0; // Did not request buffer-local option
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005195 else
5196 r |= SOPT_BUF;
5197 }
5198 }
5199
5200 if (stringval == NULL)
5201 return r;
5202
5203 if (opt_type == SREQ_GLOBAL)
5204 varp = p->var;
5205 else
5206 {
5207 if (opt_type == SREQ_BUF)
5208 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005209 // Special case: 'modified' is b_changed, but we also want to
5210 // consider it set when 'ff' or 'fenc' changed.
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005211 if (p->indir == PV_MOD)
5212 {
Bram Moolenaardefe6422018-06-24 15:14:07 +02005213 *numval = bufIsChanged((buf_T *)from);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005214 varp = NULL;
5215 }
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00005216# ifdef FEAT_CRYPT
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005217 else if (p->indir == PV_KEY)
5218 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005219 // never return the value of the crypt key
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005220 *stringval = NULL;
5221 varp = NULL;
5222 }
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00005223# endif
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005224 else
5225 {
Bram Moolenaardefe6422018-06-24 15:14:07 +02005226 buf_T *save_curbuf = curbuf;
5227
5228 // only getting a pointer, no need to use aucmd_prepbuf()
5229 curbuf = (buf_T *)from;
5230 curwin->w_buffer = curbuf;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005231 varp = get_varp(p);
Bram Moolenaardefe6422018-06-24 15:14:07 +02005232 curbuf = save_curbuf;
5233 curwin->w_buffer = curbuf;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005234 }
5235 }
5236 else if (opt_type == SREQ_WIN)
5237 {
Bram Moolenaardefe6422018-06-24 15:14:07 +02005238 win_T *save_curwin = curwin;
5239
5240 curwin = (win_T *)from;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005241 curbuf = curwin->w_buffer;
5242 varp = get_varp(p);
5243 curwin = save_curwin;
5244 curbuf = curwin->w_buffer;
5245 }
5246 if (varp == p->var)
5247 return (r | SOPT_UNSET);
5248 }
5249
5250 if (varp != NULL)
5251 {
5252 if (p->flags & P_STRING)
5253 *stringval = vim_strsave(*(char_u **)(varp));
5254 else if (p->flags & P_NUM)
5255 *numval = *(long *) varp;
5256 else
5257 *numval = *(int *)varp;
5258 }
5259
5260 return r;
5261}
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005262
5263/*
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02005264 * Iterate over options. First argument is a pointer to a pointer to a
5265 * structure inside options[] array, second is option type like in the above
5266 * function.
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005267 *
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02005268 * If first argument points to NULL it is assumed that iteration just started
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005269 * and caller needs the very first value.
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02005270 * If first argument points to the end marker function returns NULL and sets
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005271 * first argument to NULL.
5272 *
5273 * Returns full option name for current option on each call.
5274 */
5275 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005276option_iter_next(void **option, int opt_type)
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005277{
5278 struct vimoption *ret = NULL;
5279 do
5280 {
5281 if (*option == NULL)
5282 *option = (void *) options;
5283 else if (((struct vimoption *) (*option))->fullname == NULL)
5284 {
5285 *option = NULL;
5286 return NULL;
5287 }
5288 else
5289 *option = (void *) (((struct vimoption *) (*option)) + 1);
5290
5291 ret = ((struct vimoption *) (*option));
5292
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005293 // Hidden option
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005294 if (ret->var == NULL)
5295 {
5296 ret = NULL;
5297 continue;
5298 }
5299
5300 switch (opt_type)
5301 {
5302 case SREQ_GLOBAL:
5303 if (!(ret->indir == PV_NONE || ret->indir & PV_BOTH))
5304 ret = NULL;
5305 break;
5306 case SREQ_BUF:
5307 if (!(ret->indir & PV_BUF))
5308 ret = NULL;
5309 break;
5310 case SREQ_WIN:
5311 if (!(ret->indir & PV_WIN))
5312 ret = NULL;
5313 break;
5314 default:
Bram Moolenaar95f09602016-11-10 20:01:45 +01005315 internal_error("option_iter_next()");
Bram Moolenaar1028f4d2014-01-14 16:55:00 +01005316 return NULL;
5317 }
5318 }
5319 while (ret == NULL);
5320
5321 return (char_u *)ret->fullname;
5322}
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02005323#endif
5324
Bram Moolenaar071d4272004-06-13 20:20:40 +00005325/*
Bram Moolenaardac13472019-09-16 21:06:21 +02005326 * Return the flags for the option at 'opt_idx'.
5327 */
5328 long_u
5329get_option_flags(int opt_idx)
5330{
5331 return options[opt_idx].flags;
5332}
5333
5334/*
5335 * Set a flag for the option at 'opt_idx'.
5336 */
5337 void
5338set_option_flag(int opt_idx, long_u flag)
5339{
5340 options[opt_idx].flags |= flag;
5341}
5342
5343/*
Bram Moolenaardac13472019-09-16 21:06:21 +02005344 * Returns TRUE if the option at 'opt_idx' is a global option
5345 */
5346 int
5347is_global_option(int opt_idx)
5348{
5349 return options[opt_idx].indir == PV_NONE;
5350}
5351
5352/*
5353 * Returns TRUE if the option at 'opt_idx' is a global option which also has a
5354 * local value.
5355 */
5356 int
5357is_global_local_option(int opt_idx)
5358{
5359 return options[opt_idx].indir & PV_BOTH;
5360}
5361
5362/*
5363 * Returns TRUE if the option at 'opt_idx' is a window-local option
5364 */
5365 int
5366is_window_local_option(int opt_idx)
5367{
5368 return options[opt_idx].var == VAR_WIN;
5369}
5370
5371/*
5372 * Returns TRUE if the option at 'opt_idx' is a hidden option
5373 */
5374 int
5375is_hidden_option(int opt_idx)
5376{
5377 return options[opt_idx].var == NULL;
5378}
5379
5380#if defined(FEAT_CRYPT) || defined(PROTO)
5381/*
5382 * Returns TRUE if the option at 'opt_idx' is a crypt key option
5383 */
5384 int
5385is_crypt_key_option(int opt_idx)
5386{
5387 return options[opt_idx].indir == PV_KEY;
5388}
5389#endif
5390
5391/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005392 * Set the value of option "name".
5393 * Use "string" for string options, use "number" for other options.
Bram Moolenaarc96ebe72013-05-21 22:38:18 +02005394 *
Bram Moolenaar31e5c602022-04-15 13:53:33 +01005395 * Returns NULL on success or an untranslated error message on error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005396 */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005397 char *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005398set_option_value(
5399 char_u *name,
5400 long number,
5401 char_u *string,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005402 int opt_flags) // OPT_LOCAL or 0 (both)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005403{
5404 int opt_idx;
5405 char_u *varp;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00005406 long_u flags;
Christian Brabandtb39b2402023-11-29 11:34:05 +01005407 static char errbuf[ERR_BUFLEN];
5408 int errbuflen = ERR_BUFLEN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005409
5410 opt_idx = findoption(name);
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00005411 if (opt_idx < 0)
Bram Moolenaare353c402017-02-04 19:49:16 +01005412 {
5413 int key;
5414
5415 if (STRLEN(name) == 4 && name[0] == 't' && name[1] == '_'
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005416 && (key = find_key_option(name, FALSE)) != 0)
Bram Moolenaare353c402017-02-04 19:49:16 +01005417 {
5418 char_u key_name[2];
5419
5420 if (key < 0)
5421 {
5422 key_name[0] = KEY2TERMCAP0(key);
5423 key_name[1] = KEY2TERMCAP1(key);
5424 }
5425 else
5426 {
5427 key_name[0] = KS_KEY;
5428 key_name[1] = (key & 0xff);
5429 }
5430 add_termcode(key_name, string, FALSE);
5431 if (full_screen)
5432 ttest(FALSE);
Bram Moolenaara4d158b2022-08-14 14:17:45 +01005433 redraw_all_later(UPD_CLEAR);
Bram Moolenaare353c402017-02-04 19:49:16 +01005434 return NULL;
5435 }
5436
Bram Moolenaarac78dd42022-01-02 19:25:26 +00005437 semsg(_(e_unknown_option_str_2), name);
Bram Moolenaare353c402017-02-04 19:49:16 +01005438 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439 else
5440 {
5441 flags = options[opt_idx].flags;
5442#ifdef HAVE_SANDBOX
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005443 // Disallow changing some options in the sandbox
Bram Moolenaar071d4272004-06-13 20:20:40 +00005444 if (sandbox > 0 && (flags & P_SECURE))
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00005445 {
Bram Moolenaard8e44472021-07-21 22:20:33 +02005446 emsg(_(e_not_allowed_in_sandbox));
Bram Moolenaarc96ebe72013-05-21 22:38:18 +02005447 return NULL;
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00005448 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449#endif
Bram Moolenaarb71eaae2006-01-20 23:10:18 +00005450 if (flags & P_STRING)
Christian Brabandtb39b2402023-11-29 11:34:05 +01005451 return set_string_option(opt_idx, string, opt_flags, errbuf, errbuflen);
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005452
5453 varp = get_varp_scope(&(options[opt_idx]), opt_flags);
5454 if (varp != NULL) // hidden option is not changed
Bram Moolenaar071d4272004-06-13 20:20:40 +00005455 {
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005456 if (number == 0 && string != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005457 {
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005458 int idx;
5459
5460 // Either we are given a string or we are setting option
5461 // to zero.
5462 for (idx = 0; string[idx] == '0'; ++idx)
5463 ;
5464 if (string[idx] != NUL || idx == 0)
Bram Moolenaar96bb6212007-06-19 18:52:53 +00005465 {
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005466 // There's another character after zeros or the string
5467 // is empty. In both cases, we are trying to set a
5468 // num option using a string.
5469 semsg(_(e_number_required_after_str_equal_str),
5470 name, string);
5471 return NULL; // do nothing as we hit an error
Bram Moolenaar96bb6212007-06-19 18:52:53 +00005472
Bram Moolenaar96bb6212007-06-19 18:52:53 +00005473 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005474 }
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005475 if (flags & P_NUM)
Yegappan Lakshmanan32ff96e2023-02-13 16:10:04 +00005476 {
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005477 return set_num_option(opt_idx, varp, number,
Yegappan Lakshmanan32ff96e2023-02-13 16:10:04 +00005478 errbuf, sizeof(errbuf), opt_flags);
5479 }
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005480 else
5481 return set_bool_option(opt_idx, varp, (int)number, opt_flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005482 }
=?UTF-8?q?Dundar=20G=C3=B6c?=f26c1612022-04-07 13:26:34 +01005483
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484 }
Bram Moolenaarc96ebe72013-05-21 22:38:18 +02005485 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486}
5487
5488/*
Bram Moolenaar31e5c602022-04-15 13:53:33 +01005489 * Call set_option_value() and when an error is returned report it.
5490 */
5491 void
5492set_option_value_give_err(
5493 char_u *name,
5494 long number,
5495 char_u *string,
5496 int opt_flags) // OPT_LOCAL or 0 (both)
5497{
5498 char *errmsg = set_option_value(name, number, string, opt_flags);
5499
5500 if (errmsg != NULL)
5501 emsg(_(errmsg));
5502}
5503
5504/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00005505 * Get the terminal code for a terminal option.
5506 * Returns NULL when not found.
5507 */
5508 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005509get_term_code(char_u *tname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510{
5511 int opt_idx;
5512 char_u *varp;
5513
5514 if (tname[0] != 't' || tname[1] != '_' ||
5515 tname[2] == NUL || tname[3] == NUL)
5516 return NULL;
5517 if ((opt_idx = findoption(tname)) >= 0)
5518 {
5519 varp = get_varp(&(options[opt_idx]));
5520 if (varp != NULL)
5521 varp = *(char_u **)(varp);
5522 return varp;
5523 }
5524 return find_termcode(tname + 2);
5525}
5526
5527 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005528get_highlight_default(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005529{
5530 int i;
5531
5532 i = findoption((char_u *)"hl");
5533 if (i >= 0)
5534 return options[i].def_val[VI_DEFAULT];
5535 return (char_u *)NULL;
5536}
5537
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005538 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01005539get_encoding_default(void)
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005540{
5541 int i;
5542
5543 i = findoption((char_u *)"enc");
5544 if (i >= 0)
5545 return options[i].def_val[VI_DEFAULT];
5546 return (char_u *)NULL;
5547}
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005548
Dominique Pelle7765f5c2022-04-10 11:26:53 +01005549#if defined(FEAT_QUICKFIX) || defined(PROTO)
Bram Moolenaar4791fcd2022-02-23 12:06:00 +00005550 int
5551is_option_allocated(char *name)
5552{
5553 int idx = findoption((char_u *)name);
5554
5555 return idx >= 0 && (options[idx].flags & P_ALLOCED);
5556}
Dominique Pelle7765f5c2022-04-10 11:26:53 +01005557#endif
Bram Moolenaar4791fcd2022-02-23 12:06:00 +00005558
Bram Moolenaar071d4272004-06-13 20:20:40 +00005559/*
5560 * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005561 * When "has_lt" is true there is a '<' before "*arg_arg".
5562 * Returns 0 when the key is not recognized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563 */
5564 static int
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005565find_key_option(char_u *arg_arg, int has_lt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005566{
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005567 int key = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005568 int modifiers;
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005569 char_u *arg = arg_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00005571 // Don't use get_special_key_code() for t_xx, we don't want it to call
5572 // add_termcap_entry().
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573 if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
5574 key = TERMCAP2KEY(arg[2], arg[3]);
Bram Moolenaar9cf4b502018-07-23 04:12:03 +02005575 else if (has_lt)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005577 --arg; // put arg at the '<'
Bram Moolenaar071d4272004-06-13 20:20:40 +00005578 modifiers = 0;
Bram Moolenaarebe9d342020-05-30 21:52:54 +02005579 key = find_special_key(&arg, &modifiers,
5580 FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, NULL);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005581 if (modifiers) // can't handle modifiers here
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582 key = 0;
5583 }
5584 return key;
5585}
5586
5587/*
5588 * if 'all' == 0: show changed options
5589 * if 'all' == 1: show all normal options
5590 * if 'all' == 2: show all terminal options
5591 */
5592 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005593showoptions(
5594 int all,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005595 int opt_flags) // OPT_LOCAL and/or OPT_GLOBAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005596{
5597 struct vimoption *p;
5598 int col;
5599 int isterm;
5600 char_u *varp;
5601 struct vimoption **items;
5602 int item_count;
5603 int run;
5604 int row, rows;
5605 int cols;
5606 int i;
5607 int len;
5608
5609#define INC 20
5610#define GAP 3
5611
Bram Moolenaar6b915c02020-01-18 15:53:19 +01005612 items = ALLOC_MULT(struct vimoption *, OPTION_COUNT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613 if (items == NULL)
5614 return;
5615
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005616 // Highlight title
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 if (all == 2)
Bram Moolenaar32526b32019-01-19 17:43:09 +01005618 msg_puts_title(_("\n--- Terminal codes ---"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 else if (opt_flags & OPT_GLOBAL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01005620 msg_puts_title(_("\n--- Global option values ---"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621 else if (opt_flags & OPT_LOCAL)
Bram Moolenaar32526b32019-01-19 17:43:09 +01005622 msg_puts_title(_("\n--- Local option values ---"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005624 msg_puts_title(_("\n--- Options ---"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005625
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00005626 // Do the loop two times:
5627 // 1. display the short items
5628 // 2. display the long items (only strings and numbers)
5629 // When "opt_flags" has OPT_ONECOLUMN do everything in run 2.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630 for (run = 1; run <= 2 && !got_int; ++run)
5631 {
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00005632 // collect the items in items[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00005633 item_count = 0;
5634 for (p = &options[0]; p->fullname != NULL; p++)
5635 {
Bram Moolenaarf86db782018-10-25 13:31:37 +02005636 // apply :filter /pat/
Bram Moolenaar6b915c02020-01-18 15:53:19 +01005637 if (message_filtered((char_u *)p->fullname))
Bram Moolenaarf86db782018-10-25 13:31:37 +02005638 continue;
5639
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640 varp = NULL;
5641 isterm = istermoption(p);
Bram Moolenaar6b915c02020-01-18 15:53:19 +01005642 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005643 {
5644 if (p->indir != PV_NONE && !isterm)
5645 varp = get_varp_scope(p, opt_flags);
5646 }
5647 else
5648 varp = get_varp(p);
5649 if (varp != NULL
5650 && ((all == 2 && isterm)
5651 || (all == 1 && !isterm)
Bram Moolenaarcacc6a52019-05-30 15:22:43 +02005652 || (all == 0 && !optval_default(p, varp, p_cp))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 {
Bram Moolenaar6b915c02020-01-18 15:53:19 +01005654 if (opt_flags & OPT_ONECOLUMN)
5655 len = Columns;
5656 else if (p->flags & P_BOOL)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005657 len = 1; // a toggle option fits always
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658 else
5659 {
5660 option_value2string(p, opt_flags);
5661 len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1;
5662 }
5663 if ((len <= INC - GAP && run == 1) ||
5664 (len > INC - GAP && run == 2))
5665 items[item_count++] = p;
5666 }
5667 }
5668
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00005669 // display the items
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 if (run == 1)
5671 {
5672 cols = (Columns + GAP - 3) / INC;
5673 if (cols == 0)
5674 cols = 1;
5675 rows = (item_count + cols - 1) / cols;
5676 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005677 else // run == 2
Bram Moolenaar071d4272004-06-13 20:20:40 +00005678 rows = item_count;
5679 for (row = 0; row < rows && !got_int; ++row)
5680 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005681 msg_putchar('\n'); // go to next line
5682 if (got_int) // 'q' typed in more
Bram Moolenaar071d4272004-06-13 20:20:40 +00005683 break;
5684 col = 0;
5685 for (i = row; i < item_count; i += rows)
5686 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005687 msg_col = col; // make columns
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688 showoneopt(items[i], opt_flags);
5689 col += INC;
5690 }
5691 out_flush();
5692 ui_breakcheck();
5693 }
5694 }
5695 vim_free(items);
5696}
5697
5698/*
5699 * Return TRUE if option "p" has its default value.
5700 */
5701 static int
Bram Moolenaarcacc6a52019-05-30 15:22:43 +02005702optval_default(struct vimoption *p, char_u *varp, int compatible)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005703{
5704 int dvi;
5705
5706 if (varp == NULL)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005707 return TRUE; // hidden option is always at default
Bram Moolenaarcacc6a52019-05-30 15:22:43 +02005708 dvi = ((p->flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709 if (p->flags & P_NUM)
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005710 return (*(long *)varp == (long)(long_i)p->def_val[dvi]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 if (p->flags & P_BOOL)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005712 // the cast to long is required for Manx C, long_i is
5713 // needed for MSVC
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005714 return (*(int *)varp == (int)(long)(long_i)p->def_val[dvi]);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005715 // P_STRING
Bram Moolenaar071d4272004-06-13 20:20:40 +00005716 return (STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0);
5717}
5718
5719/*
5720 * showoneopt: show the value of one option
5721 * must not be called with a hidden option!
5722 */
5723 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01005724showoneopt(
5725 struct vimoption *p,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005726 int opt_flags) // OPT_LOCAL or OPT_GLOBAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005727{
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005728 char_u *varp;
5729 int save_silent = silent_mode;
5730
5731 silent_mode = FALSE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005732 info_message = TRUE; // use mch_msg(), not mch_errmsg()
Bram Moolenaar071d4272004-06-13 20:20:40 +00005733
5734 varp = get_varp_scope(p, opt_flags);
5735
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005736 // for 'modified' we also need to check if 'ff' or 'fenc' changed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737 if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed
5738 ? !curbufIsChanged() : !*(int *)varp))
Bram Moolenaar32526b32019-01-19 17:43:09 +01005739 msg_puts("no");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005740 else if ((p->flags & P_BOOL) && *(int *)varp < 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01005741 msg_puts("--");
Bram Moolenaar071d4272004-06-13 20:20:40 +00005742 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005743 msg_puts(" ");
5744 msg_puts(p->fullname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005745 if (!(p->flags & P_BOOL))
5746 {
5747 msg_putchar('=');
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005748 // put value string in NameBuff
Bram Moolenaar071d4272004-06-13 20:20:40 +00005749 option_value2string(p, opt_flags);
5750 msg_outtrans(NameBuff);
5751 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +00005752
5753 silent_mode = save_silent;
5754 info_message = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005755}
5756
5757/*
5758 * Write modified options as ":set" commands to a file.
5759 *
5760 * There are three values for "opt_flags":
5761 * OPT_GLOBAL: Write global option values and fresh values of
5762 * buffer-local options (used for start of a session
5763 * file).
5764 * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for
5765 * curwin (used for a vimrc file).
5766 * OPT_LOCAL: Write buffer-local option values for curbuf, fresh
5767 * and local values for window-local options of
5768 * curwin. Local values are also written when at the
5769 * default value, because a modeline or autocommand
5770 * may have set them when doing ":edit file" and the
5771 * user has set them back at the default or fresh
5772 * value.
5773 * When "local_only" is TRUE, don't write fresh
5774 * values, only local values (for ":mkview").
5775 * (fresh value = value used for a new buffer or window for a local option).
5776 *
5777 * Return FAIL on error, OK otherwise.
5778 */
5779 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005780makeset(FILE *fd, int opt_flags, int local_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781{
5782 struct vimoption *p;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005783 char_u *varp; // currently used value
5784 char_u *varp_fresh; // local value
5785 char_u *varp_local = NULL; // fresh value
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786 char *cmd;
5787 int round;
Bram Moolenaar7fd16022007-09-06 14:35:35 +00005788 int pri;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005789
5790 /*
5791 * The options that don't have a default (terminal name, columns, lines)
5792 * are never written. Terminal options are also not written.
Bram Moolenaar7fd16022007-09-06 14:35:35 +00005793 * Do the loop over "options[]" twice: once for options with the
5794 * P_PRI_MKRC flag and once without.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005795 */
Bram Moolenaar7fd16022007-09-06 14:35:35 +00005796 for (pri = 1; pri >= 0; --pri)
5797 {
5798 for (p = &options[0]; !istermoption(p); p++)
5799 if (!(p->flags & P_NO_MKRC)
5800 && !istermoption(p)
5801 && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005803 // skip global option when only doing locals
Bram Moolenaar071d4272004-06-13 20:20:40 +00005804 if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL))
5805 continue;
5806
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005807 // Do not store options like 'bufhidden' and 'syntax' in a vimrc
5808 // file, they are always buffer-specific.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809 if ((opt_flags & OPT_GLOBAL) && (p->flags & P_NOGLOB))
5810 continue;
5811
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005812 // Global values are only written when not at the default value.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005813 varp = get_varp_scope(p, opt_flags);
Bram Moolenaarcacc6a52019-05-30 15:22:43 +02005814 if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp, p_cp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815 continue;
5816
Bram Moolenaard23b7142021-04-17 21:04:34 +02005817 if ((opt_flags & OPT_SKIPRTP) && (p->var == (char_u *)&p_rtp
5818 || p->var == (char_u *)&p_pp))
Bram Moolenaar635bd602021-04-16 19:58:22 +02005819 continue;
5820
Bram Moolenaar071d4272004-06-13 20:20:40 +00005821 round = 2;
5822 if (p->indir != PV_NONE)
5823 {
5824 if (p->var == VAR_WIN)
5825 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005826 // skip window-local option when only doing globals
Bram Moolenaar071d4272004-06-13 20:20:40 +00005827 if (!(opt_flags & OPT_LOCAL))
5828 continue;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005829 // When fresh value of window-local option is not at the
5830 // default, need to write it too.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005831 if (!(opt_flags & OPT_GLOBAL) && !local_only)
5832 {
5833 varp_fresh = get_varp_scope(p, OPT_GLOBAL);
Bram Moolenaarcacc6a52019-05-30 15:22:43 +02005834 if (!optval_default(p, varp_fresh, p_cp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835 {
5836 round = 1;
5837 varp_local = varp;
5838 varp = varp_fresh;
5839 }
5840 }
5841 }
5842 }
5843
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005844 // Round 1: fresh value for window-local options.
5845 // Round 2: other values
Bram Moolenaar071d4272004-06-13 20:20:40 +00005846 for ( ; round <= 2; varp = varp_local, ++round)
5847 {
5848 if (round == 1 || (opt_flags & OPT_GLOBAL))
5849 cmd = "set";
5850 else
5851 cmd = "setlocal";
5852
5853 if (p->flags & P_BOOL)
5854 {
5855 if (put_setbool(fd, cmd, p->fullname, *(int *)varp) == FAIL)
5856 return FAIL;
5857 }
5858 else if (p->flags & P_NUM)
5859 {
5860 if (put_setnum(fd, cmd, p->fullname, (long *)varp) == FAIL)
5861 return FAIL;
5862 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005863 else // P_STRING
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864 {
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00005865 int do_endif = FALSE;
5866
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005867 // Don't set 'syntax' and 'filetype' again if the value is
5868 // already right, avoids reloading the syntax file.
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00005869 if (
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01005870#if defined(FEAT_SYN_HL)
5871 p->indir == PV_SYN ||
5872#endif
5873 p->indir == PV_FT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874 {
5875 if (fprintf(fd, "if &%s != '%s'", p->fullname,
5876 *(char_u **)(varp)) < 0
5877 || put_eol(fd) < 0)
5878 return FAIL;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00005879 do_endif = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880 }
5881 if (put_setstring(fd, cmd, p->fullname, (char_u **)varp,
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005882 p->flags) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 return FAIL;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00005884 if (do_endif)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885 {
5886 if (put_line(fd, "endif") == FAIL)
5887 return FAIL;
5888 }
5889 }
5890 }
5891 }
Bram Moolenaar7fd16022007-09-06 14:35:35 +00005892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005893 return OK;
5894}
5895
5896#if defined(FEAT_FOLDING) || defined(PROTO)
5897/*
5898 * Generate set commands for the local fold options only. Used when
5899 * 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
5900 */
5901 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005902makefoldset(FILE *fd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903{
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005904 if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, 0) == FAIL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005905# ifdef FEAT_EVAL
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005906 || put_setstring(fd, "setlocal", "fde", &curwin->w_p_fde, 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907 == FAIL
5908# endif
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005909 || put_setstring(fd, "setlocal", "fmr", &curwin->w_p_fmr, 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005910 == FAIL
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005911 || put_setstring(fd, "setlocal", "fdi", &curwin->w_p_fdi, 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912 == FAIL
5913 || put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL
5914 || put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL
5915 || put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL
5916 || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL
5917 )
5918 return FAIL;
5919
5920 return OK;
5921}
5922#endif
5923
5924 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01005925put_setstring(
5926 FILE *fd,
5927 char *cmd,
5928 char *name,
5929 char_u **valuep,
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005930 long_u flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005931{
5932 char_u *s;
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005933 char_u *buf = NULL;
5934 char_u *part = NULL;
5935 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005936
5937 if (fprintf(fd, "%s %s=", cmd, name) < 0)
5938 return FAIL;
5939 if (*valuep != NULL)
5940 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01005941 // Output 'pastetoggle' as key names. For other
5942 // options some characters have to be escaped with
5943 // CTRL-V or backslash
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944 if (valuep == &p_pt)
5945 {
5946 s = *valuep;
5947 while (*s != NUL)
zeertzjqcdc83932022-09-12 13:38:41 +01005948 if (put_escstr(fd, str2special(&s, FALSE, FALSE), 2) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005949 return FAIL;
5950 }
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005951 // expand the option value, replace $HOME by ~
5952 else if ((flags & P_EXPAND) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953 {
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005954 int size = (int)STRLEN(*valuep) + 1;
5955
5956 // replace home directory in the whole option value into "buf"
5957 buf = alloc(size);
Bram Moolenaarf8441472011-04-28 17:24:58 +02005958 if (buf == NULL)
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005959 goto fail;
5960 home_replace(NULL, *valuep, buf, size, FALSE);
5961
5962 // If the option value is longer than MAXPATHL, we need to append
Bram Moolenaar32aa1022019-11-02 22:54:41 +01005963 // each comma separated part of the option separately, so that it
Bram Moolenaared18f2c2019-01-24 20:30:52 +01005964 // can be expanded when read back.
5965 if (size >= MAXPATHL && (flags & P_COMMA) != 0
5966 && vim_strchr(*valuep, ',') != NULL)
5967 {
5968 part = alloc(size);
5969 if (part == NULL)
5970 goto fail;
5971
5972 // write line break to clear the option, e.g. ':set rtp='
5973 if (put_eol(fd) == FAIL)
5974 goto fail;
5975
5976 p = buf;
5977 while (*p != NUL)
5978 {
5979 // for each comma separated option part, append value to
5980 // the option, :set rtp+=value
5981 if (fprintf(fd, "%s %s+=", cmd, name) < 0)
5982 goto fail;
5983 (void)copy_option_part(&p, part, size, ",");
5984 if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL)
5985 goto fail;
5986 }
5987 vim_free(buf);
5988 vim_free(part);
5989 return OK;
5990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991 if (put_escstr(fd, buf, 2) == FAIL)
Bram Moolenaarf8441472011-04-28 17:24:58 +02005992 {
5993 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994 return FAIL;
Bram Moolenaarf8441472011-04-28 17:24:58 +02005995 }
5996 vim_free(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 }
5998 else if (put_escstr(fd, *valuep, 2) == FAIL)
5999 return FAIL;
6000 }
6001 if (put_eol(fd) < 0)
6002 return FAIL;
6003 return OK;
Bram Moolenaared18f2c2019-01-24 20:30:52 +01006004fail:
6005 vim_free(buf);
6006 vim_free(part);
6007 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008}
6009
6010 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006011put_setnum(
6012 FILE *fd,
6013 char *cmd,
6014 char *name,
6015 long *valuep)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006016{
6017 long wc;
6018
6019 if (fprintf(fd, "%s %s=", cmd, name) < 0)
6020 return FAIL;
6021 if (wc_use_keyname((char_u *)valuep, &wc))
6022 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006023 // print 'wildchar' and 'wildcharm' as a key name
Bram Moolenaar071d4272004-06-13 20:20:40 +00006024 if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0)
6025 return FAIL;
6026 }
6027 else if (fprintf(fd, "%ld", *valuep) < 0)
6028 return FAIL;
6029 if (put_eol(fd) < 0)
6030 return FAIL;
6031 return OK;
6032}
6033
6034 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006035put_setbool(
6036 FILE *fd,
6037 char *cmd,
6038 char *name,
6039 int value)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006040{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006041 if (value < 0) // global/local option using global value
Bram Moolenaar893de922007-10-02 18:40:57 +00006042 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006043 if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0
6044 || put_eol(fd) < 0)
6045 return FAIL;
6046 return OK;
6047}
6048
6049/*
6050 * Clear all the terminal options.
6051 * If the option has been allocated, free the memory.
6052 * Terminal options are never hidden or indirect.
6053 */
6054 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006055clear_termoptions(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006056{
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00006057 // Reset a few things before clearing the old options. This may cause
6058 // outputting a few things that the terminal doesn't understand, but the
6059 // screen will be cleared later, so this is OK.
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02006060 mch_setmouse(FALSE); // switch mouse off
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006061 mch_restore_title(SAVE_RESTORE_BOTH); // restore window titles
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062#if defined(FEAT_XCLIPBOARD) && defined(FEAT_GUI)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006063 // When starting the GUI close the display opened for the clipboard.
6064 // After restoring the title, because that will need the display.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006065 if (gui.starting)
6066 clear_xterm_clip();
6067#endif
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006068 stoptermcap(); // stop termcap mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006070 free_termoptions();
6071}
6072
6073 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006074free_termoptions(void)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00006075{
6076 struct vimoption *p;
6077
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02006078 for (p = options; p->fullname != NULL; p++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079 if (istermoption(p))
6080 {
6081 if (p->flags & P_ALLOCED)
6082 free_string_option(*(char_u **)(p->var));
6083 if (p->flags & P_DEF_ALLOCED)
6084 free_string_option(p->def_val[VI_DEFAULT]);
6085 *(char_u **)(p->var) = empty_option;
6086 p->def_val[VI_DEFAULT] = empty_option;
6087 p->flags &= ~(P_ALLOCED|P_DEF_ALLOCED);
Bram Moolenaar35bc7d62018-10-02 14:45:10 +02006088#ifdef FEAT_EVAL
6089 // remember where the option was cleared
6090 set_option_sctx_idx((int)(p - options), OPT_GLOBAL, current_sctx);
6091#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 }
6093 clear_termcodes();
6094}
6095
6096/*
Bram Moolenaar363cb672009-07-22 12:28:17 +00006097 * Free the string for one term option, if it was allocated.
6098 * Set the string to empty_option and clear allocated flag.
6099 * "var" points to the option value.
6100 */
6101 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006102free_one_termoption(char_u *var)
Bram Moolenaar363cb672009-07-22 12:28:17 +00006103{
6104 struct vimoption *p;
6105
6106 for (p = &options[0]; p->fullname != NULL; p++)
6107 if (p->var == var)
6108 {
6109 if (p->flags & P_ALLOCED)
6110 free_string_option(*(char_u **)(p->var));
6111 *(char_u **)(p->var) = empty_option;
6112 p->flags &= ~P_ALLOCED;
6113 break;
6114 }
6115}
6116
6117/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118 * Set the terminal option defaults to the current value.
6119 * Used after setting the terminal name.
6120 */
6121 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006122set_term_defaults(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123{
6124 struct vimoption *p;
6125
6126 for (p = &options[0]; p->fullname != NULL; p++)
6127 {
6128 if (istermoption(p) && p->def_val[VI_DEFAULT] != *(char_u **)(p->var))
6129 {
6130 if (p->flags & P_DEF_ALLOCED)
6131 {
6132 free_string_option(p->def_val[VI_DEFAULT]);
6133 p->flags &= ~P_DEF_ALLOCED;
6134 }
6135 p->def_val[VI_DEFAULT] = *(char_u **)(p->var);
6136 if (p->flags & P_ALLOCED)
6137 {
6138 p->flags |= P_DEF_ALLOCED;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006139 p->flags &= ~P_ALLOCED; // don't free the value now
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 }
6141 }
6142 }
6143}
6144
6145/*
6146 * return TRUE if 'p' starts with 't_'
6147 */
6148 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01006149istermoption(struct vimoption *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150{
6151 return (p->fullname[0] == 't' && p->fullname[1] == '_');
6152}
6153
Bram Moolenaardac13472019-09-16 21:06:21 +02006154/*
6155 * Returns TRUE if the option at 'opt_idx' starts with 't_'
6156 */
6157 int
6158istermoption_idx(int opt_idx)
6159{
6160 return istermoption(&options[opt_idx]);
6161}
6162
Bram Moolenaar113e1072019-01-20 15:30:40 +01006163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006164/*
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006165 * Unset local option value, similar to ":set opt<".
6166 */
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006167 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006168unset_global_local_option(char_u *name, void *from)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006169{
6170 struct vimoption *p;
6171 int opt_idx;
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006172 buf_T *buf = (buf_T *)from;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006173
6174 opt_idx = findoption(name);
Bram Moolenaarbd8539a2015-08-11 18:53:03 +02006175 if (opt_idx < 0)
6176 return;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006177 p = &(options[opt_idx]);
6178
6179 switch ((int)p->indir)
6180 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006181 // global option with local value: use local value if it's been set
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006182 case PV_EP:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006183 clear_string_option(&buf->b_p_ep);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006184 break;
6185 case PV_KP:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006186 clear_string_option(&buf->b_p_kp);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006187 break;
6188 case PV_PATH:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006189 clear_string_option(&buf->b_p_path);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006190 break;
6191 case PV_AR:
6192 buf->b_p_ar = -1;
6193 break;
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02006194 case PV_BKC:
6195 clear_string_option(&buf->b_p_bkc);
6196 buf->b_bkc_flags = 0;
6197 break;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006198 case PV_TAGS:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006199 clear_string_option(&buf->b_p_tags);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006200 break;
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01006201 case PV_TC:
6202 clear_string_option(&buf->b_p_tc);
6203 buf->b_tc_flags = 0;
6204 break;
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01006205 case PV_SISO:
6206 curwin->w_p_siso = -1;
6207 break;
6208 case PV_SO:
6209 curwin->w_p_so = -1;
6210 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006211# ifdef FEAT_FIND_ID
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006212 case PV_DEF:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006213 clear_string_option(&buf->b_p_def);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006214 break;
6215 case PV_INC:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006216 clear_string_option(&buf->b_p_inc);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006217 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006218# endif
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006219 case PV_DICT:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006220 clear_string_option(&buf->b_p_dict);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006221 break;
6222 case PV_TSR:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006223 clear_string_option(&buf->b_p_tsr);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006224 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006225# ifdef FEAT_COMPL_FUNC
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01006226 case PV_TSRFU:
6227 clear_string_option(&buf->b_p_tsrfu);
6228 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006229# endif
Bram Moolenaar9be7c042017-01-14 14:28:30 +01006230 case PV_FP:
6231 clear_string_option(&buf->b_p_fp);
6232 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006233# ifdef FEAT_QUICKFIX
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006234 case PV_EFM:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006235 clear_string_option(&buf->b_p_efm);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006236 break;
6237 case PV_GP:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006238 clear_string_option(&buf->b_p_gp);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006239 break;
6240 case PV_MP:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006241 clear_string_option(&buf->b_p_mp);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006242 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006243# endif
6244# if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006245 case PV_BEXPR:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006246 clear_string_option(&buf->b_p_bexpr);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006247 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006248# endif
6249# if defined(FEAT_CRYPT)
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006250 case PV_CM:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006251 clear_string_option(&buf->b_p_cm);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006252 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006253# endif
6254# ifdef FEAT_LINEBREAK
Bram Moolenaaree857022019-11-09 23:26:40 +01006255 case PV_SBR:
6256 clear_string_option(&((win_T *)from)->w_p_sbr);
6257 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006258# endif
6259# ifdef FEAT_STL_OPT
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006260 case PV_STL:
Bram Moolenaar51ac8a22013-05-06 06:45:47 +02006261 clear_string_option(&((win_T *)from)->w_p_stl);
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006262 break;
Bram Moolenaar9af2ea82022-11-22 18:18:38 +00006263# endif
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01006264 case PV_UL:
6265 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
6266 break;
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01006267 case PV_LW:
6268 clear_string_option(&buf->b_p_lw);
6269 break;
Bram Moolenaar2c7292d2017-03-05 17:43:31 +01006270 case PV_MENC:
6271 clear_string_option(&buf->b_p_menc);
6272 break;
Bram Moolenaareed9d462021-02-15 20:38:25 +01006273 case PV_LCS:
6274 clear_string_option(&((win_T *)from)->w_p_lcs);
zeertzjq6a8d2e12024-01-17 20:54:49 +01006275 set_listchars_option((win_T *)from, ((win_T *)from)->w_p_lcs, TRUE,
6276 NULL, 0);
Bram Moolenaara4d158b2022-08-14 14:17:45 +01006277 redraw_later(UPD_NOT_VALID);
Bram Moolenaareed9d462021-02-15 20:38:25 +01006278 break;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006279 case PV_FCS:
6280 clear_string_option(&((win_T *)from)->w_p_fcs);
zeertzjq6a8d2e12024-01-17 20:54:49 +01006281 set_fillchars_option((win_T *)from, ((win_T *)from)->w_p_fcs, TRUE,
6282 NULL, 0);
Bram Moolenaara4d158b2022-08-14 14:17:45 +01006283 redraw_later(UPD_NOT_VALID);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006284 break;
Gary Johnson53ba05b2021-07-26 22:19:10 +02006285 case PV_VE:
Gary Johnson51ad8502021-08-03 18:33:08 +02006286 clear_string_option(&((win_T *)from)->w_p_ve);
6287 ((win_T *)from)->w_ve_flags = 0;
Gary Johnson53ba05b2021-07-26 22:19:10 +02006288 break;
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006289 }
6290}
Bram Moolenaar113e1072019-01-20 15:30:40 +01006291#endif
Bram Moolenaar84e0f6c2013-05-06 03:52:55 +02006292
6293/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294 * Get pointer to option variable, depending on local or global scope.
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006295 * "scope" can be OPT_LOCAL, OPT_GLOBAL or a combination.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 */
6297 static char_u *
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006298get_varp_scope(struct vimoption *p, int scope)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299{
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006300 if ((scope & OPT_GLOBAL) && p->indir != PV_NONE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006301 {
6302 if (p->var == VAR_WIN)
6303 return (char_u *)GLOBAL_WO(get_varp(p));
6304 return p->var;
6305 }
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006306 if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006307 {
6308 switch ((int)p->indir)
6309 {
Bram Moolenaar9be7c042017-01-14 14:28:30 +01006310 case PV_FP: return (char_u *)&(curbuf->b_p_fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311#ifdef FEAT_QUICKFIX
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006312 case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
6313 case PV_GP: return (char_u *)&(curbuf->b_p_gp);
6314 case PV_MP: return (char_u *)&(curbuf->b_p_mp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315#endif
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006316 case PV_EP: return (char_u *)&(curbuf->b_p_ep);
6317 case PV_KP: return (char_u *)&(curbuf->b_p_kp);
6318 case PV_PATH: return (char_u *)&(curbuf->b_p_path);
Bram Moolenaara23ccb82006-02-27 00:08:02 +00006319 case PV_AR: return (char_u *)&(curbuf->b_p_ar);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006320 case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01006321 case PV_TC: return (char_u *)&(curbuf->b_p_tc);
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01006322 case PV_SISO: return (char_u *)&(curwin->w_p_siso);
6323 case PV_SO: return (char_u *)&(curwin->w_p_so);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006324#ifdef FEAT_FIND_ID
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006325 case PV_DEF: return (char_u *)&(curbuf->b_p_def);
6326 case PV_INC: return (char_u *)&(curbuf->b_p_inc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006327#endif
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006328 case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
6329 case PV_TSR: return (char_u *)&(curbuf->b_p_tsr);
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01006330#ifdef FEAT_COMPL_FUNC
6331 case PV_TSRFU: return (char_u *)&(curbuf->b_p_tsrfu);
6332#endif
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00006333#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
6334 case PV_BEXPR: return (char_u *)&(curbuf->b_p_bexpr);
6335#endif
Bram Moolenaar49771f42010-07-20 17:32:38 +02006336#if defined(FEAT_CRYPT)
6337 case PV_CM: return (char_u *)&(curbuf->b_p_cm);
6338#endif
Bram Moolenaaree857022019-11-09 23:26:40 +01006339#ifdef FEAT_LINEBREAK
6340 case PV_SBR: return (char_u *)&(curwin->w_p_sbr);
6341#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006342#ifdef FEAT_STL_OPT
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006343 case PV_STL: return (char_u *)&(curwin->w_p_stl);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006344#endif
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01006345 case PV_UL: return (char_u *)&(curbuf->b_p_ul);
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01006346 case PV_LW: return (char_u *)&(curbuf->b_p_lw);
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02006347 case PV_BKC: return (char_u *)&(curbuf->b_p_bkc);
Bram Moolenaar2c7292d2017-03-05 17:43:31 +01006348 case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
Gary Johnson53ba05b2021-07-26 22:19:10 +02006349 case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006350 case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
Gary Johnson51ad8502021-08-03 18:33:08 +02006351 case PV_VE: return (char_u *)&(curwin->w_p_ve);
Bram Moolenaareed9d462021-02-15 20:38:25 +01006352
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006354 return NULL; // "cannot happen"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006355 }
6356 return get_varp(p);
6357}
6358
6359/*
Bram Moolenaardac13472019-09-16 21:06:21 +02006360 * Get pointer to option variable at 'opt_idx', depending on local or global
6361 * scope.
6362 */
6363 char_u *
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006364get_option_varp_scope(int opt_idx, int scope)
Bram Moolenaardac13472019-09-16 21:06:21 +02006365{
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00006366 return get_varp_scope(&(options[opt_idx]), scope);
Bram Moolenaardac13472019-09-16 21:06:21 +02006367}
6368
6369/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006370 * Get pointer to option variable.
6371 */
6372 static char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01006373get_varp(struct vimoption *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006374{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006375 // hidden option, always return NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376 if (p->var == NULL)
6377 return NULL;
6378
6379 switch ((int)p->indir)
6380 {
6381 case PV_NONE: return p->var;
6382
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006383 // global option with local value: use local value if it's been set
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006384 case PV_EP: return *curbuf->b_p_ep != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006385 ? (char_u *)&curbuf->b_p_ep : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006386 case PV_KP: return *curbuf->b_p_kp != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006387 ? (char_u *)&curbuf->b_p_kp : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006388 case PV_PATH: return *curbuf->b_p_path != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006389 ? (char_u *)&(curbuf->b_p_path) : p->var;
Bram Moolenaara23ccb82006-02-27 00:08:02 +00006390 case PV_AR: return curbuf->b_p_ar >= 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006391 ? (char_u *)&(curbuf->b_p_ar) : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006392 case PV_TAGS: return *curbuf->b_p_tags != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006393 ? (char_u *)&(curbuf->b_p_tags) : p->var;
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01006394 case PV_TC: return *curbuf->b_p_tc != NUL
6395 ? (char_u *)&(curbuf->b_p_tc) : p->var;
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02006396 case PV_BKC: return *curbuf->b_p_bkc != NUL
6397 ? (char_u *)&(curbuf->b_p_bkc) : p->var;
Bram Moolenaar375e3392019-01-31 18:26:10 +01006398 case PV_SISO: return curwin->w_p_siso >= 0
6399 ? (char_u *)&(curwin->w_p_siso) : p->var;
6400 case PV_SO: return curwin->w_p_so >= 0
6401 ? (char_u *)&(curwin->w_p_so) : p->var;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006402#ifdef FEAT_FIND_ID
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006403 case PV_DEF: return *curbuf->b_p_def != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006404 ? (char_u *)&(curbuf->b_p_def) : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006405 case PV_INC: return *curbuf->b_p_inc != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006406 ? (char_u *)&(curbuf->b_p_inc) : p->var;
6407#endif
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006408 case PV_DICT: return *curbuf->b_p_dict != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006409 ? (char_u *)&(curbuf->b_p_dict) : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006410 case PV_TSR: return *curbuf->b_p_tsr != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006411 ? (char_u *)&(curbuf->b_p_tsr) : p->var;
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01006412#ifdef FEAT_COMPL_FUNC
6413 case PV_TSRFU: return *curbuf->b_p_tsrfu != NUL
6414 ? (char_u *)&(curbuf->b_p_tsrfu) : p->var;
6415#endif
Bram Moolenaar9be7c042017-01-14 14:28:30 +01006416 case PV_FP: return *curbuf->b_p_fp != NUL
6417 ? (char_u *)&(curbuf->b_p_fp) : p->var;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006418#ifdef FEAT_QUICKFIX
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006419 case PV_EFM: return *curbuf->b_p_efm != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006420 ? (char_u *)&(curbuf->b_p_efm) : p->var;
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006421 case PV_GP: return *curbuf->b_p_gp != NUL
6422 ? (char_u *)&(curbuf->b_p_gp) : p->var;
6423 case PV_MP: return *curbuf->b_p_mp != NUL
6424 ? (char_u *)&(curbuf->b_p_mp) : p->var;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006425#endif
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00006426#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
6427 case PV_BEXPR: return *curbuf->b_p_bexpr != NUL
6428 ? (char_u *)&(curbuf->b_p_bexpr) : p->var;
6429#endif
Bram Moolenaar49771f42010-07-20 17:32:38 +02006430#if defined(FEAT_CRYPT)
6431 case PV_CM: return *curbuf->b_p_cm != NUL
6432 ? (char_u *)&(curbuf->b_p_cm) : p->var;
6433#endif
Bram Moolenaaree857022019-11-09 23:26:40 +01006434#ifdef FEAT_LINEBREAK
6435 case PV_SBR: return *curwin->w_p_sbr != NUL
6436 ? (char_u *)&(curwin->w_p_sbr) : p->var;
6437#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006438#ifdef FEAT_STL_OPT
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006439 case PV_STL: return *curwin->w_p_stl != NUL
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006440 ? (char_u *)&(curwin->w_p_stl) : p->var;
6441#endif
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01006442 case PV_UL: return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
6443 ? (char_u *)&(curbuf->b_p_ul) : p->var;
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01006444 case PV_LW: return *curbuf->b_p_lw != NUL
6445 ? (char_u *)&(curbuf->b_p_lw) : p->var;
Bram Moolenaar2c7292d2017-03-05 17:43:31 +01006446 case PV_MENC: return *curbuf->b_p_menc != NUL
6447 ? (char_u *)&(curbuf->b_p_menc) : p->var;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448#ifdef FEAT_ARABIC
6449 case PV_ARAB: return (char_u *)&(curwin->w_p_arab);
6450#endif
6451 case PV_LIST: return (char_u *)&(curwin->w_p_list);
Bram Moolenaareed9d462021-02-15 20:38:25 +01006452 case PV_LCS: return *curwin->w_p_lcs != NUL
6453 ? (char_u *)&(curwin->w_p_lcs) : p->var;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006454 case PV_FCS: return *curwin->w_p_fcs != NUL
6455 ? (char_u *)&(curwin->w_p_fcs) : p->var;
Gary Johnson51ad8502021-08-03 18:33:08 +02006456 case PV_VE: return *curwin->w_p_ve != NUL
6457 ? (char_u *)&(curwin->w_p_ve) : p->var;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006458#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00006459 case PV_SPELL: return (char_u *)&(curwin->w_p_spell);
6460#endif
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006461#ifdef FEAT_SYN_HL
6462 case PV_CUC: return (char_u *)&(curwin->w_p_cuc);
6463 case PV_CUL: return (char_u *)&(curwin->w_p_cul);
Bram Moolenaar410e98a2019-09-09 22:05:49 +02006464 case PV_CULOPT: return (char_u *)&(curwin->w_p_culopt);
Bram Moolenaar1a384422010-07-14 19:53:30 +02006465 case PV_CC: return (char_u *)&(curwin->w_p_cc);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006466#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006467#ifdef FEAT_DIFF
6468 case PV_DIFF: return (char_u *)&(curwin->w_p_diff);
6469#endif
6470#ifdef FEAT_FOLDING
6471 case PV_FDC: return (char_u *)&(curwin->w_p_fdc);
6472 case PV_FEN: return (char_u *)&(curwin->w_p_fen);
6473 case PV_FDI: return (char_u *)&(curwin->w_p_fdi);
6474 case PV_FDL: return (char_u *)&(curwin->w_p_fdl);
6475 case PV_FDM: return (char_u *)&(curwin->w_p_fdm);
6476 case PV_FML: return (char_u *)&(curwin->w_p_fml);
6477 case PV_FDN: return (char_u *)&(curwin->w_p_fdn);
6478# ifdef FEAT_EVAL
6479 case PV_FDE: return (char_u *)&(curwin->w_p_fde);
6480 case PV_FDT: return (char_u *)&(curwin->w_p_fdt);
6481# endif
6482 case PV_FMR: return (char_u *)&(curwin->w_p_fmr);
6483#endif
6484 case PV_NU: return (char_u *)&(curwin->w_p_nu);
Bram Moolenaar64486672010-05-16 15:46:46 +02006485 case PV_RNU: return (char_u *)&(curwin->w_p_rnu);
Bram Moolenaar592e0a22004-07-03 16:05:59 +00006486#ifdef FEAT_LINEBREAK
6487 case PV_NUW: return (char_u *)&(curwin->w_p_nuw);
6488#endif
Colin Kennedy21570352024-03-03 16:16:47 +01006489 case PV_WFB: return (char_u *)&(curwin->w_p_wfb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006490 case PV_WFH: return (char_u *)&(curwin->w_p_wfh);
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00006491 case PV_WFW: return (char_u *)&(curwin->w_p_wfw);
Bram Moolenaar4033c552017-09-16 20:54:51 +02006492#if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006493 case PV_PVW: return (char_u *)&(curwin->w_p_pvw);
6494#endif
6495#ifdef FEAT_RIGHTLEFT
6496 case PV_RL: return (char_u *)&(curwin->w_p_rl);
6497 case PV_RLC: return (char_u *)&(curwin->w_p_rlc);
6498#endif
6499 case PV_SCROLL: return (char_u *)&(curwin->w_p_scr);
Bram Moolenaarf6196f42022-10-02 21:29:55 +01006500 case PV_SMS: return (char_u *)&(curwin->w_p_sms);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006501 case PV_WRAP: return (char_u *)&(curwin->w_p_wrap);
6502#ifdef FEAT_LINEBREAK
6503 case PV_LBR: return (char_u *)&(curwin->w_p_lbr);
Bram Moolenaar597a4222014-06-25 14:39:50 +02006504 case PV_BRI: return (char_u *)&(curwin->w_p_bri);
6505 case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006506#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006507 case PV_WCR: return (char_u *)&(curwin->w_p_wcr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006508 case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
Bram Moolenaar860cae12010-06-05 23:22:07 +02006509 case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
Bram Moolenaar860cae12010-06-05 23:22:07 +02006510#ifdef FEAT_CONCEAL
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006511 case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
6512 case PV_COLE: return (char_u *)&(curwin->w_p_cole);
6513#endif
6514#ifdef FEAT_TERMINAL
Bram Moolenaar6d150f72018-04-21 20:03:20 +02006515 case PV_TWK: return (char_u *)&(curwin->w_p_twk);
6516 case PV_TWS: return (char_u *)&(curwin->w_p_tws);
6517 case PV_TWSL: return (char_u *)&(curbuf->b_p_twsl);
Bram Moolenaar860cae12010-06-05 23:22:07 +02006518#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006519
6520 case PV_AI: return (char_u *)&(curbuf->b_p_ai);
6521 case PV_BIN: return (char_u *)&(curbuf->b_p_bin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006522 case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006523 case PV_BH: return (char_u *)&(curbuf->b_p_bh);
6524 case PV_BT: return (char_u *)&(curbuf->b_p_bt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525 case PV_BL: return (char_u *)&(curbuf->b_p_bl);
6526 case PV_CI: return (char_u *)&(curbuf->b_p_ci);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006527 case PV_CIN: return (char_u *)&(curbuf->b_p_cin);
6528 case PV_CINK: return (char_u *)&(curbuf->b_p_cink);
6529 case PV_CINO: return (char_u *)&(curbuf->b_p_cino);
Tom Praschan3506cf32022-04-07 12:39:08 +01006530 case PV_CINSD: return (char_u *)&(curbuf->b_p_cinsd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006531 case PV_CINW: return (char_u *)&(curbuf->b_p_cinw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006532 case PV_COM: return (char_u *)&(curbuf->b_p_com);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533#ifdef FEAT_FOLDING
6534 case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
6535#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006536 case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
Bram Moolenaare2c453d2019-08-21 14:37:09 +02006537#ifdef BACKSLASH_IN_FILENAME
Bram Moolenaarac3150d2019-07-28 16:36:39 +02006538 case PV_CSL: return (char_u *)&(curbuf->b_p_csl);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006539#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006540#ifdef FEAT_COMPL_FUNC
6541 case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
Bram Moolenaare344bea2005-09-01 20:46:49 +00006542 case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006543#endif
Bram Moolenaar45e18cb2019-04-28 18:05:35 +02006544#ifdef FEAT_EVAL
6545 case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
6546#endif
Bram Moolenaar3f68a412022-10-28 17:04:21 +01006547 case PV_EOF: return (char_u *)&(curbuf->b_p_eof);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006548 case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
Bram Moolenaar34d72d42015-07-17 14:18:08 +02006549 case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006550 case PV_ET: return (char_u *)&(curbuf->b_p_et);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006551 case PV_FENC: return (char_u *)&(curbuf->b_p_fenc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006552 case PV_FF: return (char_u *)&(curbuf->b_p_ff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006553 case PV_FT: return (char_u *)&(curbuf->b_p_ft);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006554 case PV_FO: return (char_u *)&(curbuf->b_p_fo);
Bram Moolenaar86b68352004-12-27 21:59:20 +00006555 case PV_FLP: return (char_u *)&(curbuf->b_p_flp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006556 case PV_IMI: return (char_u *)&(curbuf->b_p_iminsert);
6557 case PV_IMS: return (char_u *)&(curbuf->b_p_imsearch);
6558 case PV_INF: return (char_u *)&(curbuf->b_p_inf);
6559 case PV_ISK: return (char_u *)&(curbuf->b_p_isk);
6560#ifdef FEAT_FIND_ID
6561# ifdef FEAT_EVAL
6562 case PV_INEX: return (char_u *)&(curbuf->b_p_inex);
6563# endif
6564#endif
Bram Moolenaar8e145b82022-05-21 20:17:31 +01006565#if defined(FEAT_EVAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006566 case PV_INDE: return (char_u *)&(curbuf->b_p_inde);
6567 case PV_INDK: return (char_u *)&(curbuf->b_p_indk);
6568#endif
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +00006569#ifdef FEAT_EVAL
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006570 case PV_FEX: return (char_u *)&(curbuf->b_p_fex);
6571#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006572#ifdef FEAT_CRYPT
6573 case PV_KEY: return (char_u *)&(curbuf->b_p_key);
6574#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006575 case PV_LISP: return (char_u *)&(curbuf->b_p_lisp);
Bram Moolenaar49846fb2022-10-15 16:05:33 +01006576 case PV_LOP: return (char_u *)&(curbuf->b_p_lop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577 case PV_ML: return (char_u *)&(curbuf->b_p_ml);
6578 case PV_MPS: return (char_u *)&(curbuf->b_p_mps);
6579 case PV_MA: return (char_u *)&(curbuf->b_p_ma);
6580 case PV_MOD: return (char_u *)&(curbuf->b_changed);
6581 case PV_NF: return (char_u *)&(curbuf->b_p_nf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 case PV_PI: return (char_u *)&(curbuf->b_p_pi);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006583 case PV_QE: return (char_u *)&(curbuf->b_p_qe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006584 case PV_RO: return (char_u *)&(curbuf->b_p_ro);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006585 case PV_SI: return (char_u *)&(curbuf->b_p_si);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586 case PV_SN: return (char_u *)&(curbuf->b_p_sn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006587 case PV_STS: return (char_u *)&(curbuf->b_p_sts);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006588 case PV_SUA: return (char_u *)&(curbuf->b_p_sua);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006589 case PV_SWF: return (char_u *)&(curbuf->b_p_swf);
6590#ifdef FEAT_SYN_HL
Bram Moolenaar3b56eb32005-07-11 22:40:32 +00006591 case PV_SMC: return (char_u *)&(curbuf->b_p_smc);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006592 case PV_SYN: return (char_u *)&(curbuf->b_p_syn);
6593#endif
6594#ifdef FEAT_SPELL
Bram Moolenaar860cae12010-06-05 23:22:07 +02006595 case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc);
6596 case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf);
6597 case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl);
Bram Moolenaar362b44b2020-06-10 21:47:00 +02006598 case PV_SPO: return (char_u *)&(curwin->w_s->b_p_spo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599#endif
6600 case PV_SW: return (char_u *)&(curbuf->b_p_sw);
6601 case PV_TS: return (char_u *)&(curbuf->b_p_ts);
6602 case PV_TW: return (char_u *)&(curbuf->b_p_tw);
6603 case PV_TX: return (char_u *)&(curbuf->b_p_tx);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02006604#ifdef FEAT_PERSISTENT_UNDO
6605 case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
6606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006607 case PV_WM: return (char_u *)&(curbuf->b_p_wm);
6608#ifdef FEAT_KEYMAP
6609 case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
6610#endif
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02006611#ifdef FEAT_SIGNS
6612 case PV_SCL: return (char_u *)&(curwin->w_p_scl);
6613#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006614#ifdef FEAT_VARTABS
6615 case PV_VSTS: return (char_u *)&(curbuf->b_p_vsts);
6616 case PV_VTS: return (char_u *)&(curbuf->b_p_vts);
6617#endif
RestorerZ68ebcee2023-05-31 17:12:14 +01006618 default: iemsg(e_get_varp_error);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006619 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006620 // always return a valid pointer to avoid a crash!
Bram Moolenaar071d4272004-06-13 20:20:40 +00006621 return (char_u *)&(curbuf->b_p_wm);
6622}
6623
6624/*
Bram Moolenaardac13472019-09-16 21:06:21 +02006625 * Return a pointer to the variable for option at 'opt_idx'
6626 */
6627 char_u *
6628get_option_var(int opt_idx)
6629{
6630 return options[opt_idx].var;
6631}
6632
Dominique Pelle748b3082022-01-08 12:41:16 +00006633#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaardac13472019-09-16 21:06:21 +02006634/*
6635 * Return the full name of the option at 'opt_idx'
6636 */
6637 char_u *
6638get_option_fullname(int opt_idx)
6639{
6640 return (char_u *)options[opt_idx].fullname;
6641}
Dominique Pelle748b3082022-01-08 12:41:16 +00006642#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02006643
6644/*
Yegappan Lakshmananaf936912023-02-20 12:16:39 +00006645 * Return the did_set callback function for the option at 'opt_idx'
6646 */
6647 opt_did_set_cb_T
6648get_option_did_set_cb(int opt_idx)
6649{
6650 return options[opt_idx].opt_did_set_cb;
6651}
6652
6653/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006654 * Get the value of 'equalprg', either the buffer-local one or the global one.
6655 */
6656 char_u *
Bram Moolenaar9b578142016-01-30 19:39:49 +01006657get_equalprg(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006658{
6659 if (*curbuf->b_p_ep == NUL)
6660 return p_ep;
6661 return curbuf->b_p_ep;
6662}
6663
Bram Moolenaar071d4272004-06-13 20:20:40 +00006664/*
6665 * Copy options from one window to another.
6666 * Used when splitting a window.
6667 */
6668 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006669win_copy_options(win_T *wp_from, win_T *wp_to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006670{
6671 copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt);
6672 copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt);
Bram Moolenaar010ee962019-09-25 20:37:36 +02006673 after_copy_winopt(wp_to);
6674}
6675
6676/*
6677 * After copying window options: update variables depending on options.
6678 */
6679 void
Sean Dewar0f7ff852022-02-12 11:51:25 +00006680after_copy_winopt(win_T *wp)
Bram Moolenaar010ee962019-09-25 20:37:36 +02006681{
6682#ifdef FEAT_LINEBREAK
6683 briopt_check(wp);
Bram Moolenaar285ed7e2014-08-24 21:39:49 +02006684#endif
Bram Moolenaar017ba072019-09-14 21:01:23 +02006685#ifdef FEAT_SYN_HL
Bram Moolenaar010ee962019-09-25 20:37:36 +02006686 fill_culopt_flags(NULL, wp);
6687 check_colorcolumn(wp);
Bram Moolenaar017ba072019-09-14 21:01:23 +02006688#endif
zeertzjq6a8d2e12024-01-17 20:54:49 +01006689 set_listchars_option(wp, wp->w_p_lcs, TRUE, NULL, 0);
6690 set_fillchars_option(wp, wp->w_p_fcs, TRUE, NULL, 0);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006691}
6692
6693 static char_u *
6694copy_option_val(char_u *val)
6695{
6696 if (val == empty_option)
6697 return empty_option; // no need to allocate memory
6698 return vim_strsave(val);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006699}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006700
6701/*
6702 * Copy the options from one winopt_T to another.
6703 * Doesn't free the old option values in "to", use clear_winopt() for that.
6704 * The 'scroll' option is not copied, because it depends on the window height.
6705 * The 'previewwindow' option is reset, there can be only one preview window.
6706 */
6707 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006708copy_winopt(winopt_T *from, winopt_T *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006709{
6710#ifdef FEAT_ARABIC
6711 to->wo_arab = from->wo_arab;
6712#endif
6713 to->wo_list = from->wo_list;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006714 to->wo_lcs = copy_option_val(from->wo_lcs);
6715 to->wo_fcs = copy_option_val(from->wo_fcs);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006716 to->wo_nu = from->wo_nu;
Bram Moolenaar64486672010-05-16 15:46:46 +02006717 to->wo_rnu = from->wo_rnu;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006718 to->wo_ve = copy_option_val(from->wo_ve);
Gary Johnson51ad8502021-08-03 18:33:08 +02006719 to->wo_ve_flags = from->wo_ve_flags;
Bram Moolenaar592e0a22004-07-03 16:05:59 +00006720#ifdef FEAT_LINEBREAK
6721 to->wo_nuw = from->wo_nuw;
6722#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006723#ifdef FEAT_RIGHTLEFT
6724 to->wo_rl = from->wo_rl;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006725 to->wo_rlc = copy_option_val(from->wo_rlc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006726#endif
Bram Moolenaaree857022019-11-09 23:26:40 +01006727#ifdef FEAT_LINEBREAK
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006728 to->wo_sbr = copy_option_val(from->wo_sbr);
Bram Moolenaaree857022019-11-09 23:26:40 +01006729#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006730#ifdef FEAT_STL_OPT
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006731 to->wo_stl = copy_option_val(from->wo_stl);
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006732#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006733 to->wo_wrap = from->wo_wrap;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006734#ifdef FEAT_DIFF
6735 to->wo_wrap_save = from->wo_wrap_save;
6736#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006737#ifdef FEAT_LINEBREAK
6738 to->wo_lbr = from->wo_lbr;
Bram Moolenaar597a4222014-06-25 14:39:50 +02006739 to->wo_bri = from->wo_bri;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006740 to->wo_briopt = copy_option_val(from->wo_briopt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006741#endif
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006742 to->wo_wcr = copy_option_val(from->wo_wcr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006743 to->wo_scb = from->wo_scb;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006744 to->wo_scb_save = from->wo_scb_save;
Bram Moolenaarb1fd26d2022-10-03 11:23:02 +01006745 to->wo_sms = from->wo_sms;
Bram Moolenaar4161dcc2010-12-02 15:33:21 +01006746 to->wo_crb = from->wo_crb;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006747 to->wo_crb_save = from->wo_crb_save;
Christian Brabandt4a8eb6e2023-08-13 19:43:42 +02006748 to->wo_siso = from->wo_siso;
6749 to->wo_so = from->wo_so;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006750#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00006751 to->wo_spell = from->wo_spell;
6752#endif
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006753#ifdef FEAT_SYN_HL
6754 to->wo_cuc = from->wo_cuc;
6755 to->wo_cul = from->wo_cul;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006756 to->wo_culopt = copy_option_val(from->wo_culopt);
6757 to->wo_cc = copy_option_val(from->wo_cc);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00006758#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006759#ifdef FEAT_DIFF
6760 to->wo_diff = from->wo_diff;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006761 to->wo_diff_saved = from->wo_diff_saved;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006762#endif
Bram Moolenaarf5963f72010-07-23 22:10:27 +02006763#ifdef FEAT_CONCEAL
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006764 to->wo_cocu = copy_option_val(from->wo_cocu);
Bram Moolenaard497a302010-07-23 22:27:03 +02006765 to->wo_cole = from->wo_cole;
Bram Moolenaarf5963f72010-07-23 22:10:27 +02006766#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006767#ifdef FEAT_TERMINAL
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006768 to->wo_twk = copy_option_val(from->wo_twk);
6769 to->wo_tws = copy_option_val(from->wo_tws);
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006770#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006771#ifdef FEAT_FOLDING
6772 to->wo_fdc = from->wo_fdc;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006773 to->wo_fdc_save = from->wo_fdc_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006774 to->wo_fen = from->wo_fen;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006775 to->wo_fen_save = from->wo_fen_save;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006776 to->wo_fdi = copy_option_val(from->wo_fdi);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006777 to->wo_fml = from->wo_fml;
6778 to->wo_fdl = from->wo_fdl;
Bram Moolenaara87aa802013-07-03 15:47:03 +02006779 to->wo_fdl_save = from->wo_fdl_save;
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006780 to->wo_fdm = copy_option_val(from->wo_fdm);
Bram Moolenaara87aa802013-07-03 15:47:03 +02006781 to->wo_fdm_save = from->wo_diff_saved
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006782 ? vim_strsave(from->wo_fdm_save) : empty_option;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006783 to->wo_fdn = from->wo_fdn;
6784# ifdef FEAT_EVAL
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006785 to->wo_fde = copy_option_val(from->wo_fde);
6786 to->wo_fdt = copy_option_val(from->wo_fdt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006787# endif
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006788 to->wo_fmr = copy_option_val(from->wo_fmr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006789#endif
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02006790#ifdef FEAT_SIGNS
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006791 to->wo_scl = copy_option_val(from->wo_scl);
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02006792#endif
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006793
6794#ifdef FEAT_EVAL
6795 // Copy the script context so that we know where the value was last set.
6796 mch_memmove(to->wo_script_ctx, from->wo_script_ctx,
6797 sizeof(to->wo_script_ctx));
6798#endif
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006799 check_winopt(to); // don't want NULL pointers
Bram Moolenaar071d4272004-06-13 20:20:40 +00006800}
6801
6802/*
6803 * Check string options in a window for a NULL value.
6804 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +02006805 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006806check_win_options(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006807{
6808 check_winopt(&win->w_onebuf_opt);
6809 check_winopt(&win->w_allbuf_opt);
6810}
6811
6812/*
6813 * Check for NULL pointers in a winopt_T and replace them with empty_option.
6814 */
Bram Moolenaar8dc907d2014-06-25 14:44:10 +02006815 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006816check_winopt(winopt_T *wop UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006817{
6818#ifdef FEAT_FOLDING
6819 check_string_option(&wop->wo_fdi);
6820 check_string_option(&wop->wo_fdm);
Bram Moolenaara87aa802013-07-03 15:47:03 +02006821 check_string_option(&wop->wo_fdm_save);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006822# ifdef FEAT_EVAL
6823 check_string_option(&wop->wo_fde);
6824 check_string_option(&wop->wo_fdt);
6825# endif
6826 check_string_option(&wop->wo_fmr);
6827#endif
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02006828#ifdef FEAT_SIGNS
6829 check_string_option(&wop->wo_scl);
6830#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006831#ifdef FEAT_RIGHTLEFT
6832 check_string_option(&wop->wo_rlc);
6833#endif
Bram Moolenaaree857022019-11-09 23:26:40 +01006834#ifdef FEAT_LINEBREAK
6835 check_string_option(&wop->wo_sbr);
6836#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006837#ifdef FEAT_STL_OPT
6838 check_string_option(&wop->wo_stl);
6839#endif
Bram Moolenaar1a384422010-07-14 19:53:30 +02006840#ifdef FEAT_SYN_HL
Bram Moolenaar410e98a2019-09-09 22:05:49 +02006841 check_string_option(&wop->wo_culopt);
Bram Moolenaar1a384422010-07-14 19:53:30 +02006842 check_string_option(&wop->wo_cc);
6843#endif
Bram Moolenaarf5963f72010-07-23 22:10:27 +02006844#ifdef FEAT_CONCEAL
6845 check_string_option(&wop->wo_cocu);
6846#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006847#ifdef FEAT_TERMINAL
Bram Moolenaar6d150f72018-04-21 20:03:20 +02006848 check_string_option(&wop->wo_twk);
6849 check_string_option(&wop->wo_tws);
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006850#endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02006851#ifdef FEAT_LINEBREAK
6852 check_string_option(&wop->wo_briopt);
6853#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006854 check_string_option(&wop->wo_wcr);
Bram Moolenaareed9d462021-02-15 20:38:25 +01006855 check_string_option(&wop->wo_lcs);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006856 check_string_option(&wop->wo_fcs);
Gary Johnson51ad8502021-08-03 18:33:08 +02006857 check_string_option(&wop->wo_ve);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006858}
6859
6860/*
6861 * Free the allocated memory inside a winopt_T.
6862 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006863 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006864clear_winopt(winopt_T *wop UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006865{
6866#ifdef FEAT_FOLDING
6867 clear_string_option(&wop->wo_fdi);
6868 clear_string_option(&wop->wo_fdm);
Bram Moolenaara87aa802013-07-03 15:47:03 +02006869 clear_string_option(&wop->wo_fdm_save);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006870# ifdef FEAT_EVAL
6871 clear_string_option(&wop->wo_fde);
6872 clear_string_option(&wop->wo_fdt);
6873# endif
6874 clear_string_option(&wop->wo_fmr);
6875#endif
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02006876#ifdef FEAT_SIGNS
6877 clear_string_option(&wop->wo_scl);
6878#endif
Bram Moolenaar597a4222014-06-25 14:39:50 +02006879#ifdef FEAT_LINEBREAK
6880 clear_string_option(&wop->wo_briopt);
6881#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +02006882 clear_string_option(&wop->wo_wcr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006883#ifdef FEAT_RIGHTLEFT
6884 clear_string_option(&wop->wo_rlc);
6885#endif
Bram Moolenaaree857022019-11-09 23:26:40 +01006886#ifdef FEAT_LINEBREAK
6887 clear_string_option(&wop->wo_sbr);
6888#endif
Bram Moolenaarb5bf5b82004-12-24 14:35:23 +00006889#ifdef FEAT_STL_OPT
6890 clear_string_option(&wop->wo_stl);
6891#endif
Bram Moolenaar1a384422010-07-14 19:53:30 +02006892#ifdef FEAT_SYN_HL
Bram Moolenaar410e98a2019-09-09 22:05:49 +02006893 clear_string_option(&wop->wo_culopt);
Bram Moolenaar1a384422010-07-14 19:53:30 +02006894 clear_string_option(&wop->wo_cc);
6895#endif
Bram Moolenaarf5963f72010-07-23 22:10:27 +02006896#ifdef FEAT_CONCEAL
6897 clear_string_option(&wop->wo_cocu);
6898#endif
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006899#ifdef FEAT_TERMINAL
Bram Moolenaar6d150f72018-04-21 20:03:20 +02006900 clear_string_option(&wop->wo_twk);
6901 clear_string_option(&wop->wo_tws);
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006902#endif
Bram Moolenaareed9d462021-02-15 20:38:25 +01006903 clear_string_option(&wop->wo_lcs);
Bram Moolenaar96ba25a2022-07-04 17:34:33 +01006904 clear_string_option(&wop->wo_fcs);
Gary Johnson51ad8502021-08-03 18:33:08 +02006905 clear_string_option(&wop->wo_ve);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906}
6907
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006908#ifdef FEAT_EVAL
6909// Index into the options table for a buffer-local option enum.
6910static int buf_opt_idx[BV_COUNT];
6911# define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].script_ctx
6912
6913/*
6914 * Initialize buf_opt_idx[] if not done already.
6915 */
6916 static void
6917init_buf_opt_idx(void)
6918{
6919 static int did_init_buf_opt_idx = FALSE;
6920 int i;
6921
6922 if (did_init_buf_opt_idx)
6923 return;
6924 did_init_buf_opt_idx = TRUE;
6925 for (i = 0; !istermoption_idx(i); i++)
6926 if (options[i].indir & PV_BUF)
6927 buf_opt_idx[options[i].indir & PV_MASK] = i;
6928}
6929#else
6930# define COPY_OPT_SCTX(buf, bv)
6931#endif
6932
Bram Moolenaar071d4272004-06-13 20:20:40 +00006933/*
6934 * Copy global option values to local options for one buffer.
6935 * Used when creating a new buffer and sometimes when entering a buffer.
6936 * flags:
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006937 * BCO_ENTER We will enter the buffer "buf".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006938 * BCO_ALWAYS Always copy the options, but only set b_p_initialized when
6939 * appropriate.
6940 * BCO_NOHELP Don't copy the values to a help buffer.
6941 */
6942 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01006943buf_copy_options(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006944{
6945 int should_copy = TRUE;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006946 char_u *save_p_isk = NULL; // init for GCC
Bram Moolenaar071d4272004-06-13 20:20:40 +00006947 int dont_do_help;
6948 int did_isk = FALSE;
6949
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00006950 // Skip this when the option defaults have not been set yet. Happens when
6951 // main() allocates the first buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006952 if (p_cpo != NULL)
6953 {
6954 /*
6955 * Always copy when entering and 'cpo' contains 'S'.
6956 * Don't copy when already initialized.
6957 * Don't copy when 'cpo' contains 's' and not entering.
6958 * 'S' BCO_ENTER initialized 's' should_copy
6959 * yes yes X X TRUE
6960 * yes no yes X FALSE
6961 * no X yes X FALSE
6962 * X no no yes FALSE
6963 * X no no no TRUE
6964 * no yes no X TRUE
6965 */
6966 if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER))
6967 && (buf->b_p_initialized
6968 || (!(flags & BCO_ENTER)
6969 && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
6970 should_copy = FALSE;
6971
6972 if (should_copy || (flags & BCO_ALWAYS))
6973 {
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006974#ifdef FEAT_EVAL
Bram Moolenaara80faa82020-04-12 19:37:17 +02006975 CLEAR_FIELD(buf->b_p_script_ctx);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006976 init_buf_opt_idx();
6977#endif
6978 // Don't copy the options specific to a help buffer when
6979 // BCO_NOHELP is given or the options were initialized already
6980 // (jumping back to a help file with CTRL-T or CTRL-O)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006981 dont_do_help = ((flags & BCO_NOHELP) && buf->b_help)
6982 || buf->b_p_initialized;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02006983 if (dont_do_help) // don't free b_p_isk
Bram Moolenaar071d4272004-06-13 20:20:40 +00006984 {
6985 save_p_isk = buf->b_p_isk;
6986 buf->b_p_isk = NULL;
6987 }
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00006988 // Always free the allocated strings. If not already initialized,
6989 // reset 'readonly' and copy 'fileformat'.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006990 if (!buf->b_p_initialized)
6991 {
6992 free_buf_options(buf, TRUE);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01006993 buf->b_p_ro = FALSE; // don't copy readonly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006994 buf->b_p_tx = p_tx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006995 buf->b_p_fenc = vim_strsave(p_fenc);
Bram Moolenaare8ef3a02016-10-12 17:45:29 +02006996 switch (*p_ffs)
6997 {
6998 case 'm':
6999 buf->b_p_ff = vim_strsave((char_u *)FF_MAC); break;
7000 case 'd':
7001 buf->b_p_ff = vim_strsave((char_u *)FF_DOS); break;
7002 case 'u':
7003 buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); break;
7004 default:
7005 buf->b_p_ff = vim_strsave(p_ff);
7006 }
7007 if (buf->b_p_ff != NULL)
7008 buf->b_start_ffc = *buf->b_p_ff;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007009 buf->b_p_bh = empty_option;
7010 buf->b_p_bt = empty_option;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007011 }
7012 else
7013 free_buf_options(buf, FALSE);
7014
7015 buf->b_p_ai = p_ai;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007016 COPY_OPT_SCTX(buf, BV_AI);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007017 buf->b_p_ai_nopaste = p_ai_nopaste;
7018 buf->b_p_sw = p_sw;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007019 COPY_OPT_SCTX(buf, BV_SW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 buf->b_p_tw = p_tw;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007021 COPY_OPT_SCTX(buf, BV_TW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007022 buf->b_p_tw_nopaste = p_tw_nopaste;
7023 buf->b_p_tw_nobin = p_tw_nobin;
7024 buf->b_p_wm = p_wm;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007025 COPY_OPT_SCTX(buf, BV_WM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007026 buf->b_p_wm_nopaste = p_wm_nopaste;
7027 buf->b_p_wm_nobin = p_wm_nobin;
7028 buf->b_p_bin = p_bin;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007029 COPY_OPT_SCTX(buf, BV_BIN);
Bram Moolenaare8bb2552005-07-08 22:26:47 +00007030 buf->b_p_bomb = p_bomb;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007031 COPY_OPT_SCTX(buf, BV_BOMB);
Bram Moolenaarb388be02015-07-22 22:19:38 +02007032 buf->b_p_fixeol = p_fixeol;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007033 COPY_OPT_SCTX(buf, BV_FIXEOL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034 buf->b_p_et = p_et;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007035 COPY_OPT_SCTX(buf, BV_ET);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007036 buf->b_p_et_nobin = p_et_nobin;
Bram Moolenaar54f018c2015-09-15 17:30:40 +02007037 buf->b_p_et_nopaste = p_et_nopaste;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038 buf->b_p_ml = p_ml;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007039 COPY_OPT_SCTX(buf, BV_ML);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007040 buf->b_p_ml_nobin = p_ml_nobin;
7041 buf->b_p_inf = p_inf;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007042 COPY_OPT_SCTX(buf, BV_INF);
Bram Moolenaare1004402020-10-24 20:49:43 +02007043 if (cmdmod.cmod_flags & CMOD_NOSWAPFILE)
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007044 buf->b_p_swf = FALSE;
7045 else
7046 {
7047 buf->b_p_swf = p_swf;
Bram Moolenaar62068772021-12-14 09:01:38 +00007048 COPY_OPT_SCTX(buf, BV_SWF);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007049 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007050 buf->b_p_cpt = vim_strsave(p_cpt);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007051 COPY_OPT_SCTX(buf, BV_CPT);
Bram Moolenaare2c453d2019-08-21 14:37:09 +02007052#ifdef BACKSLASH_IN_FILENAME
Bram Moolenaarac3150d2019-07-28 16:36:39 +02007053 buf->b_p_csl = vim_strsave(p_csl);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007054 COPY_OPT_SCTX(buf, BV_CSL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007056#ifdef FEAT_COMPL_FUNC
7057 buf->b_p_cfu = vim_strsave(p_cfu);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007058 COPY_OPT_SCTX(buf, BV_CFU);
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00007059 set_buflocal_cfu_callback(buf);
Bram Moolenaare344bea2005-09-01 20:46:49 +00007060 buf->b_p_ofu = vim_strsave(p_ofu);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007061 COPY_OPT_SCTX(buf, BV_OFU);
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00007062 set_buflocal_ofu_callback(buf);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007063#endif
Bram Moolenaar45e18cb2019-04-28 18:05:35 +02007064#ifdef FEAT_EVAL
7065 buf->b_p_tfu = vim_strsave(p_tfu);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007066 COPY_OPT_SCTX(buf, BV_TFU);
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00007067 set_buflocal_tfu_callback(buf);
Bram Moolenaar45e18cb2019-04-28 18:05:35 +02007068#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069 buf->b_p_sts = p_sts;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007070 COPY_OPT_SCTX(buf, BV_STS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007071 buf->b_p_sts_nopaste = p_sts_nopaste;
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007072#ifdef FEAT_VARTABS
7073 buf->b_p_vsts = vim_strsave(p_vsts);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007074 COPY_OPT_SCTX(buf, BV_VSTS);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007075 if (p_vsts && p_vsts != empty_option)
Bram Moolenaarb7081e12021-09-04 18:47:28 +02007076 (void)tabstop_set(p_vsts, &buf->b_p_vsts_array);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007077 else
Bram Moolenaar652dee42022-01-28 20:47:49 +00007078 buf->b_p_vsts_array = NULL;
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007079 buf->b_p_vsts_nopaste = p_vsts_nopaste
7080 ? vim_strsave(p_vsts_nopaste) : NULL;
7081#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007082 buf->b_p_sn = p_sn;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007083 COPY_OPT_SCTX(buf, BV_SN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007084 buf->b_p_com = vim_strsave(p_com);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007085 COPY_OPT_SCTX(buf, BV_COM);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007086#ifdef FEAT_FOLDING
7087 buf->b_p_cms = vim_strsave(p_cms);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007088 COPY_OPT_SCTX(buf, BV_CMS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089#endif
7090 buf->b_p_fo = vim_strsave(p_fo);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007091 COPY_OPT_SCTX(buf, BV_FO);
Bram Moolenaar86b68352004-12-27 21:59:20 +00007092 buf->b_p_flp = vim_strsave(p_flp);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007093 COPY_OPT_SCTX(buf, BV_FLP);
Bram Moolenaar473952e2019-09-28 16:30:04 +02007094 // NOTE: Valgrind may report a bogus memory leak for 'nrformats'
7095 // when it is set to 8 bytes in defaults.vim.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007096 buf->b_p_nf = vim_strsave(p_nf);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007097 COPY_OPT_SCTX(buf, BV_NF);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007098 buf->b_p_mps = vim_strsave(p_mps);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007099 COPY_OPT_SCTX(buf, BV_MPS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007100 buf->b_p_si = p_si;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007101 COPY_OPT_SCTX(buf, BV_SI);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007102 buf->b_p_ci = p_ci;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007103 COPY_OPT_SCTX(buf, BV_CI);
Bram Moolenaar8e145b82022-05-21 20:17:31 +01007104
Bram Moolenaar071d4272004-06-13 20:20:40 +00007105 buf->b_p_cin = p_cin;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007106 COPY_OPT_SCTX(buf, BV_CIN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007107 buf->b_p_cink = vim_strsave(p_cink);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007108 COPY_OPT_SCTX(buf, BV_CINK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109 buf->b_p_cino = vim_strsave(p_cino);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007110 COPY_OPT_SCTX(buf, BV_CINO);
Tom Praschan3506cf32022-04-07 12:39:08 +01007111 buf->b_p_cinsd = vim_strsave(p_cinsd);
7112 COPY_OPT_SCTX(buf, BV_CINSD);
Bram Moolenaar49846fb2022-10-15 16:05:33 +01007113 buf->b_p_lop = vim_strsave(p_lop);
7114 COPY_OPT_SCTX(buf, BV_LOP);
Bram Moolenaar8e145b82022-05-21 20:17:31 +01007115
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007116 // Don't copy 'filetype', it must be detected
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117 buf->b_p_ft = empty_option;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007118 buf->b_p_pi = p_pi;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007119 COPY_OPT_SCTX(buf, BV_PI);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120 buf->b_p_cinw = vim_strsave(p_cinw);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007121 COPY_OPT_SCTX(buf, BV_CINW);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007122 buf->b_p_lisp = p_lisp;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007123 COPY_OPT_SCTX(buf, BV_LISP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124#ifdef FEAT_SYN_HL
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007125 // Don't copy 'syntax', it must be set
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 buf->b_p_syn = empty_option;
Bram Moolenaar3b56eb32005-07-11 22:40:32 +00007127 buf->b_p_smc = p_smc;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007128 COPY_OPT_SCTX(buf, BV_SMC);
Bram Moolenaarb8060fe2016-01-19 22:29:28 +01007129 buf->b_s.b_syn_isk = empty_option;
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00007130#endif
7131#ifdef FEAT_SPELL
Bram Moolenaard5784f92010-10-13 14:05:35 +02007132 buf->b_s.b_p_spc = vim_strsave(p_spc);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007133 COPY_OPT_SCTX(buf, BV_SPC);
Bram Moolenaar860cae12010-06-05 23:22:07 +02007134 (void)compile_cap_prog(&buf->b_s);
7135 buf->b_s.b_p_spf = vim_strsave(p_spf);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007136 COPY_OPT_SCTX(buf, BV_SPF);
Bram Moolenaar860cae12010-06-05 23:22:07 +02007137 buf->b_s.b_p_spl = vim_strsave(p_spl);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007138 COPY_OPT_SCTX(buf, BV_SPL);
Bram Moolenaar362b44b2020-06-10 21:47:00 +02007139 buf->b_s.b_p_spo = vim_strsave(p_spo);
7140 COPY_OPT_SCTX(buf, BV_SPO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141#endif
Bram Moolenaar8e145b82022-05-21 20:17:31 +01007142#if defined(FEAT_EVAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007143 buf->b_p_inde = vim_strsave(p_inde);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007144 COPY_OPT_SCTX(buf, BV_INDE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 buf->b_p_indk = vim_strsave(p_indk);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007146 COPY_OPT_SCTX(buf, BV_INDK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007147#endif
Bram Moolenaar9be7c042017-01-14 14:28:30 +01007148 buf->b_p_fp = empty_option;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00007149#if defined(FEAT_EVAL)
7150 buf->b_p_fex = vim_strsave(p_fex);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007151 COPY_OPT_SCTX(buf, BV_FEX);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00007152#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007153#ifdef FEAT_CRYPT
7154 buf->b_p_key = vim_strsave(p_key);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007155 COPY_OPT_SCTX(buf, BV_KEY);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007156#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007157 buf->b_p_sua = vim_strsave(p_sua);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007158 COPY_OPT_SCTX(buf, BV_SUA);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007159#ifdef FEAT_KEYMAP
7160 buf->b_p_keymap = vim_strsave(p_keymap);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007161 COPY_OPT_SCTX(buf, BV_KMAP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007162 buf->b_kmap_state |= KEYMAP_INIT;
7163#endif
Bram Moolenaar6d150f72018-04-21 20:03:20 +02007164#ifdef FEAT_TERMINAL
7165 buf->b_p_twsl = p_twsl;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007166 COPY_OPT_SCTX(buf, BV_TWSL);
Bram Moolenaar6d150f72018-04-21 20:03:20 +02007167#endif
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007168 // This isn't really an option, but copying the langmap and IME
7169 // state from the current buffer is better than resetting it.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007170 buf->b_p_iminsert = p_iminsert;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007171 COPY_OPT_SCTX(buf, BV_IMI);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007172 buf->b_p_imsearch = p_imsearch;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007173 COPY_OPT_SCTX(buf, BV_IMS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007174
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007175 // options that are normally global but also have a local value
7176 // are not copied, start using the global value
Bram Moolenaar071d4272004-06-13 20:20:40 +00007177 buf->b_p_ar = -1;
Bram Moolenaarf5a2fd82013-11-06 05:26:15 +01007178 buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02007179 buf->b_p_bkc = empty_option;
7180 buf->b_bkc_flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007181#ifdef FEAT_QUICKFIX
7182 buf->b_p_gp = empty_option;
7183 buf->b_p_mp = empty_option;
7184 buf->b_p_efm = empty_option;
7185#endif
7186 buf->b_p_ep = empty_option;
7187 buf->b_p_kp = empty_option;
7188 buf->b_p_path = empty_option;
7189 buf->b_p_tags = empty_option;
Bram Moolenaar0f6562e2015-11-24 18:48:14 +01007190 buf->b_p_tc = empty_option;
7191 buf->b_tc_flags = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007192#ifdef FEAT_FIND_ID
7193 buf->b_p_def = empty_option;
7194 buf->b_p_inc = empty_option;
7195# ifdef FEAT_EVAL
7196 buf->b_p_inex = vim_strsave(p_inex);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007197 COPY_OPT_SCTX(buf, BV_INEX);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007198# endif
7199#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007200 buf->b_p_dict = empty_option;
7201 buf->b_p_tsr = empty_option;
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01007202#ifdef FEAT_COMPL_FUNC
7203 buf->b_p_tsrfu = empty_option;
7204#endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007205 buf->b_p_qe = vim_strsave(p_qe);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007206 COPY_OPT_SCTX(buf, BV_QE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00007207#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
7208 buf->b_p_bexpr = empty_option;
7209#endif
Bram Moolenaar49771f42010-07-20 17:32:38 +02007210#if defined(FEAT_CRYPT)
7211 buf->b_p_cm = empty_option;
7212#endif
Bram Moolenaar55debbe2010-05-23 23:34:36 +02007213#ifdef FEAT_PERSISTENT_UNDO
7214 buf->b_p_udf = p_udf;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007215 COPY_OPT_SCTX(buf, BV_UDF);
Bram Moolenaar55debbe2010-05-23 23:34:36 +02007216#endif
Bram Moolenaaraf6c1312014-03-12 18:55:58 +01007217 buf->b_p_lw = empty_option;
Bram Moolenaar2c7292d2017-03-05 17:43:31 +01007218 buf->b_p_menc = empty_option;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007219
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00007220 // Don't copy the options set by ex_help(), use the saved values,
7221 // when going from a help buffer to a non-help buffer.
7222 // Don't touch these at all when BCO_NOHELP is used and going from
7223 // or to a help buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007224 if (dont_do_help)
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007225 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007226 buf->b_p_isk = save_p_isk;
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007227#ifdef FEAT_VARTABS
Yegappan Lakshmanan960dcbd2023-03-07 17:45:11 +00007228 if (p_vts && *p_vts != NUL && !buf->b_p_vts_array)
Bram Moolenaarb7081e12021-09-04 18:47:28 +02007229 (void)tabstop_set(p_vts, &buf->b_p_vts_array);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007230 else
7231 buf->b_p_vts_array = NULL;
7232#endif
7233 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234 else
7235 {
7236 buf->b_p_isk = vim_strsave(p_isk);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007237 COPY_OPT_SCTX(buf, BV_ISK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007238 did_isk = TRUE;
7239 buf->b_p_ts = p_ts;
Bram Moolenaar62068772021-12-14 09:01:38 +00007240 COPY_OPT_SCTX(buf, BV_TS);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007241#ifdef FEAT_VARTABS
7242 buf->b_p_vts = vim_strsave(p_vts);
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007243 COPY_OPT_SCTX(buf, BV_VTS);
Yegappan Lakshmanan960dcbd2023-03-07 17:45:11 +00007244 if (p_vts && *p_vts != NUL && !buf->b_p_vts_array)
Bram Moolenaarb7081e12021-09-04 18:47:28 +02007245 (void)tabstop_set(p_vts, &buf->b_p_vts_array);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02007246 else
7247 buf->b_p_vts_array = NULL;
7248#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007249 buf->b_help = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007250 if (buf->b_p_bt[0] == 'h')
7251 clear_string_option(&buf->b_p_bt);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007252 buf->b_p_ma = p_ma;
Bram Moolenaarcfb38142019-10-19 20:18:47 +02007253 COPY_OPT_SCTX(buf, BV_MA);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007254 }
7255 }
7256
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00007257 // When the options should be copied (ignoring BCO_ALWAYS), set the
7258 // flag that indicates that the options have been initialized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007259 if (should_copy)
7260 buf->b_p_initialized = TRUE;
7261 }
7262
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007263 check_buf_options(buf); // make sure we don't have NULLs
Bram Moolenaar071d4272004-06-13 20:20:40 +00007264 if (did_isk)
7265 (void)buf_init_chartab(buf, FALSE);
7266}
7267
7268/*
7269 * Reset the 'modifiable' option and its default value.
7270 */
7271 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01007272reset_modifiable(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007273{
7274 int opt_idx;
7275
7276 curbuf->b_p_ma = FALSE;
7277 p_ma = FALSE;
7278 opt_idx = findoption((char_u *)"ma");
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00007279 if (opt_idx >= 0)
7280 options[opt_idx].def_val[VI_DEFAULT] = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007281}
7282
7283/*
7284 * Set the global value for 'iminsert' to the local value.
7285 */
7286 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01007287set_iminsert_global(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007288{
7289 p_iminsert = curbuf->b_p_iminsert;
7290}
7291
7292/*
7293 * Set the global value for 'imsearch' to the local value.
7294 */
7295 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01007296set_imsearch_global(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007297{
7298 p_imsearch = curbuf->b_p_imsearch;
7299}
7300
Bram Moolenaar071d4272004-06-13 20:20:40 +00007301static int expand_option_idx = -1;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007302static int expand_option_start_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007303static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL};
7304static int expand_option_flags = 0;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007305static int expand_option_append = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007306
7307 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01007308set_context_in_set_cmd(
7309 expand_T *xp,
7310 char_u *arg,
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007311 int opt_flags) // OPT_GLOBAL and/or OPT_LOCAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007312{
7313 int nextchar;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007314 long_u flags = 0; // init for GCC
7315 int opt_idx = 0; // init for GCC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007316 char_u *p;
7317 char_u *s;
7318 int is_term_option = FALSE;
7319 int key;
7320
7321 expand_option_flags = opt_flags;
7322
7323 xp->xp_context = EXPAND_SETTINGS;
7324 if (*arg == NUL)
7325 {
7326 xp->xp_pattern = arg;
7327 return;
7328 }
7329 p = arg + STRLEN(arg) - 1;
7330 if (*p == ' ' && *(p - 1) != '\\')
7331 {
7332 xp->xp_pattern = p + 1;
7333 return;
7334 }
7335 while (p > arg)
7336 {
7337 s = p;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007338 // count number of backslashes before ' ' or ','
Bram Moolenaar071d4272004-06-13 20:20:40 +00007339 if (*p == ' ' || *p == ',')
7340 {
7341 while (s > arg && *(s - 1) == '\\')
7342 --s;
7343 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007344 // break at a space with an even number of backslashes
Bram Moolenaar071d4272004-06-13 20:20:40 +00007345 if (*p == ' ' && ((p - s) & 1) == 0)
7346 {
7347 ++p;
7348 break;
7349 }
7350 --p;
7351 }
Bram Moolenaar2a7b9ee2009-06-16 15:50:33 +00007352 if (STRNCMP(p, "no", 2) == 0 && STRNCMP(p, "novice", 6) != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007353 {
7354 xp->xp_context = EXPAND_BOOL_SETTINGS;
Bram Moolenaar048d9d22023-05-06 22:21:11 +01007355 xp->xp_prefix = XP_PREFIX_NO;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007356 p += 2;
7357 }
Bram Moolenaar048d9d22023-05-06 22:21:11 +01007358 else if (STRNCMP(p, "inv", 3) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007359 {
7360 xp->xp_context = EXPAND_BOOL_SETTINGS;
Bram Moolenaar048d9d22023-05-06 22:21:11 +01007361 xp->xp_prefix = XP_PREFIX_INV;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007362 p += 3;
7363 }
7364 xp->xp_pattern = arg = p;
7365 if (*arg == '<')
7366 {
7367 while (*p != '>')
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007368 if (*p++ == NUL) // expand terminal option name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007369 return;
7370 key = get_special_key_code(arg + 1);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007371 if (key == 0) // unknown name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007372 {
7373 xp->xp_context = EXPAND_NOTHING;
7374 return;
7375 }
7376 nextchar = *++p;
7377 is_term_option = TRUE;
7378 expand_option_name[2] = KEY2TERMCAP0(key);
7379 expand_option_name[3] = KEY2TERMCAP1(key);
7380 }
7381 else
7382 {
7383 if (p[0] == 't' && p[1] == '_')
7384 {
7385 p += 2;
7386 if (*p != NUL)
7387 ++p;
7388 if (*p == NUL)
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007389 return; // expand option name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007390 nextchar = *++p;
7391 is_term_option = TRUE;
7392 expand_option_name[2] = p[-2];
7393 expand_option_name[3] = p[-1];
7394 }
7395 else
7396 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007397 // Allow * wildcard
Bram Moolenaar071d4272004-06-13 20:20:40 +00007398 while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*')
7399 p++;
7400 if (*p == NUL)
7401 return;
7402 nextchar = *p;
7403 *p = NUL;
7404 opt_idx = findoption(arg);
7405 *p = nextchar;
7406 if (opt_idx == -1 || options[opt_idx].var == NULL)
7407 {
7408 xp->xp_context = EXPAND_NOTHING;
7409 return;
7410 }
7411 flags = options[opt_idx].flags;
7412 if (flags & P_BOOL)
7413 {
7414 xp->xp_context = EXPAND_NOTHING;
7415 return;
7416 }
7417 }
7418 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007419 // handle "-=" and "+="
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007420 expand_option_append = FALSE;
7421 int expand_option_subtract = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007422 if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=')
7423 {
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007424 if (nextchar == '-')
7425 expand_option_subtract = TRUE;
7426 if (nextchar == '+' || nextchar == '^')
7427 expand_option_append = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007428 ++p;
7429 nextchar = '=';
7430 }
7431 if ((nextchar != '=' && nextchar != ':')
7432 || xp->xp_context == EXPAND_BOOL_SETTINGS)
7433 {
7434 xp->xp_context = EXPAND_UNSUCCESSFUL;
7435 return;
7436 }
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007437
7438 // Below are for handling expanding a specific option's value after the '='
7439 // or ':'
7440
7441 if (is_term_option)
7442 expand_option_idx = -1;
7443 else
7444 expand_option_idx = opt_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007445
Yee Cheng Chin6ee7b522023-10-01 09:13:22 +02007446 if (!is_term_option)
7447 {
7448 if (options[opt_idx].flags & P_NO_CMD_EXPAND)
7449 {
7450 xp->xp_context=EXPAND_UNSUCCESSFUL;
7451 return;
7452 }
7453 }
7454
Bram Moolenaar071d4272004-06-13 20:20:40 +00007455 xp->xp_pattern = p + 1;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007456 expand_option_start_col = (int)(p + 1 - xp->xp_line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007457
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007458 // Certain options currently have special case handling to reuse the
7459 // expansion logic with other commands.
Doug Kearns6dfdff32023-08-27 18:48:51 +02007460#ifdef FEAT_SYN_HL
7461 if (options[opt_idx].var == (char_u *)&p_syn)
7462 {
7463 xp->xp_context = EXPAND_OWNSYNTAX;
7464 return;
7465 }
7466#endif
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007467 if (options[opt_idx].var == (char_u *)&p_ft)
7468 {
7469 xp->xp_context = EXPAND_FILETYPE;
7470 return;
7471 }
Doug Kearns81642d92024-01-04 22:37:44 +01007472#ifdef FEAT_KEYMAP
7473 if (options[opt_idx].var == (char_u *)&p_keymap)
7474 {
7475 xp->xp_context = EXPAND_KEYMAP;
7476 return;
7477 }
7478#endif
Doug Kearns6dfdff32023-08-27 18:48:51 +02007479
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007480 // Now pick. If the option has a custom expander, use that. Otherwise, just
7481 // fill with the existing option value.
7482 if (expand_option_subtract)
7483 {
7484 xp->xp_context = EXPAND_SETTING_SUBTRACT;
7485 return;
7486 }
7487 else if (expand_option_idx >= 0 &&
7488 options[expand_option_idx].opt_expand_cb != NULL)
7489 {
7490 xp->xp_context = EXPAND_STRING_SETTING;
7491 }
7492 else if (*xp->xp_pattern == NUL)
7493 {
7494 xp->xp_context = EXPAND_OLD_SETTING;
7495 return;
7496 }
7497 else
7498 xp->xp_context = EXPAND_NOTHING;
7499
7500 if (is_term_option || (flags & P_NUM))
7501 return;
7502
7503 // Only string options below
7504
7505 // Options that have P_EXPAND are considered to all use file/dir expansion.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007506 if (flags & P_EXPAND)
7507 {
7508 p = options[opt_idx].var;
7509 if (p == (char_u *)&p_bdir
7510 || p == (char_u *)&p_dir
7511 || p == (char_u *)&p_path
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01007512 || p == (char_u *)&p_pp
Bram Moolenaar071d4272004-06-13 20:20:40 +00007513 || p == (char_u *)&p_rtp
Bram Moolenaar071d4272004-06-13 20:20:40 +00007514 || p == (char_u *)&p_cdpath
Bram Moolenaar071d4272004-06-13 20:20:40 +00007515#ifdef FEAT_SESSION
7516 || p == (char_u *)&p_vdir
7517#endif
7518 )
7519 {
7520 xp->xp_context = EXPAND_DIRECTORIES;
Bram Moolenaarf80f40a2022-08-25 16:02:23 +01007521 if (p == (char_u *)&p_path || p == (char_u *)&p_cdpath)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007522 xp->xp_backslash = XP_BS_THREE;
7523 else
7524 xp->xp_backslash = XP_BS_ONE;
7525 }
7526 else
7527 {
7528 xp->xp_context = EXPAND_FILES;
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007529 // for 'tags' need three backslashes for a space
Bram Moolenaar071d4272004-06-13 20:20:40 +00007530 if (p == (char_u *)&p_tags)
7531 xp->xp_backslash = XP_BS_THREE;
7532 else
7533 xp->xp_backslash = XP_BS_ONE;
7534 }
Yee Cheng Chin54844852023-10-09 18:12:31 +02007535 if (flags & P_COMMA)
7536 xp->xp_backslash |= XP_BS_COMMA;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007537 }
7538
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007539 // For an option that is a list of file names, or comma/colon-separated
7540 // values, split it by the delimiter and find the start of the current
7541 // pattern, while accounting for backslash-escaped space/commas/colons.
7542 // Triple-backslashed escaped file names (e.g. 'path') can also be
7543 // delimited by space.
7544 if ((flags & P_EXPAND) || (flags & P_COMMA) || (flags & P_COLON))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007545 {
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007546 for (p = arg + STRLEN(arg) - 1; p >= xp->xp_pattern; --p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547 {
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007548 // count number of backslashes before ' ' or ',' or ':'
7549 if (*p == ' ' || *p == ',' ||
7550 (*p == ':' && (flags & P_COLON)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007551 {
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007552 s = p;
7553 while (s > xp->xp_pattern && *(s - 1) == '\\')
7554 --s;
Yee Cheng Chin54844852023-10-09 18:12:31 +02007555 if ((*p == ' ' && ((xp->xp_backslash & XP_BS_THREE) && (p - s) < 3))
7556#if defined(BACKSLASH_IN_FILENAME)
7557 || (*p == ',' && (flags & P_COMMA) && (p - s) < 1)
7558#else
7559 || (*p == ',' && (flags & P_COMMA) && (p - s) < 2)
7560#endif
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007561 || (*p == ':' && (flags & P_COLON)))
7562 {
7563 xp->xp_pattern = p + 1;
7564 break;
7565 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007566 }
7567 }
7568 }
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007569
7570 // An option that is a list of single-character flags should always start
7571 // at the end as we don't complete words.
7572 if (flags & P_FLAGLIST)
7573 xp->xp_pattern = arg + STRLEN(arg);
7574
7575 // Some options can either be using file/dir expansions, or custom value
7576 // expansion depending on what the user typed. Unfortunately we have to
7577 // manually handle it here to make sure we have the correct xp_context set.
7578#ifdef FEAT_SPELL
7579 if (options[opt_idx].var == (char_u *)&p_sps)
7580 {
7581 if (STRNCMP(xp->xp_pattern, "file:", 5) == 0)
7582 {
7583 xp->xp_pattern += 5;
7584 return;
7585 }
7586 else if (options[expand_option_idx].opt_expand_cb != NULL)
7587 {
7588 xp->xp_context = EXPAND_STRING_SETTING;
7589 }
7590 }
7591#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007592}
7593
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007594/*
7595 * Returns TRUE if 'str' either matches 'regmatch' or fuzzy matches 'pat'.
7596 *
7597 * If 'test_only' is TRUE and 'fuzzy' is FALSE and if 'str' matches the regular
7598 * expression 'regmatch', then returns TRUE. Otherwise returns FALSE.
7599 *
7600 * If 'test_only' is FALSE and 'fuzzy' is FALSE and if 'str' matches the
7601 * regular expression 'regmatch', then stores the match in matches[idx] and
7602 * returns TRUE.
7603 *
7604 * If 'test_only' is TRUE and 'fuzzy' is TRUE and if 'str' fuzzy matches
7605 * 'fuzzystr', then returns TRUE. Otherwise returns FALSE.
7606 *
7607 * If 'test_only' is FALSE and 'fuzzy' is TRUE and if 'str' fuzzy matches
7608 * 'fuzzystr', then stores the match details in fuzmatch[idx] and returns TRUE.
7609 */
Yee Cheng Chinf7f746b2023-09-30 12:28:50 +02007610 static int
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007611match_str(
7612 char_u *str,
7613 regmatch_T *regmatch,
7614 char_u **matches,
7615 int idx,
7616 int test_only,
7617 int fuzzy,
7618 char_u *fuzzystr,
7619 fuzmatch_str_T *fuzmatch)
7620{
7621 if (!fuzzy)
7622 {
7623 if (vim_regexec(regmatch, str, (colnr_T)0))
7624 {
7625 if (!test_only)
7626 matches[idx] = vim_strsave(str);
7627 return TRUE;
7628 }
7629 }
7630 else
7631 {
7632 int score;
7633
7634 score = fuzzy_match_str(str, fuzzystr);
7635 if (score != 0)
7636 {
7637 if (!test_only)
7638 {
7639 fuzmatch[idx].idx = idx;
7640 fuzmatch[idx].str = vim_strsave(str);
7641 fuzmatch[idx].score = score;
7642 }
7643
7644 return TRUE;
7645 }
7646 }
7647
7648 return FALSE;
7649}
7650
Bram Moolenaar071d4272004-06-13 20:20:40 +00007651 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01007652ExpandSettings(
7653 expand_T *xp,
7654 regmatch_T *regmatch,
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007655 char_u *fuzzystr,
7656 int *numMatches,
Christian Brabandtcb747892022-05-08 21:10:56 +01007657 char_u ***matches,
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01007658 int can_fuzzy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007659{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007660 int num_normal = 0; // Nr of matching non-term-code settings
7661 int num_term = 0; // Nr of matching terminal code settings
Bram Moolenaar071d4272004-06-13 20:20:40 +00007662 int opt_idx;
7663 int match;
7664 int count = 0;
7665 char_u *str;
7666 int loop;
7667 int is_term_opt;
7668 char_u name_buf[MAX_KEY_NAME_LEN];
7669 static char *(names[]) = {"all", "termcap"};
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007670 int ic = regmatch->rm_ic; // remember the ignore-case flag
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007671 int fuzzy;
7672 fuzmatch_str_T *fuzmatch = NULL;
7673
Christian Brabandtcb747892022-05-08 21:10:56 +01007674 fuzzy = can_fuzzy && cmdline_fuzzy_complete(fuzzystr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007675
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007676 // do this loop twice:
7677 // loop == 0: count the number of matching options
7678 // loop == 1: copy the matching options into allocated memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007679 for (loop = 0; loop <= 1; ++loop)
7680 {
7681 regmatch->rm_ic = ic;
7682 if (xp->xp_context != EXPAND_BOOL_SETTINGS)
7683 {
K.Takataeeec2542021-06-02 13:28:16 +02007684 for (match = 0; match < (int)ARRAY_LENGTH(names); ++match)
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007685 {
7686 if (match_str((char_u *)names[match], regmatch, *matches,
7687 count, (loop == 0), fuzzy, fuzzystr, fuzmatch))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007688 {
7689 if (loop == 0)
7690 num_normal++;
7691 else
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007692 count++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693 }
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007694 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007695 }
7696 for (opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL;
7697 opt_idx++)
7698 {
7699 if (options[opt_idx].var == NULL)
7700 continue;
7701 if (xp->xp_context == EXPAND_BOOL_SETTINGS
Bram Moolenaar048d9d22023-05-06 22:21:11 +01007702 && !(options[opt_idx].flags & P_BOOL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007703 continue;
Bram Moolenaardac13472019-09-16 21:06:21 +02007704 is_term_opt = istermoption_idx(opt_idx);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007705 if (is_term_opt && num_normal > 0)
7706 continue;
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007707
7708 if (match_str(str, regmatch, *matches, count, (loop == 0),
7709 fuzzy, fuzzystr, fuzmatch))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007710 {
7711 if (loop == 0)
7712 {
7713 if (is_term_opt)
7714 num_term++;
7715 else
7716 num_normal++;
7717 }
7718 else
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007719 count++;
7720 }
7721 else if (!fuzzy && options[opt_idx].shortname != NULL
7722 && vim_regexec(regmatch,
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01007723 (char_u *)options[opt_idx].shortname, (colnr_T)0))
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007724 {
7725 // Compare against the abbreviated option name (for regular
7726 // expression match). Fuzzy matching (previous if) already
7727 // matches against both the expanded and abbreviated names.
7728 if (loop == 0)
7729 {
7730 if (is_term_opt)
7731 num_term++;
7732 else
7733 num_normal++;
7734 }
7735 else
7736 (*matches)[count++] = vim_strsave(str);
7737 }
7738 else if (is_term_opt)
7739 {
7740 name_buf[0] = '<';
7741 name_buf[1] = 't';
7742 name_buf[2] = '_';
7743 name_buf[3] = str[2];
7744 name_buf[4] = str[3];
7745 name_buf[5] = '>';
7746 name_buf[6] = NUL;
7747
7748 if (match_str(name_buf, regmatch, *matches, count, (loop == 0),
7749 fuzzy, fuzzystr, fuzmatch))
7750 {
7751 if (loop == 0)
7752 num_term++;
7753 else
7754 count++;
7755 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007756 }
7757 }
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007758
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00007759 // Check terminal key codes, these are not in the option table
Bram Moolenaar071d4272004-06-13 20:20:40 +00007760 if (xp->xp_context != EXPAND_BOOL_SETTINGS && num_normal == 0)
7761 {
7762 for (opt_idx = 0; (str = get_termcode(opt_idx)) != NULL; opt_idx++)
7763 {
Keith Thompson184f71c2024-01-04 21:19:04 +01007764 if (!SAFE_isprint(str[0]) || !SAFE_isprint(str[1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007765 continue;
7766
7767 name_buf[0] = 't';
7768 name_buf[1] = '_';
7769 name_buf[2] = str[0];
7770 name_buf[3] = str[1];
7771 name_buf[4] = NUL;
7772
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007773 if (match_str(name_buf, regmatch, *matches, count,
Bram Moolenaar048d9d22023-05-06 22:21:11 +01007774 (loop == 0), fuzzy, fuzzystr, fuzmatch))
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007775 {
7776 if (loop == 0)
7777 num_term++;
7778 else
7779 count++;
7780 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007781 else
7782 {
7783 name_buf[0] = '<';
7784 name_buf[1] = 't';
7785 name_buf[2] = '_';
7786 name_buf[3] = str[0];
7787 name_buf[4] = str[1];
7788 name_buf[5] = '>';
7789 name_buf[6] = NUL;
7790
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007791 if (match_str(name_buf, regmatch, *matches, count,
7792 (loop == 0), fuzzy, fuzzystr,
7793 fuzmatch))
7794 {
7795 if (loop == 0)
7796 num_term++;
7797 else
7798 count++;
7799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007800 }
7801 }
7802
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00007803 // Check special key names.
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007804 regmatch->rm_ic = TRUE; // ignore case here
Bram Moolenaar071d4272004-06-13 20:20:40 +00007805 for (opt_idx = 0; (str = get_key_name(opt_idx)) != NULL; opt_idx++)
7806 {
7807 name_buf[0] = '<';
7808 STRCPY(name_buf + 1, str);
7809 STRCAT(name_buf, ">");
7810
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007811 if (match_str(name_buf, regmatch, *matches, count, (loop == 0),
7812 fuzzy, fuzzystr, fuzmatch))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007813 {
7814 if (loop == 0)
7815 num_term++;
7816 else
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007817 count++;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007818 }
7819 }
7820 }
7821 if (loop == 0)
7822 {
7823 if (num_normal > 0)
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007824 *numMatches = num_normal;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007825 else if (num_term > 0)
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007826 *numMatches = num_term;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007827 else
7828 return OK;
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007829 if (!fuzzy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007830 {
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007831 *matches = ALLOC_MULT(char_u *, *numMatches);
7832 if (*matches == NULL)
7833 {
7834 *matches = (char_u **)"";
7835 return FAIL;
7836 }
7837 }
7838 else
7839 {
7840 fuzmatch = ALLOC_MULT(fuzmatch_str_T, *numMatches);
7841 if (fuzmatch == NULL)
7842 {
7843 *matches = (char_u **)"";
7844 return FAIL;
7845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007846 }
7847 }
7848 }
Yegappan Lakshmanan38b85cb2022-02-24 13:28:41 +00007849
7850 if (fuzzy &&
7851 fuzzymatches_to_strmatches(fuzmatch, matches, count, FALSE) == FAIL)
7852 return FAIL;
7853
Bram Moolenaar071d4272004-06-13 20:20:40 +00007854 return OK;
7855}
7856
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007857// Escape an option value that can be used on the command-line with :set.
7858// Caller needs to free the returned string, unless NULL is returned.
7859 static char_u*
7860escape_option_str_cmdline(char_u *var)
7861{
7862 char_u *buf;
7863
7864 // A backslash is required before some characters. This is the reverse of
7865 // what happens in do_set().
7866 buf = vim_strsave_escaped(var, escape_chars);
7867 if (buf == NULL)
7868 return NULL;
7869
7870#ifdef BACKSLASH_IN_FILENAME
7871 // For MS-Windows et al. we don't double backslashes at the start and
7872 // before a file name character.
7873 // The reverse is found at stropt_copy_value().
7874 for (var = buf; *var != NUL; MB_PTR_ADV(var))
7875 if (var[0] == '\\' && var[1] == '\\'
7876 && expand_option_idx >= 0
7877 && (options[expand_option_idx].flags & P_EXPAND)
7878 && vim_isfilec(var[2])
7879 && (var[2] != '\\' || (var == buf && var[4] != '\\')))
7880 STRMOVE(var, var + 1);
7881#endif
7882 return buf;
7883}
7884
7885/*
7886 * Expansion handler for :set= when we just want to fill in with the existing value.
7887 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007888 int
zeertzjqb0d45ec2023-01-25 15:04:22 +00007889ExpandOldSetting(int *numMatches, char_u ***matches)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007890{
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007891 char_u *var = NULL; // init for GCC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007892 char_u *buf;
7893
zeertzjqb0d45ec2023-01-25 15:04:22 +00007894 *numMatches = 0;
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007895 *matches = ALLOC_MULT(char_u *, 1);
zeertzjqb0d45ec2023-01-25 15:04:22 +00007896 if (*matches == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007897 return FAIL;
7898
Yegappan Lakshmananc6ff21e2023-03-02 14:46:48 +00007899 // For a terminal key code expand_option_idx is < 0.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007900 if (expand_option_idx < 0)
7901 {
7902 var = find_termcode(expand_option_name + 2);
7903 if (var == NULL)
7904 expand_option_idx = findoption(expand_option_name);
7905 }
7906
7907 if (expand_option_idx >= 0)
7908 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01007909 // put string of option value in NameBuff
Bram Moolenaar071d4272004-06-13 20:20:40 +00007910 option_value2string(&options[expand_option_idx], expand_option_flags);
7911 var = NameBuff;
7912 }
7913 else if (var == NULL)
7914 var = (char_u *)"";
7915
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007916 buf = escape_option_str_cmdline(var);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007917 if (buf == NULL)
7918 {
zeertzjqb0d45ec2023-01-25 15:04:22 +00007919 VIM_CLEAR(*matches);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007920 return FAIL;
7921 }
7922
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007923 (*matches)[0] = buf;
zeertzjqb0d45ec2023-01-25 15:04:22 +00007924 *numMatches = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007925 return OK;
7926}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007927
7928/*
Yee Cheng Chin900894b2023-09-29 20:42:32 +02007929 * Expansion handler for :set=/:set+= when the option has a custom expansion handler.
7930 */
7931 int
7932ExpandStringSetting(
7933 expand_T *xp,
7934 regmatch_T *regmatch,
7935 int *numMatches,
7936 char_u ***matches)
7937{
7938 char_u *var = NULL; // init for GCC
7939 char_u *buf;
7940
7941 if (expand_option_idx < 0 ||
7942 options[expand_option_idx].opt_expand_cb == NULL)
7943 {
7944 // Not supposed to reach this. This function is only for options with
7945 // custom expansion callbacks.
7946 return FAIL;
7947 }
7948
7949 optexpand_T args;
7950 args.oe_varp = get_varp_scope(&options[expand_option_idx], expand_option_flags);
7951 args.oe_append = expand_option_append;
7952 args.oe_regmatch = regmatch;
7953 args.oe_xp = xp;
7954 args.oe_set_arg = xp->xp_line + expand_option_start_col;
7955 args.oe_include_orig_val =
7956 !expand_option_append &&
7957 (*args.oe_set_arg == NUL);
7958
7959 // Retrieve the existing value, but escape it as a reverse of setting it.
7960 // We technically only need to do this when oe_append or
7961 // oe_include_orig_val is true.
7962 option_value2string(&options[expand_option_idx], expand_option_flags);
7963 var = NameBuff;
7964 buf = escape_option_str_cmdline(var);
7965 if (buf == NULL)
7966 return FAIL;
7967
7968 args.oe_opt_value = buf;
7969
7970 int num_ret = options[expand_option_idx].opt_expand_cb(&args, numMatches, matches);
7971
7972 vim_free(buf);
7973 return num_ret;
7974}
7975
7976/*
7977 * Expansion handler for :set-=
7978 */
7979 int
7980ExpandSettingSubtract(
7981 expand_T *xp,
7982 regmatch_T *regmatch,
7983 int *numMatches,
7984 char_u ***matches)
7985{
7986 if (expand_option_idx < 0)
7987 // term option
7988 return ExpandOldSetting(numMatches, matches);
7989
7990 char_u *option_val = *(char_u**)get_option_varp_scope(
7991 expand_option_idx, expand_option_flags);
7992
7993 long_u option_flags = options[expand_option_idx].flags;
7994
7995 if (option_flags & P_NUM)
7996 return ExpandOldSetting(numMatches, matches);
7997 else if (option_flags & P_COMMA)
7998 {
7999 // Split the option by comma, then present each option to the user if
8000 // it matches the pattern.
8001 // This condition needs to go first, because 'whichwrap' has both
8002 // P_COMMA and P_FLAGLIST.
8003 garray_T ga;
8004
8005 char_u *item;
8006 char_u *option_copy;
8007 char_u *next_val;
8008 char_u *comma;
8009
8010 if (*option_val == NUL)
8011 return FAIL;
8012
8013 // Make a copy as we need to inject null characters destructively.
8014 option_copy = vim_strsave(option_val);
8015 if (option_copy == NULL)
8016 return FAIL;
8017 next_val = option_copy;
8018
8019 ga_init2(&ga, sizeof(char_u *), 10);
8020
8021 do
8022 {
8023 item = next_val;
8024 comma = vim_strchr(next_val, ',');
8025 while (comma != NULL && comma != next_val && *(comma - 1) == '\\')
8026 {
8027 // "\," is interpreted as a literal comma rather than option
8028 // separator when reading options in copy_option_part(). Skip
8029 // it.
8030 comma = vim_strchr(comma + 1, ',');
8031 }
8032 if (comma != NULL)
8033 {
8034 *comma = NUL; // null-terminate this value, required by later functions
8035 next_val = comma + 1;
8036 }
8037 else
8038 next_val = NULL;
8039
8040 if (*item == NUL)
8041 // empty value, don't add to list
8042 continue;
8043
8044 if (!vim_regexec(regmatch, item, (colnr_T)0))
8045 continue;
8046
8047 char_u *buf = escape_option_str_cmdline(item);
8048 if (buf == NULL)
8049 {
8050 vim_free(option_copy);
8051 ga_clear_strings(&ga);
8052 return FAIL;
8053 }
8054 if (ga_add_string(&ga, buf) != OK)
8055 {
8056 vim_free(buf);
8057 break;
8058 }
8059 } while (next_val != NULL);
8060
8061 vim_free(option_copy);
8062
8063 *matches = ga.ga_data;
8064 *numMatches = ga.ga_len;
8065 return OK;
8066 }
8067 else if (option_flags & P_FLAGLIST)
8068 {
8069 // Only present the flags that are set on the option as the other flags
8070 // are not meaningful to do set-= on.
8071
8072 if (*xp->xp_pattern != NUL)
8073 {
8074 // Don't suggest anything if cmdline is non-empty. Vim's set-=
8075 // behavior requires consecutive strings and it's usually
Viktor Szépedbf749b2023-10-16 09:53:37 +02008076 // unintuitive to users if they try to subtract multiple flags at
Yee Cheng Chin900894b2023-09-29 20:42:32 +02008077 // once.
8078 return FAIL;
8079 }
8080
Yee Cheng Chin6d113472023-10-02 21:38:39 +02008081 size_t num_flags = STRLEN(option_val);
Yee Cheng Chin900894b2023-09-29 20:42:32 +02008082 if (num_flags == 0)
8083 return FAIL;
8084
8085 *matches = ALLOC_MULT(char_u *, num_flags + 1);
8086 if (*matches == NULL)
8087 return FAIL;
8088
8089 int count = 0;
8090 char_u *p;
8091
8092 p = vim_strsave(option_val);
8093 if (p == NULL)
8094 {
8095 VIM_CLEAR(*matches);
8096 return FAIL;
8097 }
8098 (*matches)[count++] = p;
8099
8100 if (num_flags > 1)
8101 {
8102 // If more than one flags, split the flags up and expose each
8103 // character as individual choice.
8104 for (char_u *flag = option_val; *flag != NUL; flag++)
8105 {
Yee Cheng Chinf7f746b2023-09-30 12:28:50 +02008106 p = vim_strnsave(flag, 1);
Yee Cheng Chin900894b2023-09-29 20:42:32 +02008107 if (p == NULL)
8108 break;
8109 (*matches)[count++] = p;
8110 }
8111 }
8112
8113 *numMatches = count;
8114 return OK;
8115 }
8116
8117 return ExpandOldSetting(numMatches, matches);
8118}
8119
8120/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008121 * Get the value for the numeric or string option *opp in a nice format into
8122 * NameBuff[]. Must not be called with a hidden option!
8123 */
8124 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01008125option_value2string(
8126 struct vimoption *opp,
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00008127 int scope) // OPT_GLOBAL and/or OPT_LOCAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008128{
8129 char_u *varp;
8130
Yegappan Lakshmanan64095532021-12-06 11:03:55 +00008131 varp = get_varp_scope(opp, scope);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008132
8133 if (opp->flags & P_NUM)
8134 {
8135 long wc = 0;
8136
8137 if (wc_use_keyname(varp, &wc))
8138 STRCPY(NameBuff, get_special_key_name((int)wc, 0));
8139 else if (wc != 0)
8140 STRCPY(NameBuff, transchar((int)wc));
8141 else
8142 sprintf((char *)NameBuff, "%ld", *(long *)varp);
8143 }
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008144 else // P_STRING
Bram Moolenaar071d4272004-06-13 20:20:40 +00008145 {
8146 varp = *(char_u **)(varp);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008147 if (varp == NULL) // just in case
Bram Moolenaar071d4272004-06-13 20:20:40 +00008148 NameBuff[0] = NUL;
8149#ifdef FEAT_CRYPT
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008150 // don't show the actual value of 'key', only that it's set
Bram Moolenaareb3593b2006-04-22 22:33:57 +00008151 else if (opp->var == (char_u *)&p_key && *varp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008152 STRCPY(NameBuff, "*****");
8153#endif
8154 else if (opp->flags & P_EXPAND)
8155 home_replace(NULL, varp, NameBuff, MAXPATHL, FALSE);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008156 // Translate 'pastetoggle' into special key names
Bram Moolenaar071d4272004-06-13 20:20:40 +00008157 else if ((char_u **)opp->var == &p_pt)
8158 str2specialbuf(p_pt, NameBuff, MAXPATHL);
8159 else
Bram Moolenaarce0842a2005-07-18 21:58:11 +00008160 vim_strncpy(NameBuff, varp, MAXPATHL - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008161 }
8162}
8163
8164/*
8165 * Return TRUE if "varp" points to 'wildchar' or 'wildcharm' and it can be
8166 * printed as a keyname.
8167 * "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'.
8168 */
8169 static int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008170wc_use_keyname(char_u *varp, long *wcp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008171{
8172 if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm))
8173 {
8174 *wcp = *(long *)varp;
8175 if (IS_SPECIAL(*wcp) || find_special_key_in_table((int)*wcp) >= 0)
8176 return TRUE;
8177 }
8178 return FALSE;
8179}
8180
Bram Moolenaar071d4272004-06-13 20:20:40 +00008181/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008182 * Return TRUE if "x" is present in 'shortmess' option, or
8183 * 'shortmess' contains 'a' and "x" is present in SHM_A.
8184 */
8185 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008186shortmess(int x)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008187{
Bram Moolenaar7f29f7a2012-02-29 13:51:37 +01008188 return p_shm != NULL &&
8189 ( vim_strchr(p_shm, x) != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00008190 || (vim_strchr(p_shm, 'a') != NULL
8191 && vim_strchr((char_u *)SHM_A, x) != NULL));
8192}
8193
8194/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008195 * vimrc_found() - Called when a ".vimrc" or "VIMINIT" has been found.
8196 *
8197 * Reset 'compatible' and set the values for options that didn't get set yet
8198 * to the Vim defaults.
8199 * Don't do this if the 'compatible' option has been set or reset before.
Bram Moolenaar910f66f2006-04-05 20:41:53 +00008200 * When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008201 */
8202 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01008203vimrc_found(char_u *fname, char_u *envname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008204{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00008205 int opt_idx;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00008206 int dofree = FALSE;
Bram Moolenaar910f66f2006-04-05 20:41:53 +00008207 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008208
8209 if (!option_was_set((char_u *)"cp"))
8210 {
8211 p_cp = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +02008212 for (opt_idx = 0; !istermoption_idx(opt_idx); opt_idx++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008213 if (!(options[opt_idx].flags & (P_WAS_SET|P_VI_DEF)))
8214 set_option_default(opt_idx, OPT_FREE, FALSE);
8215 didset_options();
Bram Moolenaare68c25c2015-08-25 15:39:55 +02008216 didset_options2();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008217 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00008218
8219 if (fname != NULL)
8220 {
8221 p = vim_getenv(envname, &dofree);
8222 if (p == NULL)
8223 {
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008224 // Set $MYVIMRC to the first vimrc file found.
Bram Moolenaar910f66f2006-04-05 20:41:53 +00008225 p = FullName_save(fname, FALSE);
8226 if (p != NULL)
8227 {
8228 vim_setenv(envname, p);
8229 vim_free(p);
8230 }
8231 }
8232 else if (dofree)
8233 vim_free(p);
8234 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008235}
8236
8237/*
8238 * Set 'compatible' on or off. Called for "-C" and "-N" command line arg.
8239 */
8240 void
Bram Moolenaar9b578142016-01-30 19:39:49 +01008241change_compatible(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008242{
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00008243 int opt_idx;
8244
Bram Moolenaar071d4272004-06-13 20:20:40 +00008245 if (p_cp != on)
8246 {
8247 p_cp = on;
8248 compatible_set();
8249 }
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00008250 opt_idx = findoption((char_u *)"cp");
8251 if (opt_idx >= 0)
8252 options[opt_idx].flags |= P_WAS_SET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008253}
8254
8255/*
8256 * Return TRUE when option "name" has been set.
Bram Moolenaar1a4a75c2013-07-28 16:03:06 +02008257 * Only works correctly for global options.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008258 */
8259 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008260option_was_set(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008261{
8262 int idx;
8263
8264 idx = findoption(name);
Bram Moolenaar6e0ce172019-12-05 20:12:41 +01008265 if (idx < 0) // unknown option
Bram Moolenaar071d4272004-06-13 20:20:40 +00008266 return FALSE;
8267 if (options[idx].flags & P_WAS_SET)
8268 return TRUE;
8269 return FALSE;
8270}
8271
8272/*
Bram Moolenaar15d55de2012-12-05 14:43:02 +01008273 * Reset the flag indicating option "name" was set.
8274 */
Bram Moolenaarfe8ef982018-09-13 20:31:54 +02008275 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008276reset_option_was_set(char_u *name)
Bram Moolenaar15d55de2012-12-05 14:43:02 +01008277{
8278 int idx = findoption(name);
8279
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +00008280 if (idx < 0)
8281 return FAIL;
8282
8283 options[idx].flags &= ~P_WAS_SET;
8284 return OK;
Bram Moolenaar15d55de2012-12-05 14:43:02 +01008285}
8286
8287/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008288 * compatible_set() - Called when 'compatible' has been set or unset.
8289 *
8290 * When 'compatible' set: Set all relevant options (those that have the P_VIM)
8291 * flag) to a Vi compatible value.
8292 * When 'compatible' is unset: Set all options that have a different default
8293 * for Vim (without the P_VI_DEF flag) to that default.
8294 */
8295 static void
Bram Moolenaar9b578142016-01-30 19:39:49 +01008296compatible_set(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008297{
8298 int opt_idx;
8299
Bram Moolenaardac13472019-09-16 21:06:21 +02008300 for (opt_idx = 0; !istermoption_idx(opt_idx); opt_idx++)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008301 if ( ((options[opt_idx].flags & P_VIM) && p_cp)
8302 || (!(options[opt_idx].flags & P_VI_DEF) && !p_cp))
8303 set_option_default(opt_idx, OPT_FREE, p_cp);
8304 didset_options();
Bram Moolenaare68c25c2015-08-25 15:39:55 +02008305 didset_options2();
Bram Moolenaar071d4272004-06-13 20:20:40 +00008306}
8307
Bram Moolenaar071d4272004-06-13 20:20:40 +00008308/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008309 * Check if backspacing over something is allowed.
8310 */
8311 int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008312can_bs(
Bram Moolenaaraa0489e2020-04-17 19:41:21 +02008313 int what) // BS_INDENT, BS_EOL, BS_START or BS_NOSTOP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008314{
Bram Moolenaar6b810d92018-06-04 17:28:44 +02008315#ifdef FEAT_JOB_CHANNEL
8316 if (what == BS_START && bt_prompt(curbuf))
8317 return FALSE;
8318#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00008319 switch (*p_bs)
8320 {
Bram Moolenaaraa0489e2020-04-17 19:41:21 +02008321 case '3': return TRUE;
8322 case '2': return (what != BS_NOSTOP);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008323 case '1': return (what != BS_START);
8324 case '0': return FALSE;
8325 }
8326 return vim_strchr(p_bs, what) != NULL;
8327}
8328
8329/*
Bram Moolenaar375e3392019-01-31 18:26:10 +01008330 * Return the effective 'scrolloff' value for the current window, using the
8331 * global value when appropriate.
8332 */
8333 long
8334get_scrolloff_value(void)
8335{
8336 return curwin->w_p_so < 0 ? p_so : curwin->w_p_so;
8337}
8338
8339/*
8340 * Return the effective 'sidescrolloff' value for the current window, using the
8341 * global value when appropriate.
8342 */
8343 long
8344get_sidescrolloff_value(void)
8345{
8346 return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso;
8347}
8348
8349/*
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02008350 * Get the local or global value of 'backupcopy'.
8351 */
8352 unsigned int
Bram Moolenaar9b578142016-01-30 19:39:49 +01008353get_bkc_value(buf_T *buf)
Bram Moolenaarb8ee25a2014-09-23 15:45:08 +02008354{
8355 return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
8356}
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02008357
Dominique Pelle7765f5c2022-04-10 11:26:53 +01008358#if defined(FEAT_LINEBREAK) || defined(PROTO)
Gary Johnson53ba05b2021-07-26 22:19:10 +02008359/*
Christian Brabandtc53b4672022-01-15 10:01:05 +00008360 * Get the local or global value of 'formatlistpat'.
8361 */
8362 char_u *
8363get_flp_value(buf_T *buf)
8364{
Christian Brabandtc53b4672022-01-15 10:01:05 +00008365 if (buf->b_p_flp == NULL || *buf->b_p_flp == NUL)
8366 return p_flp;
8367 return buf->b_p_flp;
8368}
Dominique Pelle7765f5c2022-04-10 11:26:53 +01008369#endif
Christian Brabandtc53b4672022-01-15 10:01:05 +00008370
8371/*
Gary Johnson53ba05b2021-07-26 22:19:10 +02008372 * Get the local or global value of the 'virtualedit' flags.
8373 */
8374 unsigned int
8375get_ve_flags(void)
8376{
Gary Johnson51ad8502021-08-03 18:33:08 +02008377 return (curwin->w_ve_flags ? curwin->w_ve_flags : ve_flags)
8378 & ~(VE_NONE | VE_NONEU);
Gary Johnson53ba05b2021-07-26 22:19:10 +02008379}
8380
Bram Moolenaaree857022019-11-09 23:26:40 +01008381#if defined(FEAT_LINEBREAK) || defined(PROTO)
8382/*
8383 * Get the local or global value of 'showbreak'.
8384 */
8385 char_u *
8386get_showbreak_value(win_T *win)
8387{
8388 if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL)
8389 return p_sbr;
8390 if (STRCMP(win->w_p_sbr, "NONE") == 0)
8391 return empty_option;
8392 return win->w_p_sbr;
8393}
8394#endif
8395
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02008396#if defined(FEAT_EVAL) || defined(PROTO)
8397/*
8398 * Get window or buffer local options.
8399 */
8400 dict_T *
8401get_winbuf_options(int bufopt)
8402{
8403 dict_T *d;
8404 int opt_idx;
8405
8406 d = dict_alloc();
8407 if (d == NULL)
8408 return NULL;
8409
Bram Moolenaardac13472019-09-16 21:06:21 +02008410 for (opt_idx = 0; !istermoption_idx(opt_idx); opt_idx++)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02008411 {
8412 struct vimoption *opt = &options[opt_idx];
8413
8414 if ((bufopt && (opt->indir & PV_BUF))
8415 || (!bufopt && (opt->indir & PV_WIN)))
8416 {
8417 char_u *varp = get_varp(opt);
8418
8419 if (varp != NULL)
8420 {
8421 if (opt->flags & P_STRING)
Bram Moolenaare0be1672018-07-08 16:50:37 +02008422 dict_add_string(d, opt->fullname, *(char_u **)varp);
Bram Moolenaar789a5c02016-09-12 19:51:11 +02008423 else if (opt->flags & P_NUM)
Bram Moolenaare0be1672018-07-08 16:50:37 +02008424 dict_add_number(d, opt->fullname, *(long *)varp);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02008425 else
Bram Moolenaare0be1672018-07-08 16:50:37 +02008426 dict_add_number(d, opt->fullname, *(int *)varp);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02008427 }
8428 }
8429 }
8430
8431 return d;
8432}
8433#endif
Bram Moolenaar017ba072019-09-14 21:01:23 +02008434
Bram Moolenaardac13472019-09-16 21:06:21 +02008435#if defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar017ba072019-09-14 21:01:23 +02008436/*
8437 * This is called when 'culopt' is changed
8438 */
Bram Moolenaardac13472019-09-16 21:06:21 +02008439 int
Bram Moolenaar017ba072019-09-14 21:01:23 +02008440fill_culopt_flags(char_u *val, win_T *wp)
8441{
8442 char_u *p;
8443 char_u culopt_flags_new = 0;
8444
8445 if (val == NULL)
8446 p = wp->w_p_culopt;
8447 else
8448 p = val;
8449 while (*p != NUL)
8450 {
Yee Cheng Chin900894b2023-09-29 20:42:32 +02008451 // Note: Keep this in sync with p_culopt_values.
Bram Moolenaar017ba072019-09-14 21:01:23 +02008452 if (STRNCMP(p, "line", 4) == 0)
8453 {
8454 p += 4;
8455 culopt_flags_new |= CULOPT_LINE;
8456 }
8457 else if (STRNCMP(p, "both", 4) == 0)
8458 {
8459 p += 4;
8460 culopt_flags_new |= CULOPT_LINE | CULOPT_NBR;
8461 }
8462 else if (STRNCMP(p, "number", 6) == 0)
8463 {
8464 p += 6;
8465 culopt_flags_new |= CULOPT_NBR;
8466 }
8467 else if (STRNCMP(p, "screenline", 10) == 0)
8468 {
8469 p += 10;
8470 culopt_flags_new |= CULOPT_SCRLINE;
8471 }
8472
8473 if (*p != ',' && *p != NUL)
8474 return FAIL;
8475 if (*p == ',')
8476 ++p;
8477 }
8478
8479 // Can't have both "line" and "screenline".
8480 if ((culopt_flags_new & CULOPT_LINE) && (culopt_flags_new & CULOPT_SCRLINE))
8481 return FAIL;
8482 wp->w_p_culopt_flags = culopt_flags_new;
8483
8484 return OK;
8485}
8486#endif
Bram Moolenaarf4e20992020-12-21 19:59:08 +01008487
8488/*
8489 * Get the value of 'magic' adjusted for Vim9 script.
8490 */
8491 int
8492magic_isset(void)
8493{
8494 switch (magic_overruled)
8495 {
Bram Moolenaard93a7fc2021-01-04 12:42:13 +01008496 case OPTION_MAGIC_ON: return TRUE;
8497 case OPTION_MAGIC_OFF: return FALSE;
8498 case OPTION_MAGIC_NOT_SET: break;
Bram Moolenaarf4e20992020-12-21 19:59:08 +01008499 }
8500#ifdef FEAT_EVAL
8501 if (in_vim9script())
8502 return TRUE;
8503#endif
8504 return p_magic;
8505}
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008506
8507/*
8508 * Set the callback function value for an option that accepts a function name,
8509 * lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.)
8510 * Returns OK if the option is successfully set to a function, otherwise
8511 * returns FAIL.
8512 */
8513 int
8514option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
8515{
8516#ifdef FEAT_EVAL
8517 typval_T *tv;
8518 callback_T cb;
8519
8520 if (optval == NULL || *optval == NUL)
8521 {
8522 free_callback(optcb);
8523 return OK;
8524 }
8525
Yegappan Lakshmanan05e59e32021-12-01 10:30:07 +00008526 if (*optval == '{' || (in_vim9script() && *optval == '(')
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008527 || (STRNCMP(optval, "function(", 9) == 0)
8528 || (STRNCMP(optval, "funcref(", 8) == 0))
8529 // Lambda expression or a funcref
8530 tv = eval_expr(optval, NULL);
8531 else
8532 // treat everything else as a function name string
Yegappan Lakshmanane7f4abd2021-12-24 20:47:38 +00008533 tv = alloc_string_tv(vim_strsave(optval));
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008534 if (tv == NULL)
8535 return FAIL;
8536
8537 cb = get_callback(tv);
Yegappan Lakshmanan4dc24eb2021-12-07 12:23:57 +00008538 if (cb.cb_name == NULL || *cb.cb_name == NUL)
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008539 {
8540 free_tv(tv);
8541 return FAIL;
8542 }
8543
8544 free_callback(optcb);
8545 set_callback(optcb, &cb);
Bram Moolenaarc96b7f52022-12-02 15:58:38 +00008546 if (cb.cb_free_name)
8547 vim_free(cb.cb_name);
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008548 free_tv(tv);
Bram Moolenaarf0e7e632022-01-21 13:29:56 +00008549
8550 // when using Vim9 style "import.funcname" it needs to be expanded to
8551 // "import#funcname".
8552 expand_autload_callback(optcb);
8553
Yegappan Lakshmanan777175b2021-11-18 22:08:57 +00008554 return OK;
8555#else
8556 return FAIL;
8557#endif
8558}
Christian Brabandt757593c2023-08-22 21:44:10 +02008559
8560#if defined(FEAT_EVAL) || defined(PROTO)
8561 static void
8562didset_options_sctx(int opt_flags, char **buf)
8563{
8564 for (int i = 0; ; ++i)
8565 {
8566 if (buf[i] == NULL)
8567 break;
8568
8569 int idx = findoption((char_u *)buf[i]);
8570 if (idx >= 0)
8571 set_option_sctx_idx(idx, opt_flags, current_sctx);
8572 }
8573}
8574#endif