1 | // This is an open source non-commercial project. Dear PVS-Studio, please check |
2 | // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com |
3 | |
4 | // User-settable options. Checklist for adding a new option: |
5 | // - Put it in options.lua |
6 | // - For a global option: Add a variable for it in option_defs.h. |
7 | // - For a buffer or window local option: |
8 | // - Add a BV_XX or WV_XX entry to option_defs.h |
9 | // - Add a variable to the window or buffer struct in buffer_defs.h. |
10 | // - For a window option, add some code to copy_winopt(). |
11 | // - For a window string option, add code to check_winopt() |
12 | // and clear_winopt(). If setting the option needs parsing, |
13 | // add some code to didset_window_options(). |
14 | // - For a buffer option, add some code to buf_copy_options(). |
15 | // - For a buffer string option, add code to check_buf_options(). |
16 | // - If it's a numeric option, add any necessary bounds checks to |
17 | // set_num_option(). |
18 | // - If it's a list of flags, add some code in do_set(), search for WW_ALL. |
19 | // - When adding an option with expansion (P_EXPAND), but with a different |
20 | // default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP. |
21 | // - Add documentation! doc/options.txt, and any other related places. |
22 | // - Add an entry in runtime/optwin.vim. |
23 | |
24 | #define IN_OPTION_C |
25 | #include <assert.h> |
26 | #include <inttypes.h> |
27 | #include <stdbool.h> |
28 | #include <string.h> |
29 | #include <stdlib.h> |
30 | #include <limits.h> |
31 | |
32 | #include "nvim/vim.h" |
33 | #include "nvim/macros.h" |
34 | #include "nvim/ascii.h" |
35 | #include "nvim/edit.h" |
36 | #include "nvim/option.h" |
37 | #include "nvim/buffer.h" |
38 | #include "nvim/charset.h" |
39 | #include "nvim/cursor.h" |
40 | #include "nvim/diff.h" |
41 | #include "nvim/digraph.h" |
42 | #include "nvim/eval.h" |
43 | #include "nvim/eval/typval.h" |
44 | #include "nvim/ex_cmds2.h" |
45 | #include "nvim/ex_docmd.h" |
46 | #include "nvim/ex_getln.h" |
47 | #include "nvim/fileio.h" |
48 | #include "nvim/fold.h" |
49 | #include "nvim/getchar.h" |
50 | #include "nvim/hardcopy.h" |
51 | #include "nvim/highlight.h" |
52 | #include "nvim/indent_c.h" |
53 | #include "nvim/mbyte.h" |
54 | #include "nvim/memfile.h" |
55 | #include "nvim/memline.h" |
56 | #include "nvim/memory.h" |
57 | #include "nvim/message.h" |
58 | #include "nvim/misc1.h" |
59 | #include "nvim/keymap.h" |
60 | #include "nvim/garray.h" |
61 | #include "nvim/cursor_shape.h" |
62 | #include "nvim/move.h" |
63 | #include "nvim/mouse.h" |
64 | #include "nvim/normal.h" |
65 | #include "nvim/os_unix.h" |
66 | #include "nvim/path.h" |
67 | #include "nvim/popupmnu.h" |
68 | #include "nvim/regexp.h" |
69 | #include "nvim/screen.h" |
70 | #include "nvim/spell.h" |
71 | #include "nvim/spellfile.h" |
72 | #include "nvim/strings.h" |
73 | #include "nvim/syntax.h" |
74 | #include "nvim/ui.h" |
75 | #include "nvim/ui_compositor.h" |
76 | #include "nvim/undo.h" |
77 | #include "nvim/window.h" |
78 | #include "nvim/os/os.h" |
79 | #include "nvim/api/private/helpers.h" |
80 | #include "nvim/os/input.h" |
81 | #include "nvim/os/lang.h" |
82 | |
83 | /* |
84 | * The options that are local to a window or buffer have "indir" set to one of |
85 | * these values. Special values: |
86 | * PV_NONE: global option. |
87 | * PV_WIN is added: window-local option |
88 | * PV_BUF is added: buffer-local option |
89 | * PV_BOTH is added: global option which also has a local value. |
90 | */ |
91 | #define PV_BOTH 0x1000 |
92 | #define PV_WIN 0x2000 |
93 | #define PV_BUF 0x4000 |
94 | #define PV_MASK 0x0fff |
95 | #define OPT_WIN(x) (idopt_T)(PV_WIN + (int)(x)) |
96 | #define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) |
97 | #define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) |
98 | |
99 | |
100 | // WV_ and BV_ values get typecasted to this for the "indir" field |
101 | typedef enum { |
102 | PV_NONE = 0, |
103 | PV_MAXVAL = 0xffff // to avoid warnings for value out of range |
104 | } idopt_T; |
105 | |
106 | /* |
107 | * Options local to a window have a value local to a buffer and global to all |
108 | * buffers. Indicate this by setting "var" to VAR_WIN. |
109 | */ |
110 | #define VAR_WIN ((char_u *)-1) |
111 | |
112 | static char *p_term = NULL; |
113 | static char *p_ttytype = NULL; |
114 | |
115 | /* |
116 | * These are the global values for options which are also local to a buffer. |
117 | * Only to be used in option.c! |
118 | */ |
119 | static int p_ai; |
120 | static int p_bin; |
121 | static int p_bomb; |
122 | static char_u *p_bh; |
123 | static char_u *p_bt; |
124 | static int p_bl; |
125 | static long p_channel; |
126 | static int p_ci; |
127 | static int p_cin; |
128 | static char_u *p_cink; |
129 | static char_u *p_cino; |
130 | static char_u *p_cinw; |
131 | static char_u *p_com; |
132 | static char_u *p_cms; |
133 | static char_u *p_cpt; |
134 | static char_u *p_cfu; |
135 | static char_u *p_ofu; |
136 | static int p_eol; |
137 | static int p_fixeol; |
138 | static int p_et; |
139 | static char_u *p_fenc; |
140 | static char_u *p_ff; |
141 | static char_u *p_fo; |
142 | static char_u *p_flp; |
143 | static char_u *p_ft; |
144 | static long p_iminsert; |
145 | static long p_imsearch; |
146 | static char_u *p_inex; |
147 | static char_u *p_inde; |
148 | static char_u *p_indk; |
149 | static char_u *p_fex; |
150 | static int p_inf; |
151 | static char_u *p_isk; |
152 | static int p_lisp; |
153 | static int p_ml; |
154 | static int p_ma; |
155 | static int p_mod; |
156 | static char_u *p_mps; |
157 | static char_u *p_nf; |
158 | static int p_pi; |
159 | static char_u *p_qe; |
160 | static int p_ro; |
161 | static int p_si; |
162 | static long p_sts; |
163 | static char_u *p_sua; |
164 | static long p_sw; |
165 | static int p_swf; |
166 | static long p_smc; |
167 | static char_u *p_syn; |
168 | static char_u *p_spc; |
169 | static char_u *p_spf; |
170 | static char_u *p_spl; |
171 | static long p_ts; |
172 | static long p_tw; |
173 | static int p_udf; |
174 | static long p_wm; |
175 | static char_u *p_keymap; |
176 | |
177 | // Saved values for when 'bin' is set. |
178 | static int p_et_nobin; |
179 | static int p_ml_nobin; |
180 | static long p_tw_nobin; |
181 | static long p_wm_nobin; |
182 | |
183 | // Saved values for when 'paste' is set. |
184 | static int p_ai_nopaste; |
185 | static int p_et_nopaste; |
186 | static long p_sts_nopaste; |
187 | static long p_tw_nopaste; |
188 | static long p_wm_nopaste; |
189 | |
190 | typedef struct vimoption { |
191 | char *fullname; // full option name |
192 | char *shortname; // permissible abbreviation |
193 | uint32_t flags; // see below |
194 | char_u *var; // global option: pointer to variable; |
195 | // window-local option: VAR_WIN; |
196 | // buffer-local option: global value |
197 | idopt_T indir; // global option: PV_NONE; |
198 | // local option: indirect option index |
199 | char_u *def_val[2]; // default values for variable (vi and vim) |
200 | LastSet last_set; // script in which the option was last set |
201 | # define SCTX_INIT , { 0, 0, 0 } |
202 | } vimoption_T; |
203 | |
204 | #define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value |
205 | #define VIM_DEFAULT 1 // def_val[VIM_DEFAULT] is Vim default value |
206 | |
207 | /* |
208 | * Flags |
209 | */ |
210 | #define P_BOOL 0x01U // the option is boolean |
211 | #define P_NUM 0x02U // the option is numeric |
212 | #define P_STRING 0x04U // the option is a string |
213 | #define P_ALLOCED 0x08U // the string option is in allocated memory, |
214 | // must use free_string_option() when |
215 | // assigning new value. Not set if default is |
216 | // the same. |
217 | #define P_EXPAND 0x10U // environment expansion. NOTE: P_EXPAND can |
218 | // never be used for local or hidden options |
219 | #define P_NODEFAULT 0x40U // don't set to default value |
220 | #define P_DEF_ALLOCED 0x80U // default value is in allocated memory, must |
221 | // use free() when assigning new value |
222 | #define P_WAS_SET 0x100U // option has been set/reset |
223 | #define P_NO_MKRC 0x200U // don't include in :mkvimrc output |
224 | #define P_VI_DEF 0x400U // Use Vi default for Vim |
225 | #define P_VIM 0x800U // Vim option |
226 | |
227 | // when option changed, what to display: |
228 | #define P_RSTAT 0x1000U ///< redraw status lines |
229 | #define P_RWIN 0x2000U ///< redraw current window and recompute text |
230 | #define P_RBUF 0x4000U ///< redraw current buffer and recompute text |
231 | #define P_RALL 0x6000U ///< redraw all windows |
232 | #define P_RCLR 0x7000U ///< clear and redraw all |
233 | |
234 | #define P_COMMA 0x8000U ///< comma separated list |
235 | #define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive |
236 | ///< commas |
237 | #define P_NODUP 0x20000U ///< don't allow duplicate strings |
238 | #define P_FLAGLIST 0x40000U ///< list of single-char flags |
239 | |
240 | #define P_SECURE 0x80000U ///< cannot change in modeline or secure mode |
241 | #define P_GETTEXT 0x100000U ///< expand default value with _() |
242 | #define P_NOGLOB 0x200000U ///< do not use local value for global vimrc |
243 | #define P_NFNAME 0x400000U ///< only normal file name chars allowed |
244 | #define P_INSECURE 0x800000U ///< option was set from a modeline |
245 | #define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option |
246 | ///< has side effects) |
247 | #define P_NO_ML 0x2000000U ///< not allowed in modeline |
248 | #define P_CURSWANT 0x4000000U ///< update curswant required; not needed |
249 | ///< when there is a redraw flag |
250 | #define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value. |
251 | |
252 | #define P_RWINONLY 0x10000000U ///< only redraw current window |
253 | #define P_NDNAME 0x20000000U ///< only normal dir name chars allowed |
254 | #define P_UI_OPTION 0x40000000U ///< send option to remote ui |
255 | #define P_MLE 0x80000000U ///< under control of 'modelineexpr' |
256 | |
257 | #define HIGHLIGHT_INIT \ |
258 | "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ |
259 | "d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr," \ |
260 | "N:CursorLineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title," \ |
261 | "v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn," \ |
262 | "A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal," \ |
263 | "B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \ |
264 | "x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill," \ |
265 | "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine," \ |
266 | "0:Whitespace,I:NormalNC" |
267 | |
268 | /* |
269 | * options[] is initialized here. |
270 | * The order of the options MUST be alphabetic for ":set all" and findoption(). |
271 | * All option names MUST start with a lowercase letter (for findoption()). |
272 | * Exception: "t_" options are at the end. |
273 | * The options with a NULL variable are 'hidden': a set command for them is |
274 | * ignored and they are not printed. |
275 | */ |
276 | |
277 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
278 | # include "options.generated.h" |
279 | #endif |
280 | |
281 | #define PARAM_COUNT ARRAY_SIZE(options) |
282 | |
283 | static char *(p_ambw_values[]) = { "single" , "double" , NULL }; |
284 | static char *(p_bg_values[]) = { "light" , "dark" , NULL }; |
285 | static char *(p_nf_values[]) = { "bin" , "octal" , "hex" , "alpha" , NULL }; |
286 | static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL }; |
287 | static char *(p_wak_values[]) = { "yes" , "menu" , "no" , NULL }; |
288 | static char *(p_mousem_values[]) = { "extend" , "popup" , "popup_setpos" , |
289 | "mac" , NULL }; |
290 | static char *(p_sel_values[]) = { "inclusive" , "exclusive" , "old" , NULL }; |
291 | static char *(p_slm_values[]) = { "mouse" , "key" , "cmd" , NULL }; |
292 | static char *(p_km_values[]) = { "startsel" , "stopsel" , NULL }; |
293 | static char *(p_scbopt_values[]) = { "ver" , "hor" , "jump" , NULL }; |
294 | static char *(p_debug_values[]) = { "msg" , "throw" , "beep" , NULL }; |
295 | static char *(p_ead_values[]) = { "both" , "ver" , "hor" , NULL }; |
296 | static char *(p_buftype_values[]) = { "nofile" , "nowrite" , "quickfix" , |
297 | "help" , "acwrite" , "terminal" , NULL }; |
298 | |
299 | static char *(p_bufhidden_values[]) = { "hide" , "unload" , "delete" , |
300 | "wipe" , NULL }; |
301 | static char *(p_bs_values[]) = { "indent" , "eol" , "start" , NULL }; |
302 | static char *(p_fdm_values[]) = { "manual" , "expr" , "marker" , "indent" , |
303 | "syntax" , "diff" , NULL }; |
304 | static char *(p_fcl_values[]) = { "all" , NULL }; |
305 | static char *(p_cot_values[]) = { "menu" , "menuone" , "longest" , "preview" , |
306 | "noinsert" , "noselect" , NULL }; |
307 | static char *(p_icm_values[]) = { "nosplit" , "split" , NULL }; |
308 | static char *(p_scl_values[]) = { "yes" , "no" , "auto" , "auto:1" , "auto:2" , |
309 | "auto:3" , "auto:4" , "auto:5" , "auto:6" , "auto:7" , "auto:8" , "auto:9" , |
310 | "yes:1" , "yes:2" , "yes:3" , "yes:4" , "yes:5" , "yes:6" , "yes:7" , "yes:8" , |
311 | "yes:9" , NULL }; |
312 | |
313 | /// All possible flags for 'shm'. |
314 | static char_u SHM_ALL[] = { |
315 | SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, |
316 | SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, |
317 | SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU, |
318 | SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT, |
319 | 0, |
320 | }; |
321 | |
322 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
323 | # include "option.c.generated.h" |
324 | #endif |
325 | |
326 | /// Append string with escaped commas |
327 | static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len) |
328 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT |
329 | { |
330 | size_t shift = 0; |
331 | for (size_t i = 0; i < len; i++) { |
332 | if (src[i] == ',') { |
333 | dest[i + shift++] = '\\'; |
334 | } |
335 | dest[i + shift] = src[i]; |
336 | } |
337 | return &dest[len + shift]; |
338 | } |
339 | |
340 | /// Compute length of a colon-separated value, doubled and with some suffixes |
341 | /// |
342 | /// @param[in] val Colon-separated array value. |
343 | /// @param[in] common_suf_len Length of the common suffix which is appended to |
344 | /// each item in the array, twice. |
345 | /// @param[in] single_suf_len Length of the suffix which is appended to each |
346 | /// item in the array once. |
347 | /// |
348 | /// @return Length of the comma-separated string array that contains each item |
349 | /// in the original array twice with suffixes with given length |
350 | /// (common_suf is present after each new item, single_suf is present |
351 | /// after half of the new items) and with commas after each item, commas |
352 | /// inside the values are escaped. |
353 | static inline size_t compute_double_colon_len(const char *const val, |
354 | const size_t common_suf_len, |
355 | const size_t single_suf_len) |
356 | FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE |
357 | { |
358 | if (val == NULL || *val == NUL) { |
359 | return 0; |
360 | } |
361 | size_t ret = 0; |
362 | const void *iter = NULL; |
363 | do { |
364 | size_t dir_len; |
365 | const char *dir; |
366 | iter = vim_env_iter(':', val, iter, &dir, &dir_len); |
367 | if (dir != NULL && dir_len > 0) { |
368 | ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len |
369 | + !after_pathsep(dir, dir + dir_len)) * 2 |
370 | + single_suf_len); |
371 | } |
372 | } while (iter != NULL); |
373 | return ret; |
374 | } |
375 | |
376 | #define NVIM_SIZE (sizeof("nvim") - 1) |
377 | |
378 | /// Add directories to a comma-separated array from a colon-separated one |
379 | /// |
380 | /// Commas are escaped in process. To each item PATHSEP "nvim" is appended in |
381 | /// addition to suf1 and suf2. |
382 | /// |
383 | /// @param[in,out] dest Destination comma-separated array. |
384 | /// @param[in] val Source colon-separated array. |
385 | /// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it |
386 | /// directory separator is appended. Suffix must not contain |
387 | /// commas. |
388 | /// @param[in] len1 Length of the suf1. |
389 | /// @param[in] suf2 If not NULL, another suffix appended to destination. Again |
390 | /// with directory separator behind. Suffix must not contain |
391 | /// commas. |
392 | /// @param[in] len2 Length of the suf2. |
393 | /// @param[in] forward If true, iterate over val in forward direction. |
394 | /// Otherwise in reverse. |
395 | /// |
396 | /// @return (dest + appended_characters_length) |
397 | static inline char *add_colon_dirs(char *dest, const char *const val, |
398 | const char *const suf1, const size_t len1, |
399 | const char *const suf2, const size_t len2, |
400 | const bool forward) |
401 | FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) |
402 | { |
403 | if (val == NULL || *val == NUL) { |
404 | return dest; |
405 | } |
406 | const void *iter = NULL; |
407 | do { |
408 | size_t dir_len; |
409 | const char *dir; |
410 | iter = (forward ? vim_env_iter : vim_env_iter_rev)(':', val, iter, &dir, |
411 | &dir_len); |
412 | if (dir != NULL && dir_len > 0) { |
413 | dest = strcpy_comma_escaped(dest, dir, dir_len); |
414 | if (!after_pathsep(dest - 1, dest)) { |
415 | *dest++ = PATHSEP; |
416 | } |
417 | memmove(dest, "nvim" , NVIM_SIZE); |
418 | dest += NVIM_SIZE; |
419 | if (suf1 != NULL) { |
420 | *dest++ = PATHSEP; |
421 | memmove(dest, suf1, len1); |
422 | dest += len1; |
423 | if (suf2 != NULL) { |
424 | *dest++ = PATHSEP; |
425 | memmove(dest, suf2, len2); |
426 | dest += len2; |
427 | } |
428 | } |
429 | *dest++ = ','; |
430 | } |
431 | } while (iter != NULL); |
432 | return dest; |
433 | } |
434 | |
435 | /// Adds directory `dest` to a comma-separated list of directories. |
436 | /// |
437 | /// Commas in the added directory are escaped. |
438 | /// |
439 | /// Windows: Appends "nvim-data" instead of "nvim" if `type` is kXDGDataHome. |
440 | /// |
441 | /// @see get_xdg_home |
442 | /// |
443 | /// @param[in,out] dest Destination comma-separated array. |
444 | /// @param[in] dir Directory to append. |
445 | /// @param[in] type Decides whether to append "nvim" (Win: or "nvim-data"). |
446 | /// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it |
447 | /// directory separator is appended. Suffix must not contain |
448 | /// commas. |
449 | /// @param[in] len1 Length of the suf1. |
450 | /// @param[in] suf2 If not NULL, another suffix appended to destination. Again |
451 | /// with directory separator behind. Suffix must not contain |
452 | /// commas. |
453 | /// @param[in] len2 Length of the suf2. |
454 | /// @param[in] forward If true, iterate over val in forward direction. |
455 | /// Otherwise in reverse. |
456 | /// |
457 | /// @return (dest + appended_characters_length) |
458 | static inline char *add_dir(char *dest, const char *const dir, |
459 | const size_t dir_len, const XDGVarType type, |
460 | const char *const suf1, const size_t len1, |
461 | const char *const suf2, const size_t len2) |
462 | FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT |
463 | { |
464 | if (dir == NULL || dir_len == 0) { |
465 | return dest; |
466 | } |
467 | dest = strcpy_comma_escaped(dest, dir, dir_len); |
468 | bool append_nvim = (type == kXDGDataHome || type == kXDGConfigHome); |
469 | if (append_nvim) { |
470 | if (!after_pathsep(dest - 1, dest)) { |
471 | *dest++ = PATHSEP; |
472 | } |
473 | #if defined(WIN32) |
474 | size_t size = (type == kXDGDataHome ? sizeof("nvim-data" ) - 1 : NVIM_SIZE); |
475 | memmove(dest, (type == kXDGDataHome ? "nvim-data" : "nvim" ), size); |
476 | dest += size; |
477 | #else |
478 | memmove(dest, "nvim" , NVIM_SIZE); |
479 | dest += NVIM_SIZE; |
480 | #endif |
481 | if (suf1 != NULL) { |
482 | *dest++ = PATHSEP; |
483 | memmove(dest, suf1, len1); |
484 | dest += len1; |
485 | if (suf2 != NULL) { |
486 | *dest++ = PATHSEP; |
487 | memmove(dest, suf2, len2); |
488 | dest += len2; |
489 | } |
490 | } |
491 | } |
492 | *dest++ = ','; |
493 | return dest; |
494 | } |
495 | |
496 | /// Sets &runtimepath to default value. |
497 | /// |
498 | /// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing |
499 | /// configuration and data files in the same path. #4403 |
500 | static void set_runtimepath_default(void) |
501 | { |
502 | size_t rtp_size = 0; |
503 | char *const data_home = stdpaths_get_xdg_var(kXDGDataHome); |
504 | char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome); |
505 | char *const vimruntime = vim_getenv("VIMRUNTIME" ); |
506 | char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs); |
507 | char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); |
508 | #define SITE_SIZE (sizeof("site") - 1) |
509 | #define AFTER_SIZE (sizeof("after") - 1) |
510 | size_t data_len = 0; |
511 | size_t config_len = 0; |
512 | size_t vimruntime_len = 0; |
513 | if (data_home != NULL) { |
514 | data_len = strlen(data_home); |
515 | if (data_len != 0) { |
516 | #if defined(WIN32) |
517 | size_t nvim_size = (sizeof("nvim-data" ) - 1); |
518 | #else |
519 | size_t nvim_size = NVIM_SIZE; |
520 | #endif |
521 | rtp_size += ((data_len + memcnt(data_home, ',', data_len) |
522 | + nvim_size + 1 + SITE_SIZE + 1 |
523 | + !after_pathsep(data_home, data_home + data_len)) * 2 |
524 | + AFTER_SIZE + 1); |
525 | } |
526 | } |
527 | if (config_home != NULL) { |
528 | config_len = strlen(config_home); |
529 | if (config_len != 0) { |
530 | rtp_size += ((config_len + memcnt(config_home, ',', config_len) |
531 | + NVIM_SIZE + 1 |
532 | + !after_pathsep(config_home, config_home + config_len)) * 2 |
533 | + AFTER_SIZE + 1); |
534 | } |
535 | } |
536 | if (vimruntime != NULL) { |
537 | vimruntime_len = strlen(vimruntime); |
538 | if (vimruntime_len != 0) { |
539 | rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1; |
540 | } |
541 | } |
542 | rtp_size += compute_double_colon_len(data_dirs, NVIM_SIZE + 1 + SITE_SIZE + 1, |
543 | AFTER_SIZE + 1); |
544 | rtp_size += compute_double_colon_len(config_dirs, NVIM_SIZE + 1, |
545 | AFTER_SIZE + 1); |
546 | if (rtp_size == 0) { |
547 | return; |
548 | } |
549 | char *const rtp = xmalloc(rtp_size); |
550 | char *rtp_cur = rtp; |
551 | rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome, |
552 | NULL, 0, NULL, 0); |
553 | rtp_cur = add_colon_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true); |
554 | rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome, |
555 | "site" , SITE_SIZE, NULL, 0); |
556 | rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site" , SITE_SIZE, NULL, 0, |
557 | true); |
558 | rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone, |
559 | NULL, 0, NULL, 0); |
560 | rtp_cur = add_colon_dirs(rtp_cur, data_dirs, "site" , SITE_SIZE, |
561 | "after" , AFTER_SIZE, false); |
562 | rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome, |
563 | "site" , SITE_SIZE, "after" , AFTER_SIZE); |
564 | rtp_cur = add_colon_dirs(rtp_cur, config_dirs, "after" , AFTER_SIZE, NULL, 0, |
565 | false); |
566 | rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome, |
567 | "after" , AFTER_SIZE, NULL, 0); |
568 | // Strip trailing comma. |
569 | rtp_cur[-1] = NUL; |
570 | assert((size_t) (rtp_cur - rtp) == rtp_size); |
571 | #undef SITE_SIZE |
572 | #undef AFTER_SIZE |
573 | set_string_default("runtimepath" , rtp, true); |
574 | // Make a copy of 'rtp' for 'packpath' |
575 | set_string_default("packpath" , rtp, false); |
576 | xfree(data_dirs); |
577 | xfree(config_dirs); |
578 | xfree(data_home); |
579 | xfree(config_home); |
580 | xfree(vimruntime); |
581 | } |
582 | |
583 | #undef NVIM_SIZE |
584 | |
585 | /* |
586 | * Initialize the options, first part. |
587 | * |
588 | * Called only once from main(), just after creating the first buffer. |
589 | */ |
590 | void set_init_1(void) |
591 | { |
592 | int opt_idx; |
593 | |
594 | langmap_init(); |
595 | |
596 | // Be nocompatible |
597 | p_cp = false; |
598 | |
599 | /* |
600 | * Find default value for 'shell' option. |
601 | * Don't use it if it is empty. |
602 | */ |
603 | { |
604 | const char *shell = os_getenv("SHELL" ); |
605 | if (shell != NULL) { |
606 | set_string_default("sh" , (char *) shell, false); |
607 | } |
608 | } |
609 | |
610 | /* |
611 | * Set the default for 'backupskip' to include environment variables for |
612 | * temp files. |
613 | */ |
614 | { |
615 | # ifdef UNIX |
616 | static char *(names[4]) = {"" , "TMPDIR" , "TEMP" , "TMP" }; |
617 | # else |
618 | static char *(names[3]) = {"TMPDIR" , "TEMP" , "TMP" }; |
619 | # endif |
620 | int len; |
621 | garray_T ga; |
622 | |
623 | ga_init(&ga, 1, 100); |
624 | for (size_t n = 0; n < ARRAY_SIZE(names); n++) { |
625 | bool mustfree = true; |
626 | char *p; |
627 | # ifdef UNIX |
628 | if (*names[n] == NUL) { |
629 | # ifdef __APPLE__ |
630 | p = "/private/tmp" ; |
631 | # else |
632 | p = "/tmp" ; |
633 | # endif |
634 | mustfree = false; |
635 | } else |
636 | # endif |
637 | { |
638 | p = vim_getenv(names[n]); |
639 | } |
640 | if (p != NULL && *p != NUL) { |
641 | // First time count the NUL, otherwise count the ','. |
642 | len = (int)strlen(p) + 3; |
643 | ga_grow(&ga, len); |
644 | if (!GA_EMPTY(&ga)) { |
645 | STRCAT(ga.ga_data, "," ); |
646 | } |
647 | STRCAT(ga.ga_data, p); |
648 | add_pathsep(ga.ga_data); |
649 | STRCAT(ga.ga_data, "*" ); |
650 | ga.ga_len += len; |
651 | } |
652 | if(mustfree) { |
653 | xfree(p); |
654 | } |
655 | } |
656 | if (ga.ga_data != NULL) { |
657 | set_string_default("bsk" , ga.ga_data, true); |
658 | } |
659 | } |
660 | |
661 | { |
662 | char_u *cdpath; |
663 | char_u *buf; |
664 | int i; |
665 | int j; |
666 | |
667 | // Initialize the 'cdpath' option's default value. |
668 | cdpath = (char_u *)vim_getenv("CDPATH" ); |
669 | if (cdpath != NULL) { |
670 | buf = xmalloc(2 * STRLEN(cdpath) + 2); |
671 | { |
672 | buf[0] = ','; // start with ",", current dir first |
673 | j = 1; |
674 | for (i = 0; cdpath[i] != NUL; i++) { |
675 | if (vim_ispathlistsep(cdpath[i])) { |
676 | buf[j++] = ','; |
677 | } else { |
678 | if (cdpath[i] == ' ' || cdpath[i] == ',') { |
679 | buf[j++] = '\\'; |
680 | } |
681 | buf[j++] = cdpath[i]; |
682 | } |
683 | } |
684 | buf[j] = NUL; |
685 | opt_idx = findoption("cdpath" ); |
686 | if (opt_idx >= 0) { |
687 | options[opt_idx].def_val[VI_DEFAULT] = buf; |
688 | options[opt_idx].flags |= P_DEF_ALLOCED; |
689 | } else { |
690 | xfree(buf); // cannot happen |
691 | } |
692 | } |
693 | xfree(cdpath); |
694 | } |
695 | } |
696 | |
697 | #if defined(MSWIN) || defined(MAC) |
698 | // Set print encoding on platforms that don't default to latin1 |
699 | set_string_default("printencoding" , "hp-roman8" , false); |
700 | #endif |
701 | |
702 | // 'printexpr' must be allocated to be able to evaluate it. |
703 | set_string_default("printexpr" , |
704 | #ifdef UNIX |
705 | "system(['lpr'] " |
706 | "+ (empty(&printdevice)?[]:['-P', &printdevice]) " |
707 | "+ [v:fname_in])" |
708 | ". delete(v:fname_in)" |
709 | "+ v:shell_error" , |
710 | #elif defined(MSWIN) |
711 | "system(['copy', v:fname_in, " |
712 | "empty(&printdevice)?'LPT1':&printdevice])" |
713 | ". delete(v:fname_in)" , |
714 | #else |
715 | "" , |
716 | #endif |
717 | false); |
718 | |
719 | char *backupdir = stdpaths_user_data_subpath("backup" , 0, true); |
720 | const size_t backupdir_len = strlen(backupdir); |
721 | backupdir = xrealloc(backupdir, backupdir_len + 3); |
722 | memmove(backupdir + 2, backupdir, backupdir_len + 1); |
723 | memmove(backupdir, ".," , 2); |
724 | set_string_default("viewdir" , stdpaths_user_data_subpath("view" , 0, true), |
725 | true); |
726 | set_string_default("backupdir" , backupdir, true); |
727 | set_string_default("directory" , stdpaths_user_data_subpath("swap" , 2, true), |
728 | true); |
729 | set_string_default("undodir" , stdpaths_user_data_subpath("undo" , 0, true), |
730 | true); |
731 | // Set default for &runtimepath. All necessary expansions are performed in |
732 | // this function. |
733 | set_runtimepath_default(); |
734 | |
735 | /* |
736 | * Set all the options (except the terminal options) to their default |
737 | * value. Also set the global value for local options. |
738 | */ |
739 | set_options_default(0); |
740 | |
741 | |
742 | curbuf->b_p_initialized = true; |
743 | curbuf->b_p_ar = -1; // no local 'autoread' value |
744 | curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL; |
745 | check_buf_options(curbuf); |
746 | check_win_options(curwin); |
747 | check_options(); |
748 | |
749 | // Set all options to their Vim default |
750 | set_options_default(OPT_FREE); |
751 | |
752 | // set 'laststatus' |
753 | last_status(false); |
754 | |
755 | // Must be before option_expand(), because that one needs vim_isIDc() |
756 | didset_options(); |
757 | |
758 | // Use the current chartab for the generic chartab. This is not in |
759 | // didset_options() because it only depends on 'encoding'. |
760 | init_spell_chartab(); |
761 | |
762 | /* |
763 | * Expand environment variables and things like "~" for the defaults. |
764 | * If option_expand() returns non-NULL the variable is expanded. This can |
765 | * only happen for non-indirect options. |
766 | * Also set the default to the expanded value, so ":set" does not list |
767 | * them. |
768 | * Don't set the P_ALLOCED flag, because we don't want to free the |
769 | * default. |
770 | */ |
771 | for (opt_idx = 0; options[opt_idx].fullname; opt_idx++) { |
772 | if (options[opt_idx].flags & P_NO_DEF_EXP) { |
773 | continue; |
774 | } |
775 | char *p; |
776 | if ((options[opt_idx].flags & P_GETTEXT) |
777 | && options[opt_idx].var != NULL) { |
778 | p = _(*(char **)options[opt_idx].var); |
779 | } else { |
780 | p = (char *) option_expand(opt_idx, NULL); |
781 | } |
782 | if (p != NULL) { |
783 | p = xstrdup(p); |
784 | *(char **)options[opt_idx].var = p; |
785 | /* VIMEXP |
786 | * Defaults for all expanded options are currently the same for Vi |
787 | * and Vim. When this changes, add some code here! Also need to |
788 | * split P_DEF_ALLOCED in two. |
789 | */ |
790 | if (options[opt_idx].flags & P_DEF_ALLOCED) { |
791 | xfree(options[opt_idx].def_val[VI_DEFAULT]); |
792 | } |
793 | options[opt_idx].def_val[VI_DEFAULT] = (char_u *)p; |
794 | options[opt_idx].flags |= P_DEF_ALLOCED; |
795 | } |
796 | } |
797 | |
798 | save_file_ff(curbuf); // Buffer is unchanged |
799 | |
800 | /* Detect use of mlterm. |
801 | * Mlterm is a terminal emulator akin to xterm that has some special |
802 | * abilities (bidi namely). |
803 | * NOTE: mlterm's author is being asked to 'set' a variable |
804 | * instead of an environment variable due to inheritance. |
805 | */ |
806 | if (os_env_exists("MLTERM" )) { |
807 | set_option_value("tbidi" , 1L, NULL, 0); |
808 | } |
809 | |
810 | didset_options2(); |
811 | |
812 | lang_init(); |
813 | |
814 | // enc_locale() will try to find the encoding of the current locale. |
815 | // This will be used when 'default' is used as encoding specifier |
816 | // in 'fileencodings' |
817 | char_u *p = enc_locale(); |
818 | if (p == NULL) { |
819 | // use utf-8 as 'default' if locale encoding can't be detected. |
820 | p = (char_u *)xmemdupz(S_LEN("utf-8" )); |
821 | } |
822 | fenc_default = p; |
823 | |
824 | #ifdef HAVE_WORKING_LIBINTL |
825 | // GNU gettext 0.10.37 supports this feature: set the codeset used for |
826 | // translated messages independently from the current locale. |
827 | (void)bind_textdomain_codeset(PROJECT_NAME, (char *)p_enc); |
828 | #endif |
829 | |
830 | // Set the default for 'helplang'. |
831 | set_helplang_default(get_mess_lang()); |
832 | } |
833 | |
834 | /* |
835 | * Set an option to its default value. |
836 | * This does not take care of side effects! |
837 | */ |
838 | static void |
839 | set_option_default( |
840 | int opt_idx, |
841 | int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL |
842 | int compatible // use Vi default value |
843 | ) |
844 | { |
845 | char_u *varp; // pointer to variable for current option |
846 | int dvi; // index in def_val[] |
847 | int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; |
848 | |
849 | varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags); |
850 | uint32_t flags = options[opt_idx].flags; |
851 | if (varp != NULL) { // skip hidden option, nothing to do for it |
852 | dvi = ((flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT; |
853 | if (flags & P_STRING) { |
854 | /* Use set_string_option_direct() for local options to handle |
855 | * freeing and allocating the value. */ |
856 | if (options[opt_idx].indir != PV_NONE) { |
857 | set_string_option_direct(NULL, opt_idx, |
858 | options[opt_idx].def_val[dvi], opt_flags, 0); |
859 | } else { |
860 | if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) { |
861 | free_string_option(*(char_u **)(varp)); |
862 | } |
863 | *(char_u **)varp = options[opt_idx].def_val[dvi]; |
864 | options[opt_idx].flags &= ~P_ALLOCED; |
865 | } |
866 | } else if (flags & P_NUM) { |
867 | if (options[opt_idx].indir == PV_SCROLL) { |
868 | win_comp_scroll(curwin); |
869 | } else { |
870 | *(long *)varp = (long)(intptr_t)options[opt_idx].def_val[dvi]; |
871 | // May also set global value for local option. |
872 | if (both) { |
873 | *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = |
874 | *(long *)varp; |
875 | } |
876 | } |
877 | } else { // P_BOOL |
878 | *(int *)varp = (int)(intptr_t)options[opt_idx].def_val[dvi]; |
879 | #ifdef UNIX |
880 | // 'modeline' defaults to off for root |
881 | if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID) { |
882 | *(int *)varp = false; |
883 | } |
884 | #endif |
885 | // May also set global value for local option. |
886 | if (both) { |
887 | *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = |
888 | *(int *)varp; |
889 | } |
890 | } |
891 | |
892 | // The default value is not insecure. |
893 | uint32_t *flagsp = insecure_flag(opt_idx, opt_flags); |
894 | *flagsp = *flagsp & ~P_INSECURE; |
895 | } |
896 | |
897 | set_option_sctx_idx(opt_idx, opt_flags, current_sctx); |
898 | } |
899 | |
900 | /* |
901 | * Set all options (except terminal options) to their default value. |
902 | */ |
903 | static void |
904 | set_options_default( |
905 | int opt_flags // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL |
906 | ) |
907 | { |
908 | for (int i = 0; options[i].fullname; i++) { |
909 | if (!(options[i].flags & P_NODEFAULT)) { |
910 | set_option_default(i, opt_flags, p_cp); |
911 | } |
912 | } |
913 | |
914 | // The 'scroll' option must be computed for all windows. |
915 | FOR_ALL_TAB_WINDOWS(tp, wp) { |
916 | win_comp_scroll(wp); |
917 | } |
918 | |
919 | parse_cino(curbuf); |
920 | } |
921 | |
922 | /// Set the Vi-default value of a string option. |
923 | /// Used for 'sh', 'backupskip' and 'term'. |
924 | /// |
925 | /// @param name The name of the option |
926 | /// @param val The value of the option |
927 | /// @param allocated If true, do not copy default as it was already allocated. |
928 | static void set_string_default(const char *name, char *val, bool allocated) |
929 | FUNC_ATTR_NONNULL_ALL |
930 | { |
931 | int opt_idx = findoption(name); |
932 | if (opt_idx >= 0) { |
933 | if (options[opt_idx].flags & P_DEF_ALLOCED) { |
934 | xfree(options[opt_idx].def_val[VI_DEFAULT]); |
935 | } |
936 | |
937 | options[opt_idx].def_val[VI_DEFAULT] = (char_u *) ( |
938 | allocated |
939 | ? (char_u *) val |
940 | : (char_u *) xstrdup(val)); |
941 | options[opt_idx].flags |= P_DEF_ALLOCED; |
942 | } |
943 | } |
944 | |
945 | /* |
946 | * Set the Vi-default value of a number option. |
947 | * Used for 'lines' and 'columns'. |
948 | */ |
949 | void set_number_default(char *name, long val) |
950 | { |
951 | int opt_idx; |
952 | |
953 | opt_idx = findoption(name); |
954 | if (opt_idx >= 0) { |
955 | options[opt_idx].def_val[VI_DEFAULT] = (char_u *)(intptr_t)val; |
956 | } |
957 | } |
958 | |
959 | #if defined(EXITFREE) |
960 | /// Free all options. |
961 | void free_all_options(void) |
962 | { |
963 | for (int i = 0; options[i].fullname; i++) { |
964 | if (options[i].indir == PV_NONE) { |
965 | // global option: free value and default value. |
966 | if ((options[i].flags & P_ALLOCED) && options[i].var != NULL) { |
967 | free_string_option(*(char_u **)options[i].var); |
968 | } |
969 | if (options[i].flags & P_DEF_ALLOCED) { |
970 | free_string_option(options[i].def_val[VI_DEFAULT]); |
971 | } |
972 | } else if (options[i].var != VAR_WIN && (options[i].flags & P_STRING)) { |
973 | // buffer-local option: free global value |
974 | free_string_option(*(char_u **)options[i].var); |
975 | } |
976 | } |
977 | } |
978 | #endif |
979 | |
980 | |
981 | /// Initialize the options, part two: After getting Rows and Columns. |
982 | void set_init_2(bool headless) |
983 | { |
984 | int idx; |
985 | |
986 | // 'scroll' defaults to half the window height. The stored default is zero, |
987 | // which results in the actual value computed from the window height. |
988 | idx = findoption("scroll" ); |
989 | if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { |
990 | set_option_default(idx, OPT_LOCAL, p_cp); |
991 | } |
992 | comp_col(); |
993 | |
994 | /* |
995 | * 'window' is only for backwards compatibility with Vi. |
996 | * Default is Rows - 1. |
997 | */ |
998 | if (!option_was_set("window" )) { |
999 | p_window = Rows - 1; |
1000 | } |
1001 | set_number_default("window" , Rows - 1); |
1002 | (void)parse_printoptions(); // parse 'printoptions' default value |
1003 | } |
1004 | |
1005 | /// Initialize the options, part three: After reading the .vimrc |
1006 | void set_init_3(void) |
1007 | { |
1008 | parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor' |
1009 | |
1010 | // Set 'shellpipe' and 'shellredir', depending on the 'shell' option. |
1011 | // This is done after other initializations, where 'shell' might have been |
1012 | // set, but only if they have not been set before. |
1013 | int idx_srr = findoption("srr" ); |
1014 | int do_srr = (idx_srr < 0) |
1015 | ? false |
1016 | : !(options[idx_srr].flags & P_WAS_SET); |
1017 | int idx_sp = findoption("sp" ); |
1018 | int do_sp = (idx_sp < 0) |
1019 | ? false |
1020 | : !(options[idx_sp].flags & P_WAS_SET); |
1021 | |
1022 | size_t len = 0; |
1023 | char_u *p = (char_u *)invocation_path_tail(p_sh, &len); |
1024 | p = vim_strnsave(p, len); |
1025 | |
1026 | { |
1027 | // |
1028 | // Default for p_sp is "| tee", for p_srr is ">". |
1029 | // For known shells it is changed here to include stderr. |
1030 | // |
1031 | if ( fnamecmp(p, "csh" ) == 0 |
1032 | || fnamecmp(p, "tcsh" ) == 0 |
1033 | ) { |
1034 | if (do_sp) { |
1035 | p_sp = (char_u *)"|& tee" ; |
1036 | options[idx_sp].def_val[VI_DEFAULT] = p_sp; |
1037 | } |
1038 | if (do_srr) { |
1039 | p_srr = (char_u *)">&" ; |
1040 | options[idx_srr].def_val[VI_DEFAULT] = p_srr; |
1041 | } |
1042 | } else if ( fnamecmp(p, "sh" ) == 0 |
1043 | || fnamecmp(p, "ksh" ) == 0 |
1044 | || fnamecmp(p, "mksh" ) == 0 |
1045 | || fnamecmp(p, "pdksh" ) == 0 |
1046 | || fnamecmp(p, "zsh" ) == 0 |
1047 | || fnamecmp(p, "zsh-beta" ) == 0 |
1048 | || fnamecmp(p, "bash" ) == 0 |
1049 | || fnamecmp(p, "fish" ) == 0 |
1050 | ) { |
1051 | if (do_sp) { |
1052 | p_sp = (char_u *)"2>&1| tee" ; |
1053 | options[idx_sp].def_val[VI_DEFAULT] = p_sp; |
1054 | } |
1055 | if (do_srr) { |
1056 | p_srr = (char_u *)">%s 2>&1" ; |
1057 | options[idx_srr].def_val[VI_DEFAULT] = p_srr; |
1058 | } |
1059 | } |
1060 | xfree(p); |
1061 | } |
1062 | |
1063 | if (BUFEMPTY()) { |
1064 | int idx_ffs = findoption_len(S_LEN("ffs" )); |
1065 | |
1066 | // Apply the first entry of 'fileformats' to the initial buffer. |
1067 | if (idx_ffs >= 0 && (options[idx_ffs].flags & P_WAS_SET)) { |
1068 | set_fileformat(default_fileformat(), OPT_LOCAL); |
1069 | } |
1070 | } |
1071 | |
1072 | set_title_defaults(); // 'title', 'icon' |
1073 | } |
1074 | |
1075 | /* |
1076 | * When 'helplang' is still at its default value, set it to "lang". |
1077 | * Only the first two characters of "lang" are used. |
1078 | */ |
1079 | void set_helplang_default(const char *lang) |
1080 | { |
1081 | if (lang == NULL) { |
1082 | return; |
1083 | } |
1084 | |
1085 | const size_t lang_len = strlen(lang); |
1086 | if (lang_len < 2) { // safety check |
1087 | return; |
1088 | } |
1089 | int idx = findoption("hlg" ); |
1090 | if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { |
1091 | if (options[idx].flags & P_ALLOCED) { |
1092 | free_string_option(p_hlg); |
1093 | } |
1094 | p_hlg = (char_u *)xmemdupz(lang, lang_len); |
1095 | // zh_CN becomes "cn", zh_TW becomes "tw". |
1096 | if (STRNICMP(p_hlg, "zh_" , 3) == 0 && STRLEN(p_hlg) >= 5) { |
1097 | p_hlg[0] = (char_u)TOLOWER_ASC(p_hlg[3]); |
1098 | p_hlg[1] = (char_u)TOLOWER_ASC(p_hlg[4]); |
1099 | } else if (STRLEN(p_hlg) >= 1 && *p_hlg == 'C') { |
1100 | // any C like setting, such as C.UTF-8, becomes "en" |
1101 | p_hlg[0] = 'e'; |
1102 | p_hlg[1] = 'n'; |
1103 | } |
1104 | p_hlg[2] = NUL; |
1105 | options[idx].flags |= P_ALLOCED; |
1106 | } |
1107 | } |
1108 | |
1109 | |
1110 | /* |
1111 | * 'title' and 'icon' only default to true if they have not been set or reset |
1112 | * in .vimrc and we can read the old value. |
1113 | * When 'title' and 'icon' have been reset in .vimrc, we won't even check if |
1114 | * they can be reset. This reduces startup time when using X on a remote |
1115 | * machine. |
1116 | */ |
1117 | void set_title_defaults(void) |
1118 | { |
1119 | int idx1; |
1120 | |
1121 | /* |
1122 | * If GUI is (going to be) used, we can always set the window title and |
1123 | * icon name. Saves a bit of time, because the X11 display server does |
1124 | * not need to be contacted. |
1125 | */ |
1126 | idx1 = findoption("title" ); |
1127 | if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { |
1128 | options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0; |
1129 | p_title = 0; |
1130 | } |
1131 | idx1 = findoption("icon" ); |
1132 | if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) { |
1133 | options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0; |
1134 | p_icon = 0; |
1135 | } |
1136 | } |
1137 | |
1138 | // Parse 'arg' for option settings. |
1139 | // |
1140 | // 'arg' may be IObuff, but only when no errors can be present and option |
1141 | // does not need to be expanded with option_expand(). |
1142 | // "opt_flags": |
1143 | // 0 for ":set" |
1144 | // OPT_GLOBAL for ":setglobal" |
1145 | // OPT_LOCAL for ":setlocal" and a modeline |
1146 | // OPT_MODELINE for a modeline |
1147 | // OPT_WINONLY to only set window-local options |
1148 | // OPT_NOWIN to skip setting window-local options |
1149 | // |
1150 | // returns FAIL if an error is detected, OK otherwise |
1151 | int do_set( |
1152 | char_u *arg, // option string (may be written to!) |
1153 | int opt_flags |
1154 | ) |
1155 | { |
1156 | int opt_idx; |
1157 | char_u *errmsg; |
1158 | char_u errbuf[80]; |
1159 | char_u *startarg; |
1160 | int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name |
1161 | char_u nextchar; // next non-white char after option name |
1162 | int afterchar; // character just after option name |
1163 | int len; |
1164 | int i; |
1165 | varnumber_T value; |
1166 | int key; |
1167 | uint32_t flags; // flags for current option |
1168 | char_u *varp = NULL; // pointer to variable for current option |
1169 | int did_show = false; // already showed one value |
1170 | int adding; // "opt+=arg" |
1171 | int prepending; // "opt^=arg" |
1172 | int removing; // "opt-=arg" |
1173 | int cp_val = 0; |
1174 | |
1175 | if (*arg == NUL) { |
1176 | showoptions(0, opt_flags); |
1177 | did_show = true; |
1178 | goto theend; |
1179 | } |
1180 | |
1181 | while (*arg != NUL) { // loop to process all options |
1182 | errmsg = NULL; |
1183 | startarg = arg; // remember for error message |
1184 | |
1185 | if (STRNCMP(arg, "all" , 3) == 0 && !isalpha(arg[3]) |
1186 | && !(opt_flags & OPT_MODELINE)) { |
1187 | /* |
1188 | * ":set all" show all options. |
1189 | * ":set all&" set all options to their default value. |
1190 | */ |
1191 | arg += 3; |
1192 | if (*arg == '&') { |
1193 | arg++; |
1194 | // Only for :set command set global value of local options. |
1195 | set_options_default(OPT_FREE | opt_flags); |
1196 | didset_options(); |
1197 | didset_options2(); |
1198 | ui_refresh_options(); |
1199 | redraw_all_later(CLEAR); |
1200 | } else { |
1201 | showoptions(1, opt_flags); |
1202 | did_show = true; |
1203 | } |
1204 | } else { |
1205 | prefix = 1; |
1206 | if (STRNCMP(arg, "no" , 2) == 0) { |
1207 | prefix = 0; |
1208 | arg += 2; |
1209 | } else if (STRNCMP(arg, "inv" , 3) == 0) { |
1210 | prefix = 2; |
1211 | arg += 3; |
1212 | } |
1213 | |
1214 | // find end of name |
1215 | key = 0; |
1216 | if (*arg == '<') { |
1217 | opt_idx = -1; |
1218 | // look out for <t_>;> |
1219 | if (arg[1] == 't' && arg[2] == '_' && arg[3] && arg[4]) { |
1220 | len = 5; |
1221 | } else { |
1222 | len = 1; |
1223 | while (arg[len] != NUL && arg[len] != '>') { |
1224 | len++; |
1225 | } |
1226 | } |
1227 | if (arg[len] != '>') { |
1228 | errmsg = e_invarg; |
1229 | goto skip; |
1230 | } |
1231 | if (arg[1] == 't' && arg[2] == '_') { // could be term code |
1232 | opt_idx = findoption_len((const char *)arg + 1, (size_t)(len - 1)); |
1233 | } |
1234 | len++; |
1235 | if (opt_idx == -1) { |
1236 | key = find_key_option(arg + 1, true); |
1237 | } |
1238 | } else { |
1239 | len = 0; |
1240 | // The two characters after "t_" may not be alphanumeric. |
1241 | if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { |
1242 | len = 4; |
1243 | } else { |
1244 | while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { |
1245 | len++; |
1246 | } |
1247 | } |
1248 | opt_idx = findoption_len((const char *)arg, (size_t)len); |
1249 | if (opt_idx == -1) { |
1250 | key = find_key_option(arg, false); |
1251 | } |
1252 | } |
1253 | |
1254 | // remember character after option name |
1255 | afterchar = arg[len]; |
1256 | |
1257 | // skip white space, allow ":set ai ?" |
1258 | while (ascii_iswhite(arg[len])) { |
1259 | len++; |
1260 | } |
1261 | |
1262 | adding = false; |
1263 | prepending = false; |
1264 | removing = false; |
1265 | if (arg[len] != NUL && arg[len + 1] == '=') { |
1266 | if (arg[len] == '+') { |
1267 | adding = true; // "+=" |
1268 | len++; |
1269 | } else if (arg[len] == '^') { |
1270 | prepending = true; // "^=" |
1271 | len++; |
1272 | } else if (arg[len] == '-') { |
1273 | removing = true; // "-=" |
1274 | len++; |
1275 | } |
1276 | } |
1277 | nextchar = arg[len]; |
1278 | |
1279 | if (opt_idx == -1 && key == 0) { // found a mismatch: skip |
1280 | errmsg = (char_u *)N_("E518: Unknown option" ); |
1281 | goto skip; |
1282 | } |
1283 | |
1284 | if (opt_idx >= 0) { |
1285 | if (options[opt_idx].var == NULL) { // hidden option: skip |
1286 | // Only give an error message when requesting the value of |
1287 | // a hidden option, ignore setting it. |
1288 | if (vim_strchr((char_u *)"=:!&<" , nextchar) == NULL |
1289 | && (!(options[opt_idx].flags & P_BOOL) |
1290 | || nextchar == '?')) { |
1291 | errmsg = (char_u *)_(e_unsupportedoption); |
1292 | } |
1293 | goto skip; |
1294 | } |
1295 | |
1296 | flags = options[opt_idx].flags; |
1297 | varp = get_varp_scope(&(options[opt_idx]), opt_flags); |
1298 | } else { |
1299 | flags = P_STRING; |
1300 | } |
1301 | |
1302 | /* Skip all options that are not window-local (used when showing |
1303 | * an already loaded buffer in a window). */ |
1304 | if ((opt_flags & OPT_WINONLY) |
1305 | && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) |
1306 | goto skip; |
1307 | |
1308 | // Skip all options that are window-local (used for :vimgrep). |
1309 | if ((opt_flags & OPT_NOWIN) && opt_idx >= 0 |
1310 | && options[opt_idx].var == VAR_WIN) { |
1311 | goto skip; |
1312 | } |
1313 | |
1314 | // Disallow changing some options from modelines. |
1315 | if (opt_flags & OPT_MODELINE) { |
1316 | if (flags & (P_SECURE | P_NO_ML)) { |
1317 | errmsg = (char_u *)_("E520: Not allowed in a modeline" ); |
1318 | goto skip; |
1319 | } |
1320 | if ((flags & P_MLE) && !p_mle) { |
1321 | errmsg = (char_u *)_( |
1322 | "E992: Not allowed in a modeline when 'modelineexpr' is off" ); |
1323 | goto skip; |
1324 | } |
1325 | // In diff mode some options are overruled. This avoids that |
1326 | // 'foldmethod' becomes "marker" instead of "diff" and that |
1327 | // "wrap" gets set. |
1328 | if (curwin->w_p_diff |
1329 | && opt_idx >= 0 // shut up coverity warning |
1330 | && (options[opt_idx].indir == PV_FDM |
1331 | || options[opt_idx].indir == PV_WRAP)) { |
1332 | goto skip; |
1333 | } |
1334 | } |
1335 | |
1336 | // Disallow changing some options in the sandbox |
1337 | if (sandbox != 0 && (flags & P_SECURE)) { |
1338 | errmsg = (char_u *)_(e_sandbox); |
1339 | goto skip; |
1340 | } |
1341 | |
1342 | if (vim_strchr((char_u *)"?=:!&<" , nextchar) != NULL) { |
1343 | arg += len; |
1344 | cp_val = p_cp; |
1345 | if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { |
1346 | if (arg[3] == 'm') { // "opt&vim": set to Vim default |
1347 | cp_val = false; |
1348 | arg += 3; |
1349 | } else { // "opt&vi": set to Vi default |
1350 | cp_val = true; |
1351 | arg += 2; |
1352 | } |
1353 | } |
1354 | if (vim_strchr((char_u *)"?!&<" , nextchar) != NULL |
1355 | && arg[1] != NUL && !ascii_iswhite(arg[1])) { |
1356 | errmsg = e_trailing; |
1357 | goto skip; |
1358 | } |
1359 | } |
1360 | |
1361 | /* |
1362 | * allow '=' and ':' as MSDOS command.com allows only one |
1363 | * '=' character per "set" command line. grrr. (jw) |
1364 | */ |
1365 | if (nextchar == '?' |
1366 | || (prefix == 1 |
1367 | && vim_strchr((char_u *)"=:&<" , nextchar) == NULL |
1368 | && !(flags & P_BOOL))) { |
1369 | /* |
1370 | * print value |
1371 | */ |
1372 | if (did_show) { |
1373 | msg_putchar('\n'); // cursor below last one |
1374 | } else { |
1375 | gotocmdline(true); // cursor at status line |
1376 | did_show = true; // remember that we did a line |
1377 | } |
1378 | if (opt_idx >= 0) { |
1379 | showoneopt(&options[opt_idx], opt_flags); |
1380 | if (p_verbose > 0) { |
1381 | // Mention where the option was last set. |
1382 | if (varp == options[opt_idx].var) { |
1383 | option_last_set_msg(options[opt_idx].last_set); |
1384 | } else if ((int)options[opt_idx].indir & PV_WIN) { |
1385 | option_last_set_msg(curwin->w_p_script_ctx[ |
1386 | (int)options[opt_idx].indir & PV_MASK]); |
1387 | } else if ((int)options[opt_idx].indir & PV_BUF) { |
1388 | option_last_set_msg(curbuf->b_p_script_ctx[ |
1389 | (int)options[opt_idx].indir & PV_MASK]); |
1390 | } |
1391 | } |
1392 | } else { |
1393 | errmsg = (char_u *)N_("E846: Key code not set" ); |
1394 | goto skip; |
1395 | } |
1396 | if (nextchar != '?' |
1397 | && nextchar != NUL && !ascii_iswhite(afterchar)) |
1398 | errmsg = e_trailing; |
1399 | } else { |
1400 | int value_is_replaced = !prepending && !adding && !removing; |
1401 | int value_checked = false; |
1402 | |
1403 | if (flags & P_BOOL) { // boolean |
1404 | if (nextchar == '=' || nextchar == ':') { |
1405 | errmsg = e_invarg; |
1406 | goto skip; |
1407 | } |
1408 | |
1409 | /* |
1410 | * ":set opt!": invert |
1411 | * ":set opt&": reset to default value |
1412 | * ":set opt<": reset to global value |
1413 | */ |
1414 | if (nextchar == '!') { |
1415 | value = *(int *)(varp) ^ 1; |
1416 | } else if (nextchar == '&') { |
1417 | value = (int)(intptr_t)options[opt_idx].def_val[ |
1418 | ((flags & P_VI_DEF) || cp_val) |
1419 | ? VI_DEFAULT : VIM_DEFAULT]; |
1420 | } else if (nextchar == '<') { |
1421 | // For 'autoread' -1 means to use global value. |
1422 | if ((int *)varp == &curbuf->b_p_ar |
1423 | && opt_flags == OPT_LOCAL) { |
1424 | value = -1; |
1425 | } else { |
1426 | value = *(int *)get_varp_scope(&(options[opt_idx]), |
1427 | OPT_GLOBAL); |
1428 | } |
1429 | } else { |
1430 | /* |
1431 | * ":set invopt": invert |
1432 | * ":set opt" or ":set noopt": set or reset |
1433 | */ |
1434 | if (nextchar != NUL && !ascii_iswhite(afterchar)) { |
1435 | errmsg = e_trailing; |
1436 | goto skip; |
1437 | } |
1438 | if (prefix == 2) { // inv |
1439 | value = *(int *)(varp) ^ 1; |
1440 | } else { |
1441 | value = prefix; |
1442 | } |
1443 | } |
1444 | |
1445 | errmsg = (char_u *)set_bool_option(opt_idx, varp, (int)value, |
1446 | opt_flags); |
1447 | } else { // Numeric or string. |
1448 | if (vim_strchr((const char_u *)"=:&<" , nextchar) == NULL |
1449 | || prefix != 1) { |
1450 | errmsg = e_invarg; |
1451 | goto skip; |
1452 | } |
1453 | |
1454 | if (flags & P_NUM) { // numeric |
1455 | // Different ways to set a number option: |
1456 | // & set to default value |
1457 | // < set to global value |
1458 | // <xx> accept special key codes for 'wildchar' |
1459 | // c accept any non-digit for 'wildchar' |
1460 | // [-]0-9 set number |
1461 | // other error |
1462 | arg++; |
1463 | if (nextchar == '&') { |
1464 | value = (long)(intptr_t)options[opt_idx].def_val[ |
1465 | ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT]; |
1466 | } else if (nextchar == '<') { |
1467 | // For 'undolevels' NO_LOCAL_UNDOLEVEL means to |
1468 | // use the global value. |
1469 | if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) { |
1470 | value = NO_LOCAL_UNDOLEVEL; |
1471 | } else { |
1472 | value = *(long *)get_varp_scope( |
1473 | &(options[opt_idx]), OPT_GLOBAL); |
1474 | } |
1475 | } else if (((long *)varp == &p_wc |
1476 | || (long *)varp == &p_wcm) |
1477 | && (*arg == '<' |
1478 | || *arg == '^' |
1479 | || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) |
1480 | && !ascii_isdigit(*arg)))) { |
1481 | value = string_to_key(arg); |
1482 | if (value == 0 && (long *)varp != &p_wcm) { |
1483 | errmsg = e_invarg; |
1484 | goto skip; |
1485 | } |
1486 | } else if (*arg == '-' || ascii_isdigit(*arg)) { |
1487 | // Allow negative, octal and hex numbers. |
1488 | vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0); |
1489 | if (arg[i] != NUL && !ascii_iswhite(arg[i])) { |
1490 | errmsg = e_invarg; |
1491 | goto skip; |
1492 | } |
1493 | } else { |
1494 | errmsg = (char_u *)N_("E521: Number required after =" ); |
1495 | goto skip; |
1496 | } |
1497 | |
1498 | if (adding) { |
1499 | value = *(long *)varp + value; |
1500 | } |
1501 | if (prepending) { |
1502 | value = *(long *)varp * value; |
1503 | } |
1504 | if (removing) { |
1505 | value = *(long *)varp - value; |
1506 | } |
1507 | errmsg = (char_u *)set_num_option(opt_idx, varp, (long)value, |
1508 | errbuf, sizeof(errbuf), |
1509 | opt_flags); |
1510 | } else if (opt_idx >= 0) { // String. |
1511 | char_u *save_arg = NULL; |
1512 | char_u *s = NULL; |
1513 | char_u *oldval = NULL; // previous value if *varp |
1514 | char_u *newval; |
1515 | char_u *origval = NULL; |
1516 | char *saved_origval = NULL; |
1517 | char *saved_newval = NULL; |
1518 | unsigned newlen; |
1519 | int comma; |
1520 | int bs; |
1521 | int new_value_alloced; /* new string option |
1522 | was allocated */ |
1523 | |
1524 | /* When using ":set opt=val" for a global option |
1525 | * with a local value the local value will be |
1526 | * reset, use the global value here. */ |
1527 | if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 |
1528 | && ((int)options[opt_idx].indir & PV_BOTH)) |
1529 | varp = options[opt_idx].var; |
1530 | |
1531 | /* The old value is kept until we are sure that the |
1532 | * new value is valid. */ |
1533 | oldval = *(char_u **)varp; |
1534 | |
1535 | // When setting the local value of a global |
1536 | // option, the old value may be the global value. |
1537 | if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags |
1538 | & OPT_LOCAL)) { |
1539 | origval = *(char_u **)get_varp(&options[opt_idx]); |
1540 | } else { |
1541 | origval = oldval; |
1542 | } |
1543 | |
1544 | if (nextchar == '&') { // set to default val |
1545 | newval = options[opt_idx].def_val[ |
1546 | ((flags & P_VI_DEF) || cp_val) |
1547 | ? VI_DEFAULT : VIM_DEFAULT]; |
1548 | /* expand environment variables and ~ (since the |
1549 | * default value was already expanded, only |
1550 | * required when an environment variable was set |
1551 | * later */ |
1552 | new_value_alloced = true; |
1553 | if (newval == NULL) { |
1554 | newval = empty_option; |
1555 | } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { |
1556 | s = option_expand(opt_idx, newval); |
1557 | if (s == NULL) { |
1558 | s = newval; |
1559 | } |
1560 | newval = vim_strsave(s); |
1561 | } else { |
1562 | newval = (char_u *)xstrdup((char *)newval); |
1563 | } |
1564 | } else if (nextchar == '<') { // set to global val |
1565 | newval = vim_strsave(*(char_u **)get_varp_scope( |
1566 | &(options[opt_idx]), OPT_GLOBAL)); |
1567 | new_value_alloced = true; |
1568 | } else { |
1569 | arg++; // jump to after the '=' or ':' |
1570 | |
1571 | /* |
1572 | * Set 'keywordprg' to ":help" if an empty |
1573 | * value was passed to :set by the user. |
1574 | * Misuse errbuf[] for the resulting string. |
1575 | */ |
1576 | if (varp == (char_u *)&p_kp |
1577 | && (*arg == NUL || *arg == ' ')) { |
1578 | STRCPY(errbuf, ":help" ); |
1579 | save_arg = arg; |
1580 | arg = errbuf; |
1581 | } |
1582 | /* |
1583 | * Convert 'backspace' number to string, for |
1584 | * adding, prepending and removing string. |
1585 | */ |
1586 | else if (varp == (char_u *)&p_bs |
1587 | && ascii_isdigit(**(char_u **)varp)) { |
1588 | i = getdigits_int((char_u **)varp, true, 0); |
1589 | switch (i) { |
1590 | case 0: |
1591 | *(char_u **)varp = empty_option; |
1592 | break; |
1593 | case 1: |
1594 | *(char_u **)varp = vim_strsave( |
1595 | (char_u *)"indent,eol" ); |
1596 | break; |
1597 | case 2: |
1598 | *(char_u **)varp = vim_strsave( |
1599 | (char_u *)"indent,eol,start" ); |
1600 | break; |
1601 | } |
1602 | xfree(oldval); |
1603 | if (origval == oldval) { |
1604 | origval = *(char_u **)varp; |
1605 | } |
1606 | oldval = *(char_u **)varp; |
1607 | } |
1608 | /* |
1609 | * Convert 'whichwrap' number to string, for |
1610 | * backwards compatibility with Vim 3.0. |
1611 | * Misuse errbuf[] for the resulting string. |
1612 | */ |
1613 | else if (varp == (char_u *)&p_ww |
1614 | && ascii_isdigit(*arg)) { |
1615 | *errbuf = NUL; |
1616 | i = getdigits_int(&arg, true, 0); |
1617 | if (i & 1) { |
1618 | STRCAT(errbuf, "b," ); |
1619 | } |
1620 | if (i & 2) { |
1621 | STRCAT(errbuf, "s," ); |
1622 | } |
1623 | if (i & 4) { |
1624 | STRCAT(errbuf, "h,l," ); |
1625 | } |
1626 | if (i & 8) { |
1627 | STRCAT(errbuf, "<,>," ); |
1628 | } |
1629 | if (i & 16) { |
1630 | STRCAT(errbuf, "[,]," ); |
1631 | } |
1632 | if (*errbuf != NUL) { // remove trailing , |
1633 | errbuf[STRLEN(errbuf) - 1] = NUL; |
1634 | } |
1635 | save_arg = arg; |
1636 | arg = errbuf; |
1637 | } |
1638 | /* |
1639 | * Remove '>' before 'dir' and 'bdir', for |
1640 | * backwards compatibility with version 3.0 |
1641 | */ |
1642 | else if ( *arg == '>' |
1643 | && (varp == (char_u *)&p_dir |
1644 | || varp == (char_u *)&p_bdir)) { |
1645 | arg++; |
1646 | } |
1647 | |
1648 | /* |
1649 | * Copy the new string into allocated memory. |
1650 | * Can't use set_string_option_direct(), because |
1651 | * we need to remove the backslashes. |
1652 | */ |
1653 | // get a bit too much |
1654 | newlen = (unsigned)STRLEN(arg) + 1; |
1655 | if (adding || prepending || removing) { |
1656 | newlen += (unsigned)STRLEN(origval) + 1; |
1657 | } |
1658 | newval = xmalloc(newlen); |
1659 | s = newval; |
1660 | |
1661 | /* |
1662 | * Copy the string, skip over escaped chars. |
1663 | * For WIN32 backslashes before normal |
1664 | * file name characters are not removed, and keep |
1665 | * backslash at start, for "\\machine\path", but |
1666 | * do remove it for "\\\\machine\\path". |
1667 | * The reverse is found in ExpandOldSetting(). |
1668 | */ |
1669 | while (*arg && !ascii_iswhite(*arg)) { |
1670 | if (*arg == '\\' && arg[1] != NUL |
1671 | #ifdef BACKSLASH_IN_FILENAME |
1672 | && !((flags & P_EXPAND) |
1673 | && vim_isfilec(arg[1]) |
1674 | && (arg[1] != '\\' |
1675 | || (s == newval |
1676 | && arg[2] != '\\'))) |
1677 | #endif |
1678 | ) |
1679 | arg++; // remove backslash |
1680 | if (has_mbyte |
1681 | && (i = (*mb_ptr2len)(arg)) > 1) { |
1682 | // copy multibyte char |
1683 | memmove(s, arg, (size_t)i); |
1684 | arg += i; |
1685 | s += i; |
1686 | } else |
1687 | *s++ = *arg++; |
1688 | } |
1689 | *s = NUL; |
1690 | |
1691 | /* |
1692 | * Expand environment variables and ~. |
1693 | * Don't do it when adding without inserting a |
1694 | * comma. |
1695 | */ |
1696 | if (!(adding || prepending || removing) |
1697 | || (flags & P_COMMA)) { |
1698 | s = option_expand(opt_idx, newval); |
1699 | if (s != NULL) { |
1700 | xfree(newval); |
1701 | newlen = (unsigned)STRLEN(s) + 1; |
1702 | if (adding || prepending || removing) { |
1703 | newlen += (unsigned)STRLEN(origval) + 1; |
1704 | } |
1705 | newval = xmalloc(newlen); |
1706 | STRCPY(newval, s); |
1707 | } |
1708 | } |
1709 | |
1710 | /* locate newval[] in origval[] when removing it |
1711 | * and when adding to avoid duplicates */ |
1712 | i = 0; // init for GCC |
1713 | if (removing || (flags & P_NODUP)) { |
1714 | i = (int)STRLEN(newval); |
1715 | bs = 0; |
1716 | for (s = origval; *s; s++) { |
1717 | if ((!(flags & P_COMMA) |
1718 | || s == origval |
1719 | || (s[-1] == ',' && !(bs & 1))) |
1720 | && STRNCMP(s, newval, i) == 0 |
1721 | && (!(flags & P_COMMA) |
1722 | || s[i] == ',' |
1723 | || s[i] == NUL)) { |
1724 | break; |
1725 | } |
1726 | // Count backslashes. Only a comma with an even number of |
1727 | // backslashes or a single backslash preceded by a comma |
1728 | // before it is recognized as a separator |
1729 | if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',') |
1730 | || (s == origval + 1 && s[-1] == '\\')) { |
1731 | bs++; |
1732 | } else { |
1733 | bs = 0; |
1734 | } |
1735 | } |
1736 | |
1737 | // do not add if already there |
1738 | if ((adding || prepending) && *s) { |
1739 | prepending = false; |
1740 | adding = false; |
1741 | STRCPY(newval, origval); |
1742 | } |
1743 | } |
1744 | |
1745 | /* concatenate the two strings; add a ',' if |
1746 | * needed */ |
1747 | if (adding || prepending) { |
1748 | comma = ((flags & P_COMMA) && *origval != NUL |
1749 | && *newval != NUL); |
1750 | if (adding) { |
1751 | i = (int)STRLEN(origval); |
1752 | // Strip a trailing comma, would get 2. |
1753 | if (comma && i > 1 |
1754 | && (flags & P_ONECOMMA) == P_ONECOMMA |
1755 | && origval[i - 1] == ',' |
1756 | && origval[i - 2] != '\\') { |
1757 | i--; |
1758 | } |
1759 | memmove(newval + i + comma, newval, |
1760 | STRLEN(newval) + 1); |
1761 | memmove(newval, origval, (size_t)i); |
1762 | } else { |
1763 | i = (int)STRLEN(newval); |
1764 | STRMOVE(newval + i + comma, origval); |
1765 | } |
1766 | if (comma) { |
1767 | newval[i] = ','; |
1768 | } |
1769 | } |
1770 | |
1771 | /* Remove newval[] from origval[]. (Note: "i" has |
1772 | * been set above and is used here). */ |
1773 | if (removing) { |
1774 | STRCPY(newval, origval); |
1775 | if (*s) { |
1776 | // may need to remove a comma |
1777 | if (flags & P_COMMA) { |
1778 | if (s == origval) { |
1779 | // include comma after string |
1780 | if (s[i] == ',') { |
1781 | i++; |
1782 | } |
1783 | } else { |
1784 | // include comma before string |
1785 | s--; |
1786 | i++; |
1787 | } |
1788 | } |
1789 | STRMOVE(newval + (s - origval), s + i); |
1790 | } |
1791 | } |
1792 | |
1793 | if (flags & P_FLAGLIST) { |
1794 | // Remove flags that appear twice. |
1795 | for (s = newval; *s;) { |
1796 | // if options have P_FLAGLIST and P_ONECOMMA such as |
1797 | // 'whichwrap' |
1798 | if (flags & P_ONECOMMA) { |
1799 | if (*s != ',' && *(s + 1) == ',' |
1800 | && vim_strchr(s + 2, *s) != NULL) { |
1801 | // Remove the duplicated value and the next comma. |
1802 | STRMOVE(s, s + 2); |
1803 | continue; |
1804 | } |
1805 | } else { |
1806 | if ((!(flags & P_COMMA) || *s != ',') |
1807 | && vim_strchr(s + 1, *s) != NULL) { |
1808 | STRMOVE(s, s + 1); |
1809 | continue; |
1810 | } |
1811 | } |
1812 | s++; |
1813 | } |
1814 | } |
1815 | |
1816 | if (save_arg != NULL) { // number for 'whichwrap' |
1817 | arg = save_arg; |
1818 | } |
1819 | new_value_alloced = true; |
1820 | } |
1821 | |
1822 | // Set the new value. |
1823 | *(char_u **)(varp) = newval; |
1824 | |
1825 | // origval may be freed by |
1826 | // did_set_string_option(), make a copy. |
1827 | saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0; |
1828 | |
1829 | // newval (and varp) may become invalid if the |
1830 | // buffer is closed by autocommands. |
1831 | saved_newval = (newval != NULL) ? xstrdup((char *)newval) : 0; |
1832 | |
1833 | { |
1834 | uint32_t *p = insecure_flag(opt_idx, opt_flags); |
1835 | const int secure_saved = secure; |
1836 | |
1837 | // When an option is set in the sandbox, from a |
1838 | // modeline or in secure mode, then deal with side |
1839 | // effects in secure mode. Also when the value was |
1840 | // set with the P_INSECURE flag and is not |
1841 | // completely replaced. |
1842 | if ((opt_flags & OPT_MODELINE) |
1843 | || sandbox != 0 |
1844 | || (!value_is_replaced && (*p & P_INSECURE))) { |
1845 | secure = 1; |
1846 | } |
1847 | |
1848 | // Handle side effects, and set the global value |
1849 | // for ":set" on local options. Note: when setting |
1850 | // 'syntax' or 'filetype' autocommands may be |
1851 | // triggered that can cause havoc. |
1852 | errmsg = did_set_string_option(opt_idx, (char_u **)varp, |
1853 | new_value_alloced, oldval, |
1854 | errbuf, sizeof(errbuf), |
1855 | opt_flags, &value_checked); |
1856 | |
1857 | secure = secure_saved; |
1858 | } |
1859 | |
1860 | if (errmsg == NULL) { |
1861 | if (!starting) { |
1862 | trigger_optionsset_string(opt_idx, opt_flags, saved_origval, |
1863 | saved_newval); |
1864 | } |
1865 | if (options[opt_idx].flags & P_UI_OPTION) { |
1866 | ui_call_option_set(cstr_as_string(options[opt_idx].fullname), |
1867 | STRING_OBJ(cstr_as_string(saved_newval))); |
1868 | } |
1869 | } |
1870 | xfree(saved_origval); |
1871 | xfree(saved_newval); |
1872 | |
1873 | // If error detected, print the error message. |
1874 | if (errmsg != NULL) { |
1875 | goto skip; |
1876 | } |
1877 | |
1878 | } else { |
1879 | // key code option(FIXME(tarruda): Show a warning or something |
1880 | // similar) |
1881 | } |
1882 | } |
1883 | |
1884 | if (opt_idx >= 0) { |
1885 | did_set_option(opt_idx, opt_flags, value_is_replaced, value_checked); |
1886 | } |
1887 | } |
1888 | |
1889 | skip: |
1890 | /* |
1891 | * Advance to next argument. |
1892 | * - skip until a blank found, taking care of backslashes |
1893 | * - skip blanks |
1894 | * - skip one "=val" argument (for hidden options ":set gfn =xx") |
1895 | */ |
1896 | for (i = 0; i < 2; i++) { |
1897 | while (*arg != NUL && !ascii_iswhite(*arg)) { |
1898 | if (*arg++ == '\\' && *arg != NUL) { |
1899 | arg++; |
1900 | } |
1901 | } |
1902 | arg = skipwhite(arg); |
1903 | if (*arg != '=') { |
1904 | break; |
1905 | } |
1906 | } |
1907 | } |
1908 | |
1909 | if (errmsg != NULL) { |
1910 | STRLCPY(IObuff, _(errmsg), IOSIZE); |
1911 | i = (int)STRLEN(IObuff) + 2; |
1912 | if (i + (arg - startarg) < IOSIZE) { |
1913 | // append the argument with the error |
1914 | STRCAT(IObuff, ": " ); |
1915 | assert(arg >= startarg); |
1916 | memmove(IObuff + i, startarg, (size_t)(arg - startarg)); |
1917 | IObuff[i + (arg - startarg)] = NUL; |
1918 | } |
1919 | // make sure all characters are printable |
1920 | trans_characters(IObuff, IOSIZE); |
1921 | |
1922 | no_wait_return++; // wait_return done later |
1923 | emsg(IObuff); // show error highlighted |
1924 | no_wait_return--; |
1925 | |
1926 | return FAIL; |
1927 | } |
1928 | |
1929 | arg = skipwhite(arg); |
1930 | } |
1931 | |
1932 | theend: |
1933 | if (silent_mode && did_show) { |
1934 | // After displaying option values in silent mode. |
1935 | silent_mode = false; |
1936 | info_message = true; // use mch_msg(), not mch_errmsg() |
1937 | msg_putchar('\n'); |
1938 | ui_flush(); |
1939 | silent_mode = true; |
1940 | info_message = false; // use mch_msg(), not mch_errmsg() |
1941 | } |
1942 | |
1943 | return OK; |
1944 | } |
1945 | |
1946 | // Call this when an option has been given a new value through a user command. |
1947 | // Sets the P_WAS_SET flag and takes care of the P_INSECURE flag. |
1948 | static void did_set_option( |
1949 | int opt_idx, |
1950 | int opt_flags, // possibly with OPT_MODELINE |
1951 | int new_value, // value was replaced completely |
1952 | int value_checked // value was checked to be safe, no need to |
1953 | // set P_INSECURE |
1954 | ) |
1955 | { |
1956 | options[opt_idx].flags |= P_WAS_SET; |
1957 | |
1958 | /* When an option is set in the sandbox, from a modeline or in secure mode |
1959 | * set the P_INSECURE flag. Otherwise, if a new value is stored reset the |
1960 | * flag. */ |
1961 | uint32_t *p = insecure_flag(opt_idx, opt_flags); |
1962 | if (!value_checked && (secure |
1963 | || sandbox != 0 |
1964 | || (opt_flags & OPT_MODELINE))) { |
1965 | *p = *p | P_INSECURE; |
1966 | } else if (new_value) { |
1967 | *p = *p & ~P_INSECURE; |
1968 | } |
1969 | } |
1970 | |
1971 | static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) |
1972 | { |
1973 | if (errbuf == NULL) { |
1974 | return (char_u *)"" ; |
1975 | } |
1976 | vim_snprintf((char *)errbuf, errbuflen, _("E539: Illegal character <%s>" ), |
1977 | (char *)transchar(c)); |
1978 | return errbuf; |
1979 | } |
1980 | |
1981 | /* |
1982 | * Convert a key name or string into a key value. |
1983 | * Used for 'wildchar' and 'cedit' options. |
1984 | */ |
1985 | static int string_to_key(char_u *arg) |
1986 | { |
1987 | if (*arg == '<') { |
1988 | return find_key_option(arg + 1, true); |
1989 | } |
1990 | if (*arg == '^') { |
1991 | return Ctrl_chr(arg[1]); |
1992 | } |
1993 | return *arg; |
1994 | } |
1995 | |
1996 | /* |
1997 | * Check value of 'cedit' and set cedit_key. |
1998 | * Returns NULL if value is OK, error message otherwise. |
1999 | */ |
2000 | static char_u *check_cedit(void) |
2001 | { |
2002 | int n; |
2003 | |
2004 | if (*p_cedit == NUL) { |
2005 | cedit_key = -1; |
2006 | } else { |
2007 | n = string_to_key(p_cedit); |
2008 | if (vim_isprintc(n)) { |
2009 | return e_invarg; |
2010 | } |
2011 | cedit_key = n; |
2012 | } |
2013 | return NULL; |
2014 | } |
2015 | |
2016 | // When changing 'title', 'titlestring', 'icon' or 'iconstring', call |
2017 | // maketitle() to create and display it. |
2018 | // When switching the title or icon off, call ui_set_{icon,title}(NULL) to get |
2019 | // the old value back. |
2020 | static void did_set_title( |
2021 | int icon // Did set icon instead of title |
2022 | ) |
2023 | { |
2024 | if (starting != NO_SCREEN) { |
2025 | maketitle(); |
2026 | resettitle(); |
2027 | } |
2028 | } |
2029 | |
2030 | // set_options_bin - called when 'bin' changes value. |
2031 | void set_options_bin( |
2032 | int oldval, |
2033 | int newval, |
2034 | int opt_flags // OPT_LOCAL and/or OPT_GLOBAL |
2035 | ) |
2036 | { |
2037 | /* |
2038 | * The option values that are changed when 'bin' changes are |
2039 | * copied when 'bin is set and restored when 'bin' is reset. |
2040 | */ |
2041 | if (newval) { |
2042 | if (!oldval) { // switched on |
2043 | if (!(opt_flags & OPT_GLOBAL)) { |
2044 | curbuf->b_p_tw_nobin = curbuf->b_p_tw; |
2045 | curbuf->b_p_wm_nobin = curbuf->b_p_wm; |
2046 | curbuf->b_p_ml_nobin = curbuf->b_p_ml; |
2047 | curbuf->b_p_et_nobin = curbuf->b_p_et; |
2048 | } |
2049 | if (!(opt_flags & OPT_LOCAL)) { |
2050 | p_tw_nobin = p_tw; |
2051 | p_wm_nobin = p_wm; |
2052 | p_ml_nobin = p_ml; |
2053 | p_et_nobin = p_et; |
2054 | } |
2055 | } |
2056 | |
2057 | if (!(opt_flags & OPT_GLOBAL)) { |
2058 | curbuf->b_p_tw = 0; // no automatic line wrap |
2059 | curbuf->b_p_wm = 0; // no automatic line wrap |
2060 | curbuf->b_p_ml = 0; // no modelines |
2061 | curbuf->b_p_et = 0; // no expandtab |
2062 | } |
2063 | if (!(opt_flags & OPT_LOCAL)) { |
2064 | p_tw = 0; |
2065 | p_wm = 0; |
2066 | p_ml = false; |
2067 | p_et = false; |
2068 | p_bin = true; // needed when called for the "-b" argument |
2069 | } |
2070 | } else if (oldval) { // switched off |
2071 | if (!(opt_flags & OPT_GLOBAL)) { |
2072 | curbuf->b_p_tw = curbuf->b_p_tw_nobin; |
2073 | curbuf->b_p_wm = curbuf->b_p_wm_nobin; |
2074 | curbuf->b_p_ml = curbuf->b_p_ml_nobin; |
2075 | curbuf->b_p_et = curbuf->b_p_et_nobin; |
2076 | } |
2077 | if (!(opt_flags & OPT_LOCAL)) { |
2078 | p_tw = p_tw_nobin; |
2079 | p_wm = p_wm_nobin; |
2080 | p_ml = p_ml_nobin; |
2081 | p_et = p_et_nobin; |
2082 | } |
2083 | } |
2084 | } |
2085 | |
2086 | /* |
2087 | * Find the parameter represented by the given character (eg ', :, ", or /), |
2088 | * and return its associated value in the 'shada' string. |
2089 | * Only works for number parameters, not for 'r' or 'n'. |
2090 | * If the parameter is not specified in the string or there is no following |
2091 | * number, return -1. |
2092 | */ |
2093 | int get_shada_parameter(int type) |
2094 | { |
2095 | char_u *p; |
2096 | |
2097 | p = find_shada_parameter(type); |
2098 | if (p != NULL && ascii_isdigit(*p)) { |
2099 | return atoi((char *)p); |
2100 | } |
2101 | return -1; |
2102 | } |
2103 | |
2104 | /* |
2105 | * Find the parameter represented by the given character (eg ''', ':', '"', or |
2106 | * '/') in the 'shada' option and return a pointer to the string after it. |
2107 | * Return NULL if the parameter is not specified in the string. |
2108 | */ |
2109 | char_u *find_shada_parameter(int type) |
2110 | { |
2111 | char_u *p; |
2112 | |
2113 | for (p = p_shada; *p; p++) { |
2114 | if (*p == type) { |
2115 | return p + 1; |
2116 | } |
2117 | if (*p == 'n') { // 'n' is always the last one |
2118 | break; |
2119 | } |
2120 | p = vim_strchr(p, ','); // skip until next ',' |
2121 | if (p == NULL) { // hit the end without finding parameter |
2122 | break; |
2123 | } |
2124 | } |
2125 | return NULL; |
2126 | } |
2127 | |
2128 | /* |
2129 | * Expand environment variables for some string options. |
2130 | * These string options cannot be indirect! |
2131 | * If "val" is NULL expand the current value of the option. |
2132 | * Return pointer to NameBuff, or NULL when not expanded. |
2133 | */ |
2134 | static char_u *option_expand(int opt_idx, char_u *val) |
2135 | { |
2136 | // if option doesn't need expansion nothing to do |
2137 | if (!(options[opt_idx].flags & P_EXPAND) || options[opt_idx].var == NULL) { |
2138 | return NULL; |
2139 | } |
2140 | |
2141 | if (val == NULL) { |
2142 | val = *(char_u **)options[opt_idx].var; |
2143 | } |
2144 | |
2145 | // If val is longer than MAXPATHL no meaningful expansion can be done, |
2146 | // expand_env() would truncate the string. |
2147 | if (val == NULL || STRLEN(val) > MAXPATHL) { |
2148 | return NULL; |
2149 | } |
2150 | |
2151 | /* |
2152 | * Expanding this with NameBuff, expand_env() must not be passed IObuff. |
2153 | * Escape spaces when expanding 'tags', they are used to separate file |
2154 | * names. |
2155 | * For 'spellsuggest' expand after "file:". |
2156 | */ |
2157 | expand_env_esc(val, NameBuff, MAXPATHL, |
2158 | (char_u **)options[opt_idx].var == &p_tags, false, |
2159 | (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" : |
2160 | NULL); |
2161 | if (STRCMP(NameBuff, val) == 0) { // they are the same |
2162 | return NULL; |
2163 | } |
2164 | |
2165 | return NameBuff; |
2166 | } |
2167 | |
2168 | // After setting various option values: recompute variables that depend on |
2169 | // option values. |
2170 | static void didset_options(void) |
2171 | { |
2172 | // initialize the table for 'iskeyword' et.al. |
2173 | (void)init_chartab(); |
2174 | |
2175 | (void)opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true); |
2176 | (void)opt_strings_flags(p_bkc, p_bkc_values, &bkc_flags, true); |
2177 | (void)opt_strings_flags(p_bo, p_bo_values, &bo_flags, true); |
2178 | (void)opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true); |
2179 | (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); |
2180 | (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); |
2181 | (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true); |
2182 | (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true); |
2183 | (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false); |
2184 | (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true); |
2185 | (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true); |
2186 | (void)spell_check_msm(); |
2187 | (void)spell_check_sps(); |
2188 | (void)compile_cap_prog(curwin->w_s); |
2189 | (void)did_set_spell_option(true); |
2190 | // set cedit_key |
2191 | (void)check_cedit(); |
2192 | briopt_check(curwin); |
2193 | // initialize the table for 'breakat'. |
2194 | fill_breakat_flags(); |
2195 | } |
2196 | |
2197 | // More side effects of setting options. |
2198 | static void didset_options2(void) |
2199 | { |
2200 | // Initialize the highlight_attr[] table. |
2201 | highlight_changed(); |
2202 | |
2203 | // Parse default for 'clipboard'. |
2204 | (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true); |
2205 | |
2206 | // Parse default for 'fillchars'. |
2207 | (void)set_chars_option(curwin, &curwin->w_p_fcs); |
2208 | |
2209 | // Parse default for 'listchars'. |
2210 | (void)set_chars_option(curwin, &curwin->w_p_lcs); |
2211 | |
2212 | // Parse default for 'wildmode'. |
2213 | check_opt_wim(); |
2214 | } |
2215 | |
2216 | /* |
2217 | * Check for string options that are NULL (normally only termcap options). |
2218 | */ |
2219 | void check_options(void) |
2220 | { |
2221 | int opt_idx; |
2222 | |
2223 | for (opt_idx = 0; options[opt_idx].fullname != NULL; opt_idx++) { |
2224 | if ((options[opt_idx].flags & P_STRING) && options[opt_idx].var != NULL) { |
2225 | check_string_option((char_u **)get_varp(&(options[opt_idx]))); |
2226 | } |
2227 | } |
2228 | } |
2229 | |
2230 | /* |
2231 | * Check string options in a buffer for NULL value. |
2232 | */ |
2233 | void check_buf_options(buf_T *buf) |
2234 | { |
2235 | check_string_option(&buf->b_p_bh); |
2236 | check_string_option(&buf->b_p_bt); |
2237 | check_string_option(&buf->b_p_fenc); |
2238 | check_string_option(&buf->b_p_ff); |
2239 | check_string_option(&buf->b_p_def); |
2240 | check_string_option(&buf->b_p_inc); |
2241 | check_string_option(&buf->b_p_inex); |
2242 | check_string_option(&buf->b_p_inde); |
2243 | check_string_option(&buf->b_p_indk); |
2244 | check_string_option(&buf->b_p_fp); |
2245 | check_string_option(&buf->b_p_fex); |
2246 | check_string_option(&buf->b_p_kp); |
2247 | check_string_option(&buf->b_p_mps); |
2248 | check_string_option(&buf->b_p_fo); |
2249 | check_string_option(&buf->b_p_flp); |
2250 | check_string_option(&buf->b_p_isk); |
2251 | check_string_option(&buf->b_p_com); |
2252 | check_string_option(&buf->b_p_cms); |
2253 | check_string_option(&buf->b_p_nf); |
2254 | check_string_option(&buf->b_p_qe); |
2255 | check_string_option(&buf->b_p_syn); |
2256 | check_string_option(&buf->b_s.b_syn_isk); |
2257 | check_string_option(&buf->b_s.b_p_spc); |
2258 | check_string_option(&buf->b_s.b_p_spf); |
2259 | check_string_option(&buf->b_s.b_p_spl); |
2260 | check_string_option(&buf->b_p_sua); |
2261 | check_string_option(&buf->b_p_cink); |
2262 | check_string_option(&buf->b_p_cino); |
2263 | parse_cino(buf); |
2264 | check_string_option(&buf->b_p_ft); |
2265 | check_string_option(&buf->b_p_cinw); |
2266 | check_string_option(&buf->b_p_cpt); |
2267 | check_string_option(&buf->b_p_cfu); |
2268 | check_string_option(&buf->b_p_ofu); |
2269 | check_string_option(&buf->b_p_keymap); |
2270 | check_string_option(&buf->b_p_gp); |
2271 | check_string_option(&buf->b_p_mp); |
2272 | check_string_option(&buf->b_p_efm); |
2273 | check_string_option(&buf->b_p_ep); |
2274 | check_string_option(&buf->b_p_path); |
2275 | check_string_option(&buf->b_p_tags); |
2276 | check_string_option(&buf->b_p_tc); |
2277 | check_string_option(&buf->b_p_dict); |
2278 | check_string_option(&buf->b_p_tsr); |
2279 | check_string_option(&buf->b_p_lw); |
2280 | check_string_option(&buf->b_p_bkc); |
2281 | check_string_option(&buf->b_p_menc); |
2282 | } |
2283 | |
2284 | /* |
2285 | * Free the string allocated for an option. |
2286 | * Checks for the string being empty_option. This may happen if we're out of |
2287 | * memory, vim_strsave() returned NULL, which was replaced by empty_option by |
2288 | * check_options(). |
2289 | * Does NOT check for P_ALLOCED flag! |
2290 | */ |
2291 | void free_string_option(char_u *p) |
2292 | { |
2293 | if (p != empty_option) { |
2294 | xfree(p); |
2295 | } |
2296 | } |
2297 | |
2298 | void clear_string_option(char_u **pp) |
2299 | { |
2300 | if (*pp != empty_option) { |
2301 | xfree(*pp); |
2302 | } |
2303 | *pp = empty_option; |
2304 | } |
2305 | |
2306 | static void check_string_option(char_u **pp) |
2307 | { |
2308 | if (*pp == NULL) { |
2309 | *pp = empty_option; |
2310 | } |
2311 | } |
2312 | |
2313 | /// Return true when option "opt" was set from a modeline or in secure mode. |
2314 | /// Return false when it wasn't. |
2315 | /// Return -1 for an unknown option. |
2316 | int was_set_insecurely(char_u *opt, int opt_flags) |
2317 | { |
2318 | int idx = findoption((const char *)opt); |
2319 | |
2320 | if (idx >= 0) { |
2321 | uint32_t *flagp = insecure_flag(idx, opt_flags); |
2322 | return (*flagp & P_INSECURE) != 0; |
2323 | } |
2324 | internal_error("was_set_insecurely()" ); |
2325 | return -1; |
2326 | } |
2327 | |
2328 | /* |
2329 | * Get a pointer to the flags used for the P_INSECURE flag of option |
2330 | * "opt_idx". For some local options a local flags field is used. |
2331 | */ |
2332 | static uint32_t *insecure_flag(int opt_idx, int opt_flags) |
2333 | { |
2334 | if (opt_flags & OPT_LOCAL) |
2335 | switch ((int)options[opt_idx].indir) { |
2336 | case PV_STL: return &curwin->w_p_stl_flags; |
2337 | case PV_FDE: return &curwin->w_p_fde_flags; |
2338 | case PV_FDT: return &curwin->w_p_fdt_flags; |
2339 | case PV_INDE: return &curbuf->b_p_inde_flags; |
2340 | case PV_FEX: return &curbuf->b_p_fex_flags; |
2341 | case PV_INEX: return &curbuf->b_p_inex_flags; |
2342 | } |
2343 | |
2344 | // Nothing special, return global flags field. |
2345 | return &options[opt_idx].flags; |
2346 | } |
2347 | |
2348 | |
2349 | /* |
2350 | * Redraw the window title and/or tab page text later. |
2351 | */ |
2352 | static void redraw_titles(void) |
2353 | { |
2354 | need_maketitle = true; |
2355 | redraw_tabline = true; |
2356 | } |
2357 | |
2358 | static int shada_idx = -1; |
2359 | |
2360 | // Set a string option to a new value (without checking the effect). |
2361 | // The string is copied into allocated memory. |
2362 | // if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used. |
2363 | // When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When |
2364 | // "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to |
2365 | // "set_sid". |
2366 | void |
2367 | set_string_option_direct( |
2368 | char_u *name, |
2369 | int opt_idx, |
2370 | char_u *val, |
2371 | int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL |
2372 | int set_sid |
2373 | ) |
2374 | { |
2375 | char_u *s; |
2376 | char_u **varp; |
2377 | int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; |
2378 | int idx = opt_idx; |
2379 | |
2380 | if (idx == -1) { // Use name. |
2381 | idx = findoption((const char *)name); |
2382 | if (idx < 0) { // Not found (should not happen). |
2383 | internal_error("set_string_option_direct()" ); |
2384 | IEMSG2(_("For option %s" ), name); |
2385 | return; |
2386 | } |
2387 | } |
2388 | |
2389 | if (options[idx].var == NULL) { // can't set hidden option |
2390 | return; |
2391 | } |
2392 | |
2393 | assert((void *) options[idx].var != (void *) &p_shada); |
2394 | |
2395 | s = vim_strsave(val); |
2396 | { |
2397 | varp = (char_u **)get_varp_scope(&(options[idx]), |
2398 | both ? OPT_LOCAL : opt_flags); |
2399 | if ((opt_flags & OPT_FREE) && (options[idx].flags & P_ALLOCED)) { |
2400 | free_string_option(*varp); |
2401 | } |
2402 | *varp = s; |
2403 | |
2404 | // For buffer/window local option may also set the global value. |
2405 | if (both) { |
2406 | set_string_option_global(idx, varp); |
2407 | } |
2408 | |
2409 | options[idx].flags |= P_ALLOCED; |
2410 | |
2411 | /* When setting both values of a global option with a local value, |
2412 | * make the local value empty, so that the global value is used. */ |
2413 | if (((int)options[idx].indir & PV_BOTH) && both) { |
2414 | free_string_option(*varp); |
2415 | *varp = empty_option; |
2416 | } |
2417 | if (set_sid != SID_NONE) { |
2418 | sctx_T script_ctx; |
2419 | |
2420 | if (set_sid == 0) { |
2421 | script_ctx = current_sctx; |
2422 | } else { |
2423 | script_ctx.sc_sid = set_sid; |
2424 | script_ctx.sc_seq = 0; |
2425 | script_ctx.sc_lnum = 0; |
2426 | } |
2427 | set_option_sctx_idx(idx, opt_flags, script_ctx); |
2428 | } |
2429 | } |
2430 | } |
2431 | |
2432 | /* |
2433 | * Set global value for string option when it's a local option. |
2434 | */ |
2435 | static void |
2436 | set_string_option_global( |
2437 | int opt_idx, // option index |
2438 | char_u **varp // pointer to option variable |
2439 | ) |
2440 | { |
2441 | char_u **p, *s; |
2442 | |
2443 | // the global value is always allocated |
2444 | if (options[opt_idx].var == VAR_WIN) { |
2445 | p = (char_u **)GLOBAL_WO(varp); |
2446 | } else { |
2447 | p = (char_u **)options[opt_idx].var; |
2448 | } |
2449 | if (options[opt_idx].indir != PV_NONE && p != varp) { |
2450 | s = vim_strsave(*varp); |
2451 | free_string_option(*p); |
2452 | *p = s; |
2453 | } |
2454 | } |
2455 | |
2456 | /// Set a string option to a new value, handling the effects |
2457 | /// |
2458 | /// @param[in] opt_idx Option to set. |
2459 | /// @param[in] value New value. |
2460 | /// @param[in] opt_flags Option flags: expected to contain #OPT_LOCAL and/or |
2461 | /// #OPT_GLOBAL. |
2462 | /// |
2463 | /// @return NULL on success, error message on error. |
2464 | static char *set_string_option(const int opt_idx, const char *const value, |
2465 | const int opt_flags) |
2466 | FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT |
2467 | { |
2468 | if (options[opt_idx].var == NULL) { // don't set hidden option |
2469 | return NULL; |
2470 | } |
2471 | |
2472 | char *const s = xstrdup(value); |
2473 | char **const varp = (char **)get_varp_scope( |
2474 | &(options[opt_idx]), |
2475 | ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 |
2476 | ? (((int)options[opt_idx].indir & PV_BOTH) |
2477 | ? OPT_GLOBAL : OPT_LOCAL) |
2478 | : opt_flags)); |
2479 | char *const oldval = *varp; |
2480 | *varp = s; |
2481 | |
2482 | char *const saved_oldval = xstrdup(oldval); |
2483 | char *const saved_newval = xstrdup(s); |
2484 | |
2485 | int value_checked = false; |
2486 | char *const r = (char *)did_set_string_option( |
2487 | opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, |
2488 | NULL, 0, opt_flags, &value_checked); |
2489 | if (r == NULL) { |
2490 | did_set_option(opt_idx, opt_flags, true, value_checked); |
2491 | } |
2492 | |
2493 | // call autocommand after handling side effects |
2494 | if (r == NULL) { |
2495 | if (!starting) { |
2496 | trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval); |
2497 | } |
2498 | if (options[opt_idx].flags & P_UI_OPTION) { |
2499 | ui_call_option_set(cstr_as_string(options[opt_idx].fullname), |
2500 | STRING_OBJ(cstr_as_string(saved_newval))); |
2501 | } |
2502 | } |
2503 | xfree(saved_oldval); |
2504 | xfree(saved_newval); |
2505 | |
2506 | return r; |
2507 | } |
2508 | |
2509 | /// Return true if "val" is a valid 'filetype' name. |
2510 | /// Also used for 'syntax' and 'keymap'. |
2511 | static bool valid_filetype(char_u *val) |
2512 | { |
2513 | for (char_u *s = val; *s != NUL; s++) { |
2514 | if (!ASCII_ISALNUM(*s) && vim_strchr((char_u *)".-_" , *s) == NULL) { |
2515 | return false; |
2516 | } |
2517 | } |
2518 | return true; |
2519 | } |
2520 | |
2521 | /// Handle string options that need some action to perform when changed. |
2522 | /// Returns NULL for success, or an error message for an error. |
2523 | static char_u * |
2524 | did_set_string_option( |
2525 | int opt_idx, // index in options[] table |
2526 | char_u **varp, // pointer to the option variable |
2527 | int new_value_alloced, // new value was allocated |
2528 | char_u *oldval, // previous value of the option |
2529 | char_u *errbuf, // buffer for errors, or NULL |
2530 | size_t errbuflen, // length of errors buffer |
2531 | int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL |
2532 | int *value_checked // value was checked to be safe, no |
2533 | // need to set P_INSECURE |
2534 | ) |
2535 | { |
2536 | char_u *errmsg = NULL; |
2537 | char_u *s, *p; |
2538 | int did_chartab = false; |
2539 | char_u **gvarp; |
2540 | bool free_oldval = (options[opt_idx].flags & P_ALLOCED); |
2541 | bool value_changed = false; |
2542 | |
2543 | /* Get the global option to compare with, otherwise we would have to check |
2544 | * two values for all local options. */ |
2545 | gvarp = (char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL); |
2546 | |
2547 | // Disallow changing some options from secure mode |
2548 | if ((secure || sandbox != 0) |
2549 | && (options[opt_idx].flags & P_SECURE)) { |
2550 | errmsg = e_secure; |
2551 | } else if (((options[opt_idx].flags & P_NFNAME) |
2552 | && vim_strpbrk(*varp, (char_u *)(secure ? "/\\*?[|;&<>\r\n" |
2553 | : "/\\*?[<>\r\n" )) != NULL) |
2554 | || ((options[opt_idx].flags & P_NDNAME) |
2555 | && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n" ) != NULL)) { |
2556 | // Check for a "normal" directory or file name in some options. Disallow a |
2557 | // path separator (slash and/or backslash), wildcards and characters that |
2558 | // are often illegal in a file name. Be more permissive if "secure" is off. |
2559 | errmsg = e_invarg; |
2560 | } else if (gvarp == &p_bkc) { // 'backupcopy' |
2561 | char_u *bkc = p_bkc; |
2562 | unsigned int *flags = &bkc_flags; |
2563 | |
2564 | if (opt_flags & OPT_LOCAL) { |
2565 | bkc = curbuf->b_p_bkc; |
2566 | flags = &curbuf->b_bkc_flags; |
2567 | } |
2568 | |
2569 | if ((opt_flags & OPT_LOCAL) && *bkc == NUL) { |
2570 | // make the local value empty: use the global value |
2571 | *flags = 0; |
2572 | } else { |
2573 | if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) { |
2574 | errmsg = e_invarg; |
2575 | } |
2576 | |
2577 | if (((*flags & BKC_AUTO) != 0) |
2578 | + ((*flags & BKC_YES) != 0) |
2579 | + ((*flags & BKC_NO) != 0) != 1) { |
2580 | // Must have exactly one of "auto", "yes" and "no". |
2581 | (void)opt_strings_flags(oldval, p_bkc_values, flags, true); |
2582 | errmsg = e_invarg; |
2583 | } |
2584 | } |
2585 | } else if (varp == &p_bex || varp == &p_pm) { // 'backupext' and 'patchmode' |
2586 | if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex, |
2587 | *p_pm == '.' ? p_pm + 1 : p_pm) == 0) { |
2588 | errmsg = (char_u *)N_("E589: 'backupext' and 'patchmode' are equal" ); |
2589 | } |
2590 | } else if (varp == &curwin->w_p_briopt) { // 'breakindentopt' |
2591 | if (briopt_check(curwin) == FAIL) { |
2592 | errmsg = e_invarg; |
2593 | } |
2594 | } else if (varp == &p_isi |
2595 | || varp == &(curbuf->b_p_isk) |
2596 | || varp == &p_isp |
2597 | || varp == &p_isf) { |
2598 | // 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[] |
2599 | // If the new option is invalid, use old value. 'lisp' option: refill |
2600 | // g_chartab[] for '-' char |
2601 | if (init_chartab() == FAIL) { |
2602 | did_chartab = true; // need to restore it below |
2603 | errmsg = e_invarg; // error in value |
2604 | } |
2605 | } else if (varp == &p_hf) { // 'helpfile' |
2606 | // May compute new values for $VIM and $VIMRUNTIME |
2607 | if (didset_vim) { |
2608 | os_setenv("VIM" , "" , 1); |
2609 | didset_vim = false; |
2610 | } |
2611 | if (didset_vimruntime) { |
2612 | os_setenv("VIMRUNTIME" , "" , 1); |
2613 | didset_vimruntime = false; |
2614 | } |
2615 | } else if (varp == &curwin->w_p_cc) { // 'colorcolumn' |
2616 | errmsg = check_colorcolumn(curwin); |
2617 | } else if (varp == &p_hlg) { // 'helplang' |
2618 | // Check for "", "ab", "ab,cd", etc. |
2619 | for (s = p_hlg; *s != NUL; s += 3) { |
2620 | if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) { |
2621 | errmsg = e_invarg; |
2622 | break; |
2623 | } |
2624 | if (s[2] == NUL) { |
2625 | break; |
2626 | } |
2627 | } |
2628 | } else if (varp == &p_hl) { |
2629 | // 'highlight' |
2630 | if (strcmp((char *)(*varp), HIGHLIGHT_INIT) != 0) { |
2631 | errmsg = e_unsupportedoption; |
2632 | } |
2633 | } else if (gvarp == &p_nf) { // 'nrformats' |
2634 | if (check_opt_strings(*varp, p_nf_values, true) != OK) { |
2635 | errmsg = e_invarg; |
2636 | } |
2637 | } else if (varp == &p_ssop) { // 'sessionoptions' |
2638 | if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) { |
2639 | errmsg = e_invarg; |
2640 | } |
2641 | if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) { |
2642 | // Don't allow both "sesdir" and "curdir". |
2643 | (void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true); |
2644 | errmsg = e_invarg; |
2645 | } |
2646 | } else if (varp == &p_vop) { // 'viewoptions' |
2647 | if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) { |
2648 | errmsg = e_invarg; |
2649 | } |
2650 | } else if (varp == &p_rdb) { // 'redrawdebug' |
2651 | if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { |
2652 | errmsg = e_invarg; |
2653 | } |
2654 | } else if (varp == &p_sbo) { // 'scrollopt' |
2655 | if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { |
2656 | errmsg = e_invarg; |
2657 | } |
2658 | } else if (varp == &p_ambw || (int *)varp == &p_emoji) { |
2659 | // 'ambiwidth' |
2660 | if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) { |
2661 | errmsg = e_invarg; |
2662 | } else { |
2663 | FOR_ALL_TAB_WINDOWS(tp, wp) { |
2664 | if (set_chars_option(wp, &wp->w_p_lcs) != NULL) { |
2665 | errmsg = (char_u *)_("E834: Conflicts with value of 'listchars'" ); |
2666 | goto ambw_end; |
2667 | } |
2668 | if (set_chars_option(wp, &wp->w_p_fcs) != NULL) { |
2669 | errmsg = (char_u *)_("E835: Conflicts with value of 'fillchars'" ); |
2670 | goto ambw_end; |
2671 | } |
2672 | } |
2673 | ambw_end: |
2674 | {} // clint prefers {} over ; as an empty statement |
2675 | } |
2676 | } else if (varp == &p_bg) { // 'background' |
2677 | if (check_opt_strings(p_bg, p_bg_values, false) == OK) { |
2678 | int dark = (*p_bg == 'd'); |
2679 | |
2680 | init_highlight(false, false); |
2681 | |
2682 | if (dark != (*p_bg == 'd') && get_var_value("g:colors_name" ) != NULL) { |
2683 | // The color scheme must have set 'background' back to another |
2684 | // value, that's not what we want here. Disable the color |
2685 | // scheme and set the colors again. |
2686 | do_unlet(S_LEN("g:colors_name" ), true); |
2687 | free_string_option(p_bg); |
2688 | p_bg = vim_strsave((char_u *)(dark ? "dark" : "light" )); |
2689 | check_string_option(&p_bg); |
2690 | init_highlight(false, false); |
2691 | } |
2692 | } else |
2693 | errmsg = e_invarg; |
2694 | } else if (varp == &p_wim) { // 'wildmode' |
2695 | if (check_opt_wim() == FAIL) { |
2696 | errmsg = e_invarg; |
2697 | } |
2698 | // 'wildoptions' |
2699 | } else if (varp == &p_wop) { |
2700 | if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) { |
2701 | errmsg = e_invarg; |
2702 | } |
2703 | } else if (varp == &p_wak) { // 'winaltkeys' |
2704 | if (*p_wak == NUL |
2705 | || check_opt_strings(p_wak, p_wak_values, false) != OK) { |
2706 | errmsg = e_invarg; |
2707 | } |
2708 | } else if (varp == &p_ei) { // 'eventignore' |
2709 | if (check_ei() == FAIL) { |
2710 | errmsg = e_invarg; |
2711 | } |
2712 | // 'encoding', 'fileencoding' and 'makeencoding' |
2713 | } else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) { |
2714 | if (gvarp == &p_fenc) { |
2715 | if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) { |
2716 | errmsg = e_modifiable; |
2717 | } else if (vim_strchr(*varp, ',') != NULL) { |
2718 | // No comma allowed in 'fileencoding'; catches confusing it |
2719 | // with 'fileencodings'. |
2720 | errmsg = e_invarg; |
2721 | } else { |
2722 | // May show a "+" in the title now. |
2723 | redraw_titles(); |
2724 | // Add 'fileencoding' to the swap file. |
2725 | ml_setflags(curbuf); |
2726 | } |
2727 | } |
2728 | |
2729 | if (errmsg == NULL) { |
2730 | // canonize the value, so that STRCMP() can be used on it |
2731 | p = enc_canonize(*varp); |
2732 | xfree(*varp); |
2733 | *varp = p; |
2734 | if (varp == &p_enc) { |
2735 | // only encoding=utf-8 allowed |
2736 | if (STRCMP(p_enc, "utf-8" ) != 0) { |
2737 | errmsg = e_unsupportedoption; |
2738 | } |
2739 | } |
2740 | } |
2741 | } else if (varp == &p_penc) { |
2742 | // Canonize printencoding if VIM standard one |
2743 | p = enc_canonize(p_penc); |
2744 | xfree(p_penc); |
2745 | p_penc = p; |
2746 | } else if (varp == &curbuf->b_p_keymap) { |
2747 | if (!valid_filetype(*varp)) { |
2748 | errmsg = e_invarg; |
2749 | } else { |
2750 | int secure_save = secure; |
2751 | |
2752 | // Reset the secure flag, since the value of 'keymap' has |
2753 | // been checked to be safe. |
2754 | secure = 0; |
2755 | |
2756 | // load or unload key mapping tables |
2757 | errmsg = keymap_init(); |
2758 | |
2759 | secure = secure_save; |
2760 | |
2761 | // Since we check the value, there is no need to set P_INSECURE, |
2762 | // even when the value comes from a modeline. |
2763 | *value_checked = true; |
2764 | } |
2765 | |
2766 | if (errmsg == NULL) { |
2767 | if (*curbuf->b_p_keymap != NUL) { |
2768 | // Installed a new keymap, switch on using it. |
2769 | curbuf->b_p_iminsert = B_IMODE_LMAP; |
2770 | if (curbuf->b_p_imsearch != B_IMODE_USE_INSERT) { |
2771 | curbuf->b_p_imsearch = B_IMODE_LMAP; |
2772 | } |
2773 | } else { |
2774 | // Cleared the keymap, may reset 'iminsert' and 'imsearch'. |
2775 | if (curbuf->b_p_iminsert == B_IMODE_LMAP) { |
2776 | curbuf->b_p_iminsert = B_IMODE_NONE; |
2777 | } |
2778 | if (curbuf->b_p_imsearch == B_IMODE_LMAP) { |
2779 | curbuf->b_p_imsearch = B_IMODE_USE_INSERT; |
2780 | } |
2781 | } |
2782 | if ((opt_flags & OPT_LOCAL) == 0) { |
2783 | set_iminsert_global(); |
2784 | set_imsearch_global(); |
2785 | } |
2786 | status_redraw_curbuf(); |
2787 | } |
2788 | } else if (gvarp == &p_ff) { // 'fileformat' |
2789 | if (!MODIFIABLE(curbuf) && !(opt_flags & OPT_GLOBAL)) { |
2790 | errmsg = e_modifiable; |
2791 | } else if (check_opt_strings(*varp, p_ff_values, false) != OK) { |
2792 | errmsg = e_invarg; |
2793 | } else { |
2794 | redraw_titles(); |
2795 | // update flag in swap file |
2796 | ml_setflags(curbuf); |
2797 | /* Redraw needed when switching to/from "mac": a CR in the text |
2798 | * will be displayed differently. */ |
2799 | if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm') { |
2800 | redraw_curbuf_later(NOT_VALID); |
2801 | } |
2802 | } |
2803 | } else if (varp == &p_ffs) { // 'fileformats' |
2804 | if (check_opt_strings(p_ffs, p_ff_values, true) != OK) { |
2805 | errmsg = e_invarg; |
2806 | } |
2807 | } else if (gvarp == &p_mps) { // 'matchpairs' |
2808 | if (has_mbyte) { |
2809 | for (p = *varp; *p != NUL; p++) { |
2810 | int x2 = -1; |
2811 | int x3 = -1; |
2812 | |
2813 | if (*p != NUL) { |
2814 | p += mb_ptr2len(p); |
2815 | } |
2816 | if (*p != NUL) { |
2817 | x2 = *p++; |
2818 | } |
2819 | if (*p != NUL) { |
2820 | x3 = utf_ptr2char(p); |
2821 | p += mb_ptr2len(p); |
2822 | } |
2823 | if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { |
2824 | errmsg = e_invarg; |
2825 | break; |
2826 | } |
2827 | if (*p == NUL) { |
2828 | break; |
2829 | } |
2830 | } |
2831 | } else { |
2832 | // Check for "x:y,x:y" |
2833 | for (p = *varp; *p != NUL; p += 4) { |
2834 | if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ',')) { |
2835 | errmsg = e_invarg; |
2836 | break; |
2837 | } |
2838 | if (p[3] == NUL) { |
2839 | break; |
2840 | } |
2841 | } |
2842 | } |
2843 | } else if (gvarp == &p_com) { // 'comments' |
2844 | for (s = *varp; *s; ) { |
2845 | while (*s && *s != ':') { |
2846 | if (vim_strchr((char_u *)COM_ALL, *s) == NULL |
2847 | && !ascii_isdigit(*s) && *s != '-') { |
2848 | errmsg = illegal_char(errbuf, errbuflen, *s); |
2849 | break; |
2850 | } |
2851 | s++; |
2852 | } |
2853 | if (*s++ == NUL) { |
2854 | errmsg = (char_u *)N_("E524: Missing colon" ); |
2855 | } else if (*s == ',' || *s == NUL) { |
2856 | errmsg = (char_u *)N_("E525: Zero length string" ); |
2857 | } |
2858 | if (errmsg != NULL) { |
2859 | break; |
2860 | } |
2861 | while (*s && *s != ',') { |
2862 | if (*s == '\\' && s[1] != NUL) { |
2863 | s++; |
2864 | } |
2865 | s++; |
2866 | } |
2867 | s = skip_to_option_part(s); |
2868 | } |
2869 | } else if (varp == &curwin->w_p_lcs) { // 'listchars' |
2870 | errmsg = set_chars_option(curwin, varp); |
2871 | } else if (varp == &curwin->w_p_fcs) { // 'fillchars' |
2872 | errmsg = set_chars_option(curwin, varp); |
2873 | } else if (varp == &p_cedit) { // 'cedit' |
2874 | errmsg = check_cedit(); |
2875 | } else if (varp == &p_vfile) { // 'verbosefile' |
2876 | verbose_stop(); |
2877 | if (*p_vfile != NUL && verbose_open() == FAIL) { |
2878 | errmsg = e_invarg; |
2879 | } |
2880 | // 'shada' |
2881 | } else if (varp == &p_shada) { |
2882 | // TODO(ZyX-I): Remove this code in the future, alongside with &viminfo |
2883 | // option. |
2884 | opt_idx = ((options[opt_idx].fullname[0] == 'v') |
2885 | ? (shada_idx == -1 |
2886 | ? ((shada_idx = findoption("shada" ))) |
2887 | : shada_idx) |
2888 | : opt_idx); |
2889 | // Update free_oldval now that we have the opt_idx for 'shada', otherwise |
2890 | // there would be a disconnect between the check for P_ALLOCED at the start |
2891 | // of the function and the set of P_ALLOCED at the end of the fuction. |
2892 | free_oldval = (options[opt_idx].flags & P_ALLOCED); |
2893 | for (s = p_shada; *s; ) { |
2894 | // Check it's a valid character |
2895 | if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs" , *s) == NULL) { |
2896 | errmsg = illegal_char(errbuf, errbuflen, *s); |
2897 | break; |
2898 | } |
2899 | if (*s == 'n') { // name is always last one |
2900 | break; |
2901 | } else if (*s == 'r') { // skip until next ',' |
2902 | while (*++s && *s != ',') {} |
2903 | } else if (*s == '%') { |
2904 | // optional number |
2905 | while (ascii_isdigit(*++s)) {} |
2906 | } else if (*s == '!' || *s == 'h' || *s == 'c') { |
2907 | s++; // no extra chars |
2908 | } else { // must have a number |
2909 | while (ascii_isdigit(*++s)) {} |
2910 | |
2911 | if (!ascii_isdigit(*(s - 1))) { |
2912 | if (errbuf != NULL) { |
2913 | vim_snprintf((char *)errbuf, errbuflen, |
2914 | _("E526: Missing number after <%s>" ), |
2915 | transchar_byte(*(s - 1))); |
2916 | errmsg = errbuf; |
2917 | } else |
2918 | errmsg = (char_u *)"" ; |
2919 | break; |
2920 | } |
2921 | } |
2922 | if (*s == ',') { |
2923 | s++; |
2924 | } else if (*s) { |
2925 | if (errbuf != NULL) { |
2926 | errmsg = (char_u *)N_("E527: Missing comma" ); |
2927 | } else { |
2928 | errmsg = (char_u *)"" ; |
2929 | } |
2930 | break; |
2931 | } |
2932 | } |
2933 | if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) { |
2934 | errmsg = (char_u *)N_("E528: Must specify a ' value" ); |
2935 | } |
2936 | } else if (varp == &p_sbr) { // 'showbreak' |
2937 | for (s = p_sbr; *s; ) { |
2938 | if (ptr2cells(s) != 1) { |
2939 | errmsg = (char_u *)N_("E595: contains unprintable or wide character" ); |
2940 | } |
2941 | MB_PTR_ADV(s); |
2942 | } |
2943 | } else if (varp == &p_guicursor) { // 'guicursor' |
2944 | errmsg = parse_shape_opt(SHAPE_CURSOR); |
2945 | } else if (varp == &p_popt) { |
2946 | errmsg = parse_printoptions(); |
2947 | } else if (varp == &p_pmfn) { |
2948 | errmsg = parse_printmbfont(); |
2949 | } else if (varp == &p_langmap) { // 'langmap' |
2950 | langmap_set(); |
2951 | } else if (varp == &p_breakat) { // 'breakat' |
2952 | fill_breakat_flags(); |
2953 | } else if (varp == &p_titlestring || varp == &p_iconstring) { |
2954 | // 'titlestring' and 'iconstring' |
2955 | int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON; |
2956 | |
2957 | // NULL => statusline syntax |
2958 | if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) { |
2959 | stl_syntax |= flagval; |
2960 | } else { |
2961 | stl_syntax &= ~flagval; |
2962 | } |
2963 | did_set_title(varp == &p_iconstring); |
2964 | |
2965 | } else if (varp == &p_sel) { // 'selection' |
2966 | if (*p_sel == NUL |
2967 | || check_opt_strings(p_sel, p_sel_values, false) != OK) { |
2968 | errmsg = e_invarg; |
2969 | } |
2970 | } else if (varp == &p_slm) { // 'selectmode' |
2971 | if (check_opt_strings(p_slm, p_slm_values, true) != OK) { |
2972 | errmsg = e_invarg; |
2973 | } |
2974 | } else if (varp == &p_km) { // 'keymodel' |
2975 | if (check_opt_strings(p_km, p_km_values, true) != OK) { |
2976 | errmsg = e_invarg; |
2977 | } else { |
2978 | km_stopsel = (vim_strchr(p_km, 'o') != NULL); |
2979 | km_startsel = (vim_strchr(p_km, 'a') != NULL); |
2980 | } |
2981 | } else if (varp == &p_mousem) { // 'mousemodel' |
2982 | if (check_opt_strings(p_mousem, p_mousem_values, false) != OK) { |
2983 | errmsg = e_invarg; |
2984 | } |
2985 | } else if (varp == &p_swb) { // 'switchbuf' |
2986 | if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) { |
2987 | errmsg = e_invarg; |
2988 | } |
2989 | } else if (varp == &p_debug) { // 'debug' |
2990 | if (check_opt_strings(p_debug, p_debug_values, true) != OK) { |
2991 | errmsg = e_invarg; |
2992 | } |
2993 | } else if (varp == &p_dy) { // 'display' |
2994 | if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) { |
2995 | errmsg = e_invarg; |
2996 | } else { |
2997 | (void)init_chartab(); |
2998 | msg_grid_validate(); |
2999 | } |
3000 | } else if (varp == &p_ead) { // 'eadirection' |
3001 | if (check_opt_strings(p_ead, p_ead_values, false) != OK) { |
3002 | errmsg = e_invarg; |
3003 | } |
3004 | } else if (varp == &p_cb) { // 'clipboard' |
3005 | if (opt_strings_flags(p_cb, p_cb_values, &cb_flags, true) != OK) { |
3006 | errmsg = e_invarg; |
3007 | } |
3008 | } else if (varp == &(curwin->w_s->b_p_spl) // 'spell' |
3009 | || varp == &(curwin->w_s->b_p_spf)) { |
3010 | // When 'spelllang' or 'spellfile' is set and there is a window for this |
3011 | // buffer in which 'spell' is set load the wordlists. |
3012 | errmsg = did_set_spell_option(varp == &(curwin->w_s->b_p_spf)); |
3013 | } else if (varp == &(curwin->w_s->b_p_spc)) { |
3014 | // When 'spellcapcheck' is set compile the regexp program. |
3015 | errmsg = compile_cap_prog(curwin->w_s); |
3016 | } else if (varp == &p_sps) { // 'spellsuggest' |
3017 | if (spell_check_sps() != OK) { |
3018 | errmsg = e_invarg; |
3019 | } |
3020 | } else if (varp == &p_msm) { // 'mkspellmem' |
3021 | if (spell_check_msm() != OK) { |
3022 | errmsg = e_invarg; |
3023 | } |
3024 | } else if (gvarp == &p_bh) { |
3025 | // When 'bufhidden' is set, check for valid value. |
3026 | if (check_opt_strings(curbuf->b_p_bh, p_bufhidden_values, false) != OK) { |
3027 | errmsg = e_invarg; |
3028 | } |
3029 | } else if (gvarp == &p_bt) { |
3030 | // When 'buftype' is set, check for valid value. |
3031 | if ((curbuf->terminal && curbuf->b_p_bt[0] != 't') |
3032 | || (!curbuf->terminal && curbuf->b_p_bt[0] == 't') |
3033 | || check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) { |
3034 | errmsg = e_invarg; |
3035 | } else { |
3036 | if (curwin->w_status_height) { |
3037 | curwin->w_redr_status = true; |
3038 | redraw_later(VALID); |
3039 | } |
3040 | curbuf->b_help = (curbuf->b_p_bt[0] == 'h'); |
3041 | redraw_titles(); |
3042 | } |
3043 | } else if (gvarp == &p_stl || varp == &p_ruf) { |
3044 | // 'statusline' or 'rulerformat' |
3045 | int wid; |
3046 | |
3047 | if (varp == &p_ruf) { // reset ru_wid first |
3048 | ru_wid = 0; |
3049 | } |
3050 | s = *varp; |
3051 | if (varp == &p_ruf && *s == '%') { |
3052 | // set ru_wid if 'ruf' starts with "%99(" |
3053 | if (*++s == '-') { // ignore a '-' |
3054 | s++; |
3055 | } |
3056 | wid = getdigits_int(&s, true, 0); |
3057 | if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) { |
3058 | ru_wid = wid; |
3059 | } else { |
3060 | errmsg = check_stl_option(p_ruf); |
3061 | } |
3062 | } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') { |
3063 | // check 'statusline' only if it doesn't start with "%!" |
3064 | errmsg = check_stl_option(s); |
3065 | } |
3066 | if (varp == &p_ruf && errmsg == NULL) { |
3067 | comp_col(); |
3068 | } |
3069 | } else if (gvarp == &p_cpt) { |
3070 | // check if it is a valid value for 'complete' -- Acevedo |
3071 | for (s = *varp; *s; ) { |
3072 | while (*s == ',' || *s == ' ') |
3073 | s++; |
3074 | if (!*s) { |
3075 | break; |
3076 | } |
3077 | if (vim_strchr((char_u *)".wbuksid]tU" , *s) == NULL) { |
3078 | errmsg = illegal_char(errbuf, errbuflen, *s); |
3079 | break; |
3080 | } |
3081 | if (*++s != NUL && *s != ',' && *s != ' ') { |
3082 | if (s[-1] == 'k' || s[-1] == 's') { |
3083 | // skip optional filename after 'k' and 's' |
3084 | while (*s && *s != ',' && *s != ' ') { |
3085 | if (*s == '\\' && s[1] != NUL) { |
3086 | s++; |
3087 | } |
3088 | s++; |
3089 | } |
3090 | } else { |
3091 | if (errbuf != NULL) { |
3092 | vim_snprintf((char *)errbuf, errbuflen, |
3093 | _("E535: Illegal character after <%c>" ), |
3094 | *--s); |
3095 | errmsg = errbuf; |
3096 | } else |
3097 | errmsg = (char_u *)"" ; |
3098 | break; |
3099 | } |
3100 | } |
3101 | } |
3102 | } else if (varp == &p_cot) { // 'completeopt' |
3103 | if (check_opt_strings(p_cot, p_cot_values, true) != OK) { |
3104 | errmsg = e_invarg; |
3105 | } else { |
3106 | completeopt_was_set(); |
3107 | } |
3108 | } else if (varp == &curwin->w_p_scl) { |
3109 | // 'signcolumn' |
3110 | if (check_opt_strings(*varp, p_scl_values, false) != OK) { |
3111 | errmsg = e_invarg; |
3112 | } |
3113 | } else if (varp == &p_pt) { |
3114 | // 'pastetoggle': translate key codes like in a mapping |
3115 | if (*p_pt) { |
3116 | (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, true, |
3117 | CPO_TO_CPO_FLAGS); |
3118 | if (p != NULL) { |
3119 | if (new_value_alloced) { |
3120 | free_string_option(p_pt); |
3121 | } |
3122 | p_pt = p; |
3123 | new_value_alloced = true; |
3124 | } |
3125 | } |
3126 | } else if (varp == &p_bs) { // 'backspace' |
3127 | if (ascii_isdigit(*p_bs)) { |
3128 | if (*p_bs >'2' || p_bs[1] != NUL) { |
3129 | errmsg = e_invarg; |
3130 | } |
3131 | } else if (check_opt_strings(p_bs, p_bs_values, true) != OK) { |
3132 | errmsg = e_invarg; |
3133 | } |
3134 | } else if (varp == &p_bo) { |
3135 | if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) { |
3136 | errmsg = e_invarg; |
3137 | } |
3138 | } else if (gvarp == &p_tc) { // 'tagcase' |
3139 | unsigned int *flags; |
3140 | |
3141 | if (opt_flags & OPT_LOCAL) { |
3142 | p = curbuf->b_p_tc; |
3143 | flags = &curbuf->b_tc_flags; |
3144 | } else { |
3145 | p = p_tc; |
3146 | flags = &tc_flags; |
3147 | } |
3148 | |
3149 | if ((opt_flags & OPT_LOCAL) && *p == NUL) { |
3150 | // make the local value empty: use the global value |
3151 | *flags = 0; |
3152 | } else if (*p == NUL |
3153 | || opt_strings_flags(p, p_tc_values, flags, false) != OK) { |
3154 | errmsg = e_invarg; |
3155 | } |
3156 | } else if (varp == &p_cmp) { // 'casemap' |
3157 | if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK) { |
3158 | errmsg = e_invarg; |
3159 | } |
3160 | } else if (varp == &p_dip) { // 'diffopt' |
3161 | if (diffopt_changed() == FAIL) { |
3162 | errmsg = e_invarg; |
3163 | } |
3164 | } else if (gvarp == &curwin->w_allbuf_opt.wo_fdm) { // 'foldmethod' |
3165 | if (check_opt_strings(*varp, p_fdm_values, false) != OK |
3166 | || *curwin->w_p_fdm == NUL) { |
3167 | errmsg = e_invarg; |
3168 | } else { |
3169 | foldUpdateAll(curwin); |
3170 | if (foldmethodIsDiff(curwin)) { |
3171 | newFoldLevel(); |
3172 | } |
3173 | } |
3174 | } else if (varp == &curwin->w_p_fde) { // 'foldexpr' |
3175 | if (foldmethodIsExpr(curwin)) { |
3176 | foldUpdateAll(curwin); |
3177 | } |
3178 | } else if (gvarp == &curwin->w_allbuf_opt.wo_fmr) { // 'foldmarker' |
3179 | p = vim_strchr(*varp, ','); |
3180 | if (p == NULL) { |
3181 | errmsg = (char_u *)N_("E536: comma required" ); |
3182 | } else if (p == *varp || p[1] == NUL) { |
3183 | errmsg = e_invarg; |
3184 | } else if (foldmethodIsMarker(curwin)) { |
3185 | foldUpdateAll(curwin); |
3186 | } |
3187 | } else if (gvarp == &p_cms) { // 'commentstring' |
3188 | if (**varp != NUL && strstr((char *)(*varp), "%s" ) == NULL) { |
3189 | errmsg = (char_u *)N_( |
3190 | "E537: 'commentstring' must be empty or contain %s" ); |
3191 | } |
3192 | } else if (varp == &p_fdo) { // 'foldopen' |
3193 | if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) { |
3194 | errmsg = e_invarg; |
3195 | } |
3196 | } else if (varp == &p_fcl) { // 'foldclose' |
3197 | if (check_opt_strings(p_fcl, p_fcl_values, true) != OK) { |
3198 | errmsg = e_invarg; |
3199 | } |
3200 | } else if (gvarp == &curwin->w_allbuf_opt.wo_fdi) { // 'foldignore' |
3201 | if (foldmethodIsIndent(curwin)) { |
3202 | foldUpdateAll(curwin); |
3203 | } |
3204 | } else if (varp == &p_ve) { // 'virtualedit' |
3205 | if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, true) != OK) { |
3206 | errmsg = e_invarg; |
3207 | } else if (STRCMP(p_ve, oldval) != 0) { |
3208 | // Recompute cursor position in case the new 've' setting |
3209 | // changes something. |
3210 | validate_virtcol(); |
3211 | coladvance(curwin->w_virtcol); |
3212 | } |
3213 | } else if (varp == &p_csqf) { |
3214 | if (p_csqf != NULL) { |
3215 | p = p_csqf; |
3216 | while (*p != NUL) { |
3217 | if (vim_strchr((char_u *)CSQF_CMDS, *p) == NULL |
3218 | || p[1] == NUL |
3219 | || vim_strchr((char_u *)CSQF_FLAGS, p[1]) == NULL |
3220 | || (p[2] != NUL && p[2] != ',')) { |
3221 | errmsg = e_invarg; |
3222 | break; |
3223 | } else if (p[2] == NUL) { |
3224 | break; |
3225 | } else { |
3226 | p += 3; |
3227 | } |
3228 | } |
3229 | } |
3230 | } else if (gvarp == &p_cino) { // 'cinoptions' |
3231 | // TODO(vim): recognize errors |
3232 | parse_cino(curbuf); |
3233 | // inccommand |
3234 | } else if (varp == &p_icm) { |
3235 | if (check_opt_strings(p_icm, p_icm_values, false) != OK) { |
3236 | errmsg = e_invarg; |
3237 | } |
3238 | } else if (gvarp == &p_ft) { |
3239 | if (!valid_filetype(*varp)) { |
3240 | errmsg = e_invarg; |
3241 | } else { |
3242 | value_changed = STRCMP(oldval, *varp) != 0; |
3243 | |
3244 | // Since we check the value, there is no need to set P_INSECURE, |
3245 | // even when the value comes from a modeline. |
3246 | *value_checked = true; |
3247 | } |
3248 | } else if (gvarp == &p_syn) { |
3249 | if (!valid_filetype(*varp)) { |
3250 | errmsg = e_invarg; |
3251 | } else { |
3252 | value_changed = STRCMP(oldval, *varp) != 0; |
3253 | |
3254 | // Since we check the value, there is no need to set P_INSECURE, |
3255 | // even when the value comes from a modeline. |
3256 | *value_checked = true; |
3257 | } |
3258 | } else if (varp == &curwin->w_p_winhl) { |
3259 | if (!parse_winhl_opt(curwin)) { |
3260 | errmsg = e_invarg; |
3261 | } |
3262 | } else { |
3263 | // Options that are a list of flags. |
3264 | p = NULL; |
3265 | if (varp == &p_ww) { // 'whichwrap' |
3266 | p = (char_u *)WW_ALL; |
3267 | } |
3268 | if (varp == &p_shm) { // 'shortmess' |
3269 | p = (char_u *)SHM_ALL; |
3270 | } else if (varp == &(p_cpo)) { // 'cpoptions' |
3271 | p = (char_u *)CPO_VI; |
3272 | } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions' |
3273 | p = (char_u *)FO_ALL; |
3274 | } else if (varp == &curwin->w_p_cocu) { // 'concealcursor' |
3275 | p = (char_u *)COCU_ALL; |
3276 | } else if (varp == &p_mouse) { // 'mouse' |
3277 | p = (char_u *)MOUSE_ALL; |
3278 | } |
3279 | if (p != NULL) { |
3280 | for (s = *varp; *s; s++) { |
3281 | if (vim_strchr(p, *s) == NULL) { |
3282 | errmsg = illegal_char(errbuf, errbuflen, *s); |
3283 | break; |
3284 | } |
3285 | } |
3286 | } |
3287 | } |
3288 | |
3289 | /* |
3290 | * If error detected, restore the previous value. |
3291 | */ |
3292 | if (errmsg != NULL) { |
3293 | if (new_value_alloced) { |
3294 | free_string_option(*varp); |
3295 | } |
3296 | *varp = oldval; |
3297 | /* |
3298 | * When resetting some values, need to act on it. |
3299 | */ |
3300 | if (did_chartab) { |
3301 | (void)init_chartab(); |
3302 | } |
3303 | } else { |
3304 | // Remember where the option was set. |
3305 | set_option_sctx_idx(opt_idx, opt_flags, current_sctx); |
3306 | // Free string options that are in allocated memory. |
3307 | // Use "free_oldval", because recursiveness may change the flags under |
3308 | // our fingers (esp. init_highlight()). |
3309 | if (free_oldval) { |
3310 | free_string_option(oldval); |
3311 | } |
3312 | if (new_value_alloced) { |
3313 | options[opt_idx].flags |= P_ALLOCED; |
3314 | } else { |
3315 | options[opt_idx].flags &= ~P_ALLOCED; |
3316 | } |
3317 | |
3318 | if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 |
3319 | && ((int)options[opt_idx].indir & PV_BOTH)) { |
3320 | /* global option with local value set to use global value; free |
3321 | * the local value and make it empty */ |
3322 | p = get_varp_scope(&(options[opt_idx]), OPT_LOCAL); |
3323 | free_string_option(*(char_u **)p); |
3324 | *(char_u **)p = empty_option; |
3325 | } else if (!(opt_flags & OPT_LOCAL) && opt_flags != OPT_GLOBAL) { |
3326 | // May set global value for local option. |
3327 | set_string_option_global(opt_idx, varp); |
3328 | } |
3329 | |
3330 | /* |
3331 | * Trigger the autocommand only after setting the flags. |
3332 | */ |
3333 | // When 'syntax' is set, load the syntax of that name |
3334 | if (varp == &(curbuf->b_p_syn)) { |
3335 | static int syn_recursive = 0; |
3336 | |
3337 | syn_recursive++; |
3338 | // Only pass true for "force" when the value changed or not used |
3339 | // recursively, to avoid endless recurrence. |
3340 | apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname, |
3341 | value_changed || syn_recursive == 1, curbuf); |
3342 | syn_recursive--; |
3343 | } else if (varp == &(curbuf->b_p_ft)) { |
3344 | // 'filetype' is set, trigger the FileType autocommand |
3345 | // Skip this when called from a modeline and the filetype was |
3346 | // already set to this value. |
3347 | if (!(opt_flags & OPT_MODELINE) || value_changed) { |
3348 | static int ft_recursive = 0; |
3349 | int secure_save = secure; |
3350 | |
3351 | // Reset the secure flag, since the value of 'filetype' has |
3352 | // been checked to be safe. |
3353 | secure = 0; |
3354 | |
3355 | ft_recursive++; |
3356 | did_filetype = true; |
3357 | // Only pass true for "force" when the value changed or not |
3358 | // used recursively, to avoid endless recurrence. |
3359 | apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, |
3360 | value_changed || ft_recursive == 1, curbuf); |
3361 | ft_recursive--; |
3362 | // Just in case the old "curbuf" is now invalid |
3363 | if (varp != &(curbuf->b_p_ft)) { |
3364 | varp = NULL; |
3365 | } |
3366 | secure = secure_save; |
3367 | } |
3368 | } |
3369 | if (varp == &(curwin->w_s->b_p_spl)) { |
3370 | char_u fname[200]; |
3371 | char_u *q = curwin->w_s->b_p_spl; |
3372 | |
3373 | // Skip the first name if it is "cjk". |
3374 | if (STRNCMP(q, "cjk," , 4) == 0) { |
3375 | q += 4; |
3376 | } |
3377 | |
3378 | /* |
3379 | * Source the spell/LANG.vim in 'runtimepath'. |
3380 | * They could set 'spellcapcheck' depending on the language. |
3381 | * Use the first name in 'spelllang' up to '_region' or |
3382 | * '.encoding'. |
3383 | */ |
3384 | for (p = q; *p != NUL; p++) { |
3385 | if (!ASCII_ISALNUM(*p) && *p != '-') { |
3386 | break; |
3387 | } |
3388 | } |
3389 | if (p > q) { |
3390 | vim_snprintf((char *)fname, sizeof(fname), "spell/%.*s.vim" , |
3391 | (int)(p - q), q); |
3392 | source_runtime(fname, DIP_ALL); |
3393 | } |
3394 | } |
3395 | } |
3396 | |
3397 | if (varp == &p_mouse) { |
3398 | if (*p_mouse == NUL) { |
3399 | ui_call_mouse_off(); |
3400 | } else { |
3401 | setmouse(); // in case 'mouse' changed |
3402 | } |
3403 | } |
3404 | |
3405 | if (curwin->w_curswant != MAXCOL |
3406 | && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) |
3407 | curwin->w_set_curswant = true; |
3408 | |
3409 | check_redraw(options[opt_idx].flags); |
3410 | |
3411 | return errmsg; |
3412 | } // NOLINT(readability/fn_size) |
3413 | |
3414 | /// Simple int comparison function for use with qsort() |
3415 | static int int_cmp(const void *a, const void *b) |
3416 | { |
3417 | return *(const int *)a - *(const int *)b; |
3418 | } |
3419 | |
3420 | /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". |
3421 | /// |
3422 | /// @return error message, NULL if it's OK. |
3423 | char_u *check_colorcolumn(win_T *wp) |
3424 | { |
3425 | char_u *s; |
3426 | int col; |
3427 | unsigned int count = 0; |
3428 | int color_cols[256]; |
3429 | int j = 0; |
3430 | |
3431 | if (wp->w_buffer == NULL) { |
3432 | return NULL; // buffer was closed |
3433 | } |
3434 | |
3435 | for (s = wp->w_p_cc; *s != NUL && count < 255; ) { |
3436 | if (*s == '-' || *s == '+') { |
3437 | // -N and +N: add to 'textwidth' |
3438 | col = (*s == '-') ? -1 : 1; |
3439 | s++; |
3440 | if (!ascii_isdigit(*s)) { |
3441 | return e_invarg; |
3442 | } |
3443 | col = col * getdigits_int(&s, true, 0); |
3444 | if (wp->w_buffer->b_p_tw == 0) { |
3445 | goto skip; // 'textwidth' not set, skip this item |
3446 | } |
3447 | assert((col >= 0 |
3448 | && wp->w_buffer->b_p_tw <= INT_MAX - col |
3449 | && wp->w_buffer->b_p_tw + col >= INT_MIN) |
3450 | || (col < 0 |
3451 | && wp->w_buffer->b_p_tw >= INT_MIN - col |
3452 | && wp->w_buffer->b_p_tw + col <= INT_MAX)); |
3453 | col += (int)wp->w_buffer->b_p_tw; |
3454 | if (col < 0) { |
3455 | goto skip; |
3456 | } |
3457 | } else if (ascii_isdigit(*s)) { |
3458 | col = getdigits_int(&s, true, 0); |
3459 | } else { |
3460 | return e_invarg; |
3461 | } |
3462 | color_cols[count++] = col - 1; // 1-based to 0-based |
3463 | skip: |
3464 | if (*s == NUL) { |
3465 | break; |
3466 | } |
3467 | if (*s != ',') { |
3468 | return e_invarg; |
3469 | } |
3470 | if (*++s == NUL) { |
3471 | return e_invarg; // illegal trailing comma as in "set cc=80," |
3472 | } |
3473 | } |
3474 | |
3475 | xfree(wp->w_p_cc_cols); |
3476 | if (count == 0) { |
3477 | wp->w_p_cc_cols = NULL; |
3478 | } else { |
3479 | wp->w_p_cc_cols = xmalloc(sizeof(int) * (count + 1)); |
3480 | /* sort the columns for faster usage on screen redraw inside |
3481 | * win_line() */ |
3482 | qsort(color_cols, count, sizeof(int), int_cmp); |
3483 | |
3484 | for (unsigned int i = 0; i < count; i++) { |
3485 | // skip duplicates |
3486 | if (j == 0 || wp->w_p_cc_cols[j - 1] != color_cols[i]) { |
3487 | wp->w_p_cc_cols[j++] = color_cols[i]; |
3488 | } |
3489 | } |
3490 | wp->w_p_cc_cols[j] = -1; // end marker |
3491 | } |
3492 | |
3493 | return NULL; // no error |
3494 | } |
3495 | |
3496 | |
3497 | /// Handle setting 'listchars' or 'fillchars'. |
3498 | /// Assume monocell characters |
3499 | /// |
3500 | /// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs |
3501 | /// @return error message, NULL if it's OK. |
3502 | static char_u *set_chars_option(win_T *wp, char_u **varp) |
3503 | { |
3504 | int round, i, len, entries; |
3505 | char_u *p, *s; |
3506 | int c1; |
3507 | int c2 = 0; |
3508 | int c3 = 0; |
3509 | |
3510 | struct chars_tab { |
3511 | int *cp; ///< char value |
3512 | char *name; ///< char id |
3513 | int def; ///< default value |
3514 | }; |
3515 | struct chars_tab *tab; |
3516 | |
3517 | struct chars_tab fcs_tab[] = { |
3518 | { &wp->w_p_fcs_chars.stl, "stl" , ' ' }, |
3519 | { &wp->w_p_fcs_chars.stlnc, "stlnc" , ' ' }, |
3520 | { &wp->w_p_fcs_chars.vert, "vert" , 9474 }, // │ |
3521 | { &wp->w_p_fcs_chars.fold, "fold" , 183 }, // · |
3522 | { &wp->w_p_fcs_chars.diff, "diff" , '-' }, |
3523 | { &wp->w_p_fcs_chars.msgsep, "msgsep" , ' ' }, |
3524 | { &wp->w_p_fcs_chars.eob, "eob" , '~' }, |
3525 | }; |
3526 | struct chars_tab lcs_tab[] = { |
3527 | { &wp->w_p_lcs_chars.eol, "eol" , NUL }, |
3528 | { &wp->w_p_lcs_chars.ext, "extends" , NUL }, |
3529 | { &wp->w_p_lcs_chars.nbsp, "nbsp" , NUL }, |
3530 | { &wp->w_p_lcs_chars.prec, "precedes" , NUL }, |
3531 | { &wp->w_p_lcs_chars.space, "space" , NUL }, |
3532 | { &wp->w_p_lcs_chars.tab2, "tab" , NUL }, |
3533 | { &wp->w_p_lcs_chars.trail, "trail" , NUL }, |
3534 | { &wp->w_p_lcs_chars.conceal, "conceal" , NUL }, |
3535 | }; |
3536 | |
3537 | if (varp == &wp->w_p_lcs) { |
3538 | tab = lcs_tab; |
3539 | entries = ARRAY_SIZE(lcs_tab); |
3540 | } else { |
3541 | tab = fcs_tab; |
3542 | entries = ARRAY_SIZE(fcs_tab); |
3543 | if (*p_ambw == 'd') { |
3544 | // XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is |
3545 | // forbidden (TUI limitation?). Set old defaults. |
3546 | fcs_tab[2].def = '|'; |
3547 | fcs_tab[3].def = '-'; |
3548 | } else { |
3549 | fcs_tab[2].def = 9474; // │ |
3550 | fcs_tab[3].def = 183; // · |
3551 | } |
3552 | } |
3553 | |
3554 | // first round: check for valid value, second round: assign values |
3555 | for (round = 0; round <= 1; round++) { |
3556 | if (round > 0) { |
3557 | // After checking that the value is valid: set defaults |
3558 | for (i = 0; i < entries; i++) { |
3559 | if (tab[i].cp != NULL) { |
3560 | *(tab[i].cp) = tab[i].def; |
3561 | } |
3562 | } |
3563 | if (varp == &wp->w_p_lcs) { |
3564 | wp->w_p_lcs_chars.tab1 = NUL; |
3565 | wp->w_p_lcs_chars.tab3 = NUL; |
3566 | } |
3567 | } |
3568 | p = *varp; |
3569 | while (*p) { |
3570 | for (i = 0; i < entries; i++) { |
3571 | len = (int)STRLEN(tab[i].name); |
3572 | if (STRNCMP(p, tab[i].name, len) == 0 |
3573 | && p[len] == ':' |
3574 | && p[len + 1] != NUL) { |
3575 | c2 = c3 = 0; |
3576 | s = p + len + 1; |
3577 | |
3578 | // TODO(bfredl): use schar_T representation and utfc_ptr2len |
3579 | int c1len = utf_ptr2len(s); |
3580 | c1 = mb_cptr2char_adv((const char_u **)&s); |
3581 | if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) { |
3582 | continue; |
3583 | } |
3584 | if (tab[i].cp == &wp->w_p_lcs_chars.tab2) { |
3585 | if (*s == NUL) { |
3586 | continue; |
3587 | } |
3588 | int c2len = utf_ptr2len(s); |
3589 | c2 = mb_cptr2char_adv((const char_u **)&s); |
3590 | if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) { |
3591 | continue; |
3592 | } |
3593 | if (!(*s == ',' || *s == NUL)) { |
3594 | int c3len = utf_ptr2len(s); |
3595 | c3 = mb_cptr2char_adv((const char_u **)&s); |
3596 | if (mb_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) { |
3597 | continue; |
3598 | } |
3599 | } |
3600 | } |
3601 | if (*s == ',' || *s == NUL) { |
3602 | if (round) { |
3603 | if (tab[i].cp == &wp->w_p_lcs_chars.tab2) { |
3604 | wp->w_p_lcs_chars.tab1 = c1; |
3605 | wp->w_p_lcs_chars.tab2 = c2; |
3606 | wp->w_p_lcs_chars.tab3 = c3; |
3607 | } else if (tab[i].cp != NULL) { |
3608 | *(tab[i].cp) = c1; |
3609 | } |
3610 | } |
3611 | p = s; |
3612 | break; |
3613 | } |
3614 | } |
3615 | } |
3616 | |
3617 | if (i == entries) { |
3618 | return e_invarg; |
3619 | } |
3620 | if (*p == ',') { |
3621 | p++; |
3622 | } |
3623 | } |
3624 | } |
3625 | |
3626 | return NULL; // no error |
3627 | } |
3628 | |
3629 | /* |
3630 | * Check validity of options with the 'statusline' format. |
3631 | * Return error message or NULL. |
3632 | */ |
3633 | char_u *check_stl_option(char_u *s) |
3634 | { |
3635 | int itemcnt = 0; |
3636 | int groupdepth = 0; |
3637 | static char_u errbuf[80]; |
3638 | |
3639 | while (*s && itemcnt < STL_MAX_ITEM) { |
3640 | // Check for valid keys after % sequences |
3641 | while (*s && *s != '%') { |
3642 | s++; |
3643 | } |
3644 | if (!*s) { |
3645 | break; |
3646 | } |
3647 | s++; |
3648 | if (*s != '%' && *s != ')') { |
3649 | itemcnt++; |
3650 | } |
3651 | if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE) { |
3652 | s++; |
3653 | continue; |
3654 | } |
3655 | if (*s == ')') { |
3656 | s++; |
3657 | if (--groupdepth < 0) { |
3658 | break; |
3659 | } |
3660 | continue; |
3661 | } |
3662 | if (*s == '-') { |
3663 | s++; |
3664 | } |
3665 | while (ascii_isdigit(*s)) { |
3666 | s++; |
3667 | } |
3668 | if (*s == STL_USER_HL) { |
3669 | continue; |
3670 | } |
3671 | if (*s == '.') { |
3672 | s++; |
3673 | while (*s && ascii_isdigit(*s)) |
3674 | s++; |
3675 | } |
3676 | if (*s == '(') { |
3677 | groupdepth++; |
3678 | continue; |
3679 | } |
3680 | if (vim_strchr(STL_ALL, *s) == NULL) { |
3681 | return illegal_char(errbuf, sizeof(errbuf), *s); |
3682 | } |
3683 | if (*s == '{') { |
3684 | s++; |
3685 | while (*s != '}' && *s) |
3686 | s++; |
3687 | if (*s != '}') { |
3688 | return (char_u *)N_("E540: Unclosed expression sequence" ); |
3689 | } |
3690 | } |
3691 | } |
3692 | if (itemcnt >= STL_MAX_ITEM) { |
3693 | return (char_u *)N_("E541: too many items" ); |
3694 | } |
3695 | if (groupdepth != 0) { |
3696 | return (char_u *)N_("E542: unbalanced groups" ); |
3697 | } |
3698 | return NULL; |
3699 | } |
3700 | |
3701 | static char_u *did_set_spell_option(bool is_spellfile) |
3702 | { |
3703 | char_u *errmsg = NULL; |
3704 | |
3705 | if (is_spellfile) { |
3706 | int l = (int)STRLEN(curwin->w_s->b_p_spf); |
3707 | if (l > 0 |
3708 | && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add" ) != 0)) { |
3709 | errmsg = e_invarg; |
3710 | } |
3711 | } |
3712 | |
3713 | if (errmsg == NULL) { |
3714 | FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { |
3715 | if (wp->w_buffer == curbuf && wp->w_p_spell) { |
3716 | errmsg = did_set_spelllang(wp); |
3717 | break; |
3718 | } |
3719 | } |
3720 | } |
3721 | |
3722 | return errmsg; |
3723 | } |
3724 | |
3725 | /* |
3726 | * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. |
3727 | * Return error message when failed, NULL when OK. |
3728 | */ |
3729 | static char_u *compile_cap_prog(synblock_T *synblock) |
3730 | { |
3731 | regprog_T *rp = synblock->b_cap_prog; |
3732 | char_u *re; |
3733 | |
3734 | if (*synblock->b_p_spc == NUL) { |
3735 | synblock->b_cap_prog = NULL; |
3736 | } else { |
3737 | // Prepend a ^ so that we only match at one column |
3738 | re = concat_str((char_u *)"^" , synblock->b_p_spc); |
3739 | synblock->b_cap_prog = vim_regcomp(re, RE_MAGIC); |
3740 | xfree(re); |
3741 | if (synblock->b_cap_prog == NULL) { |
3742 | synblock->b_cap_prog = rp; // restore the previous program |
3743 | return e_invarg; |
3744 | } |
3745 | } |
3746 | |
3747 | vim_regfree(rp); |
3748 | return NULL; |
3749 | } |
3750 | |
3751 | /// Handle setting `winhighlight' in window "wp" |
3752 | static bool parse_winhl_opt(win_T *wp) |
3753 | { |
3754 | int w_hl_id_normal = 0; |
3755 | int w_hl_ids[HLF_COUNT] = { 0 }; |
3756 | int hlf; |
3757 | |
3758 | const char *p = (const char *)wp->w_p_winhl; |
3759 | while (*p) { |
3760 | char *colon = strchr(p, ':'); |
3761 | if (!colon) { |
3762 | return false; |
3763 | } |
3764 | size_t nlen = (size_t)(colon-p); |
3765 | char *hi = colon+1; |
3766 | char *commap = xstrchrnul(hi, ','); |
3767 | int len = (int)(commap-hi); |
3768 | int hl_id = len ? syn_check_group((char_u *)hi, len) : -1; |
3769 | |
3770 | if (strncmp("Normal" , p, nlen) == 0) { |
3771 | w_hl_id_normal = hl_id; |
3772 | } else { |
3773 | for (hlf = 0; hlf < (int)HLF_COUNT; hlf++) { |
3774 | if (strncmp(hlf_names[hlf], p, nlen) == 0) { |
3775 | w_hl_ids[hlf] = hl_id; |
3776 | break; |
3777 | } |
3778 | } |
3779 | if (hlf == HLF_COUNT) { |
3780 | return false; |
3781 | } |
3782 | } |
3783 | |
3784 | p = *commap ? commap+1 : "" ; |
3785 | } |
3786 | |
3787 | wp->w_hl_id_normal = w_hl_id_normal; |
3788 | memcpy(wp->w_hl_ids, w_hl_ids, sizeof(w_hl_ids)); |
3789 | wp->w_hl_needs_update = true; |
3790 | return true; |
3791 | } |
3792 | |
3793 | // Set the script_ctx for an option, taking care of setting the buffer- or |
3794 | // window-local value. |
3795 | static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) |
3796 | { |
3797 | int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; |
3798 | int indir = (int)options[opt_idx].indir; |
3799 | const LastSet last_set = { .script_ctx = |
3800 | { script_ctx.sc_sid, script_ctx.sc_seq, |
3801 | script_ctx.sc_lnum + sourcing_lnum }, |
3802 | current_channel_id }; |
3803 | |
3804 | // Remember where the option was set. For local options need to do that |
3805 | // in the buffer or window structure. |
3806 | if (both || (opt_flags & OPT_GLOBAL) || (indir & (PV_BUF|PV_WIN)) == 0) { |
3807 | options[opt_idx].last_set = last_set; |
3808 | } |
3809 | if (both || (opt_flags & OPT_LOCAL)) { |
3810 | if (indir & PV_BUF) { |
3811 | curbuf->b_p_script_ctx[indir & PV_MASK] = last_set; |
3812 | } else if (indir & PV_WIN) { |
3813 | curwin->w_p_script_ctx[indir & PV_MASK] = last_set; |
3814 | } |
3815 | } |
3816 | } |
3817 | |
3818 | /// Set the value of a boolean option, taking care of side effects |
3819 | /// |
3820 | /// @param[in] opt_idx Option index in options[] table. |
3821 | /// @param[out] varp Pointer to the option variable. |
3822 | /// @param[in] value New value. |
3823 | /// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL. |
3824 | /// |
3825 | /// @return NULL on success, error message on error. |
3826 | static char *set_bool_option(const int opt_idx, char_u *const varp, |
3827 | const int value, |
3828 | const int opt_flags) |
3829 | { |
3830 | int old_value = *(int *)varp; |
3831 | |
3832 | // Disallow changing some options from secure mode |
3833 | if ((secure || sandbox != 0) |
3834 | && (options[opt_idx].flags & P_SECURE)) { |
3835 | return (char *)e_secure; |
3836 | } |
3837 | |
3838 | *(int *)varp = value; // set the new value |
3839 | // Remember where the option was set. |
3840 | set_option_sctx_idx(opt_idx, opt_flags, current_sctx); |
3841 | |
3842 | |
3843 | // May set global value for local option. |
3844 | if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { |
3845 | *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value; |
3846 | } |
3847 | |
3848 | // Ensure that options set to p_force_on cannot be disabled. |
3849 | if ((int *)varp == &p_force_on && p_force_on == false) { |
3850 | p_force_on = true; |
3851 | return (char *)e_unsupportedoption; |
3852 | // Ensure that options set to p_force_off cannot be enabled. |
3853 | } else if ((int *)varp == &p_force_off && p_force_off == true) { |
3854 | p_force_off = false; |
3855 | return (char *)e_unsupportedoption; |
3856 | } else if ((int *)varp == &p_lrm) { |
3857 | // 'langremap' -> !'langnoremap' |
3858 | p_lnr = !p_lrm; |
3859 | } else if ((int *)varp == &p_lnr) { |
3860 | // 'langnoremap' -> !'langremap' |
3861 | p_lrm = !p_lnr; |
3862 | } else if ((int *)varp == &curwin->w_p_cul && !value && old_value) { |
3863 | // 'cursorline' |
3864 | reset_cursorline(); |
3865 | // 'undofile' |
3866 | } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) { |
3867 | // Only take action when the option was set. When reset we do not |
3868 | // delete the undo file, the option may be set again without making |
3869 | // any changes in between. |
3870 | if (curbuf->b_p_udf || p_udf) { |
3871 | char_u hash[UNDO_HASH_SIZE]; |
3872 | buf_T *save_curbuf = curbuf; |
3873 | |
3874 | FOR_ALL_BUFFERS(bp) { |
3875 | curbuf = bp; |
3876 | // When 'undofile' is set globally: for every buffer, otherwise |
3877 | // only for the current buffer: Try to read in the undofile, |
3878 | // if one exists, the buffer wasn't changed and the buffer was |
3879 | // loaded |
3880 | if ((curbuf == save_curbuf |
3881 | || (opt_flags & OPT_GLOBAL) || opt_flags == 0) |
3882 | && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL) { |
3883 | u_compute_hash(hash); |
3884 | u_read_undo(NULL, hash, curbuf->b_fname); |
3885 | } |
3886 | } |
3887 | curbuf = save_curbuf; |
3888 | } |
3889 | } else if ((int *)varp == &curbuf->b_p_ro) { |
3890 | // when 'readonly' is reset globally, also reset readonlymode |
3891 | if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0) { |
3892 | readonlymode = false; |
3893 | } |
3894 | |
3895 | // when 'readonly' is set may give W10 again |
3896 | if (curbuf->b_p_ro) { |
3897 | curbuf->b_did_warn = false; |
3898 | } |
3899 | |
3900 | redraw_titles(); |
3901 | } else if ((int *)varp == &curbuf->b_p_ma) { |
3902 | // when 'modifiable' is changed, redraw the window title |
3903 | redraw_titles(); |
3904 | } else if ((int *)varp == &curbuf->b_p_eol) { |
3905 | // when 'endofline' is changed, redraw the window title |
3906 | redraw_titles(); |
3907 | } else if ((int *)varp == &curbuf->b_p_fixeol) { |
3908 | // when 'fixeol' is changed, redraw the window title |
3909 | redraw_titles(); |
3910 | } else if ((int *)varp == &curbuf->b_p_bomb) { |
3911 | // when 'bomb' is changed, redraw the window title and tab page text |
3912 | redraw_titles(); |
3913 | } else if ((int *)varp == &curbuf->b_p_bin) { |
3914 | // when 'bin' is set also set some other options |
3915 | set_options_bin(old_value, curbuf->b_p_bin, opt_flags); |
3916 | redraw_titles(); |
3917 | } else if ((int *)varp == &curbuf->b_p_bl && old_value != curbuf->b_p_bl) { |
3918 | // when 'buflisted' changes, trigger autocommands |
3919 | apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, |
3920 | NULL, NULL, true, curbuf); |
3921 | } else if ((int *)varp == (int *)&curbuf->b_p_swf) { |
3922 | // when 'swf' is set, create swapfile, when reset remove swapfile |
3923 | if (curbuf->b_p_swf && p_uc) { |
3924 | ml_open_file(curbuf); // create the swap file |
3925 | } else { |
3926 | // no need to reset curbuf->b_may_swap, ml_open_file() will check |
3927 | // buf->b_p_swf |
3928 | mf_close_file(curbuf, true); // remove the swap file |
3929 | } |
3930 | } else if ((int *)varp == &p_terse) { |
3931 | // when 'terse' is set change 'shortmess' |
3932 | char_u *p; |
3933 | |
3934 | p = vim_strchr(p_shm, SHM_SEARCH); |
3935 | |
3936 | // insert 's' in p_shm |
3937 | if (p_terse && p == NULL) { |
3938 | STRCPY(IObuff, p_shm); |
3939 | STRCAT(IObuff, "s" ); |
3940 | set_string_option_direct((char_u *)"shm" , -1, IObuff, OPT_FREE, 0); |
3941 | } else if (!p_terse && p != NULL) { // remove 's' from p_shm |
3942 | STRMOVE(p, p + 1); |
3943 | } |
3944 | } else if ((int *)varp == &p_paste) { |
3945 | // when 'paste' is set or reset also change other options |
3946 | paste_option_changed(); |
3947 | } else if ((int *)varp == &p_im) { |
3948 | // when 'insertmode' is set from an autocommand need to do work here |
3949 | if (p_im) { |
3950 | if ((State & INSERT) == 0) { |
3951 | need_start_insertmode = true; |
3952 | } |
3953 | stop_insert_mode = false; |
3954 | } else if (old_value) { // only reset if it was set previously |
3955 | need_start_insertmode = false; |
3956 | stop_insert_mode = true; |
3957 | if (restart_edit != 0 && mode_displayed) { |
3958 | clear_cmdline = true; // remove "(insert)" |
3959 | } |
3960 | restart_edit = 0; |
3961 | } |
3962 | } else if ((int *)varp == &p_ic && p_hls) { |
3963 | // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw |
3964 | redraw_all_later(SOME_VALID); |
3965 | } else if ((int *)varp == &p_hls) { |
3966 | // when 'hlsearch' is set or reset: reset no_hlsearch |
3967 | set_no_hlsearch(false); |
3968 | } else if ((int *)varp == &curwin->w_p_scb) { |
3969 | // when 'scrollbind' is set: snapshot the current position to avoid a jump |
3970 | // at the end of normal_cmd() |
3971 | if (curwin->w_p_scb) { |
3972 | do_check_scrollbind(false); |
3973 | curwin->w_scbind_pos = curwin->w_topline; |
3974 | } |
3975 | } else if ((int *)varp == &curwin->w_p_pvw) { |
3976 | // There can be only one window with 'previewwindow' set. |
3977 | if (curwin->w_p_pvw) { |
3978 | FOR_ALL_WINDOWS_IN_TAB(win, curtab) { |
3979 | if (win->w_p_pvw && win != curwin) { |
3980 | curwin->w_p_pvw = false; |
3981 | return N_("E590: A preview window already exists" ); |
3982 | } |
3983 | } |
3984 | } |
3985 | } else if (varp == (char_u *)&(curbuf->b_p_lisp)) { |
3986 | // When 'lisp' option changes include/exclude '-' in |
3987 | // keyword characters. |
3988 | (void)buf_init_chartab(curbuf, false); // ignore errors |
3989 | } else if ((int *)varp == &p_title) { |
3990 | // when 'title' changed, may need to change the title; same for 'icon' |
3991 | did_set_title(false); |
3992 | } else if ((int *)varp == &p_icon) { |
3993 | did_set_title(true); |
3994 | } else if ((int *)varp == &curbuf->b_changed) { |
3995 | if (!value) { |
3996 | save_file_ff(curbuf); // Buffer is unchanged |
3997 | } |
3998 | redraw_titles(); |
3999 | modified_was_set = value; |
4000 | } |
4001 | |
4002 | #ifdef BACKSLASH_IN_FILENAME |
4003 | else if ((int *)varp == &p_ssl) { |
4004 | if (p_ssl) { |
4005 | psepc = '/'; |
4006 | psepcN = '\\'; |
4007 | pseps[0] = '/'; |
4008 | } else { |
4009 | psepc = '\\'; |
4010 | psepcN = '/'; |
4011 | pseps[0] = '\\'; |
4012 | } |
4013 | |
4014 | // need to adjust the file name arguments and buffer names. |
4015 | buflist_slash_adjust(); |
4016 | alist_slash_adjust(); |
4017 | scriptnames_slash_adjust(); |
4018 | } |
4019 | #endif |
4020 | else if ((int *)varp == &curwin->w_p_wrap) { |
4021 | // If 'wrap' is set, set w_leftcol to zero. |
4022 | if (curwin->w_p_wrap) { |
4023 | curwin->w_leftcol = 0; |
4024 | } |
4025 | } else if ((int *)varp == &p_ea) { |
4026 | if (p_ea && !old_value) { |
4027 | win_equal(curwin, false, 0); |
4028 | } |
4029 | } else if ((int *)varp == &p_acd) { |
4030 | // Change directories when the 'acd' option is set now. |
4031 | do_autochdir(); |
4032 | } else if ((int *)varp == &curwin->w_p_diff) { // 'diff' |
4033 | // May add or remove the buffer from the list of diff buffers. |
4034 | diff_buf_adjust(curwin); |
4035 | if (foldmethodIsDiff(curwin)) { |
4036 | foldUpdateAll(curwin); |
4037 | } |
4038 | } else if ((int *)varp == &curwin->w_p_spell) { // 'spell' |
4039 | if (curwin->w_p_spell) { |
4040 | char_u *errmsg = did_set_spelllang(curwin); |
4041 | if (errmsg != NULL) { |
4042 | EMSG(_(errmsg)); |
4043 | } |
4044 | } |
4045 | } |
4046 | |
4047 | if ((int *)varp == &curwin->w_p_arab) { |
4048 | if (curwin->w_p_arab) { |
4049 | /* |
4050 | * 'arabic' is set, handle various sub-settings. |
4051 | */ |
4052 | if (!p_tbidi) { |
4053 | // set rightleft mode |
4054 | if (!curwin->w_p_rl) { |
4055 | curwin->w_p_rl = true; |
4056 | changed_window_setting(); |
4057 | } |
4058 | |
4059 | // Enable Arabic shaping (major part of what Arabic requires) |
4060 | if (!p_arshape) { |
4061 | p_arshape = true; |
4062 | redraw_all_later(NOT_VALID); |
4063 | } |
4064 | } |
4065 | |
4066 | /* Arabic requires a utf-8 encoding, inform the user if its not |
4067 | * set. */ |
4068 | if (STRCMP(p_enc, "utf-8" ) != 0) { |
4069 | static char *w_arabic = N_( |
4070 | "W17: Arabic requires UTF-8, do ':set encoding=utf-8'" ); |
4071 | |
4072 | msg_source(HL_ATTR(HLF_W)); |
4073 | msg_attr(_(w_arabic), HL_ATTR(HLF_W)); |
4074 | set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); |
4075 | } |
4076 | |
4077 | // set 'delcombine' |
4078 | p_deco = true; |
4079 | |
4080 | // Force-set the necessary keymap for arabic. |
4081 | set_option_value("keymap" , 0L, "arabic" , OPT_LOCAL); |
4082 | } else { |
4083 | /* |
4084 | * 'arabic' is reset, handle various sub-settings. |
4085 | */ |
4086 | if (!p_tbidi) { |
4087 | // reset rightleft mode |
4088 | if (curwin->w_p_rl) { |
4089 | curwin->w_p_rl = false; |
4090 | changed_window_setting(); |
4091 | } |
4092 | |
4093 | /* 'arabicshape' isn't reset, it is a global option and |
4094 | * another window may still need it "on". */ |
4095 | } |
4096 | |
4097 | /* 'delcombine' isn't reset, it is a global option and another |
4098 | * window may still want it "on". */ |
4099 | |
4100 | // Revert to the default keymap |
4101 | curbuf->b_p_iminsert = B_IMODE_NONE; |
4102 | curbuf->b_p_imsearch = B_IMODE_USE_INSERT; |
4103 | } |
4104 | } |
4105 | |
4106 | |
4107 | /* |
4108 | * End of handling side effects for bool options. |
4109 | */ |
4110 | |
4111 | // after handling side effects, call autocommand |
4112 | |
4113 | options[opt_idx].flags |= P_WAS_SET; |
4114 | |
4115 | // Don't do this while starting up or recursively. |
4116 | if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { |
4117 | char buf_old[2]; |
4118 | char buf_new[2]; |
4119 | char buf_type[7]; |
4120 | vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d" , |
4121 | old_value ? true: false); |
4122 | vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d" , |
4123 | value ? true: false); |
4124 | vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s" , |
4125 | (opt_flags & OPT_LOCAL) ? "local" : "global" ); |
4126 | set_vim_var_string(VV_OPTION_NEW, buf_new, -1); |
4127 | set_vim_var_string(VV_OPTION_OLD, buf_old, -1); |
4128 | set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); |
4129 | apply_autocmds(EVENT_OPTIONSET, |
4130 | (char_u *) options[opt_idx].fullname, |
4131 | NULL, false, NULL); |
4132 | reset_v_option_vars(); |
4133 | } |
4134 | |
4135 | if (options[opt_idx].flags & P_UI_OPTION) { |
4136 | ui_call_option_set(cstr_as_string(options[opt_idx].fullname), |
4137 | BOOLEAN_OBJ(value)); |
4138 | } |
4139 | |
4140 | comp_col(); // in case 'ruler' or 'showcmd' changed |
4141 | if (curwin->w_curswant != MAXCOL |
4142 | && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) { |
4143 | curwin->w_set_curswant = true; |
4144 | } |
4145 | check_redraw(options[opt_idx].flags); |
4146 | |
4147 | return NULL; |
4148 | } |
4149 | |
4150 | /// Set the value of a number option, taking care of side effects |
4151 | /// |
4152 | /// @param[in] opt_idx Option index in options[] table. |
4153 | /// @param[out] varp Pointer to the option variable. |
4154 | /// @param[in] value New value. |
4155 | /// @param errbuf Buffer for error messages. |
4156 | /// @param[in] errbuflen Length of `errbuf`. |
4157 | /// @param[in] opt_flags OPT_LOCAL, OPT_GLOBAL or OPT_MODELINE. |
4158 | /// |
4159 | /// @return NULL on success, error message on error. |
4160 | static char *set_num_option(int opt_idx, char_u *varp, long value, |
4161 | char_u *errbuf, size_t errbuflen, int opt_flags) |
4162 | { |
4163 | char_u *errmsg = NULL; |
4164 | long old_value = *(long *)varp; |
4165 | long old_Rows = Rows; // remember old Rows |
4166 | long *pp = (long *)varp; |
4167 | |
4168 | // Disallow changing some options from secure mode. |
4169 | if ((secure || sandbox != 0) |
4170 | && (options[opt_idx].flags & P_SECURE)) { |
4171 | return (char *)e_secure; |
4172 | } |
4173 | |
4174 | // Many number options assume their value is in the signed int range. |
4175 | if (value < INT_MIN || value > INT_MAX) { |
4176 | return (char *)e_invarg; |
4177 | } |
4178 | |
4179 | // Options that need some validation. |
4180 | if (pp == &p_wh) { |
4181 | if (value < 1) { |
4182 | errmsg = e_positive; |
4183 | } else if (p_wmh > value) { |
4184 | errmsg = e_winheight; |
4185 | } |
4186 | } else if (pp == &p_hh) { |
4187 | if (value < 0) { |
4188 | errmsg = e_positive; |
4189 | } |
4190 | } else if (pp == &p_wmh) { |
4191 | if (value < 0) { |
4192 | errmsg = e_positive; |
4193 | } else if (value > p_wh) { |
4194 | errmsg = e_winheight; |
4195 | } |
4196 | } else if (pp == &p_wiw) { |
4197 | if (value < 1) { |
4198 | errmsg = e_positive; |
4199 | } else if (p_wmw > value) { |
4200 | errmsg = e_winwidth; |
4201 | } |
4202 | } else if (pp == &p_wmw) { |
4203 | if (value < 0) { |
4204 | errmsg = e_positive; |
4205 | } else if (value > p_wiw) { |
4206 | errmsg = e_winwidth; |
4207 | } |
4208 | } else if (pp == &p_mco) { |
4209 | value = MAX_MCO; |
4210 | } else if (pp == &p_titlelen) { |
4211 | if (value < 0) { |
4212 | errmsg = e_positive; |
4213 | } |
4214 | } else if (pp == &p_uc) { |
4215 | if (value < 0) { |
4216 | errmsg = e_positive; |
4217 | } |
4218 | } else if (pp == &p_ch) { |
4219 | int minval = ui_has(kUIMessages) ? 0 : 1; |
4220 | if (value < minval) { |
4221 | errmsg = e_positive; |
4222 | } |
4223 | } else if (pp == &p_tm) { |
4224 | if (value < 0) { |
4225 | errmsg = e_positive; |
4226 | } |
4227 | } else if (pp == &p_hi) { |
4228 | if (value < 0) { |
4229 | errmsg = e_positive; |
4230 | } else if (value > 10000) { |
4231 | errmsg = e_invarg; |
4232 | } |
4233 | } else if (pp == &p_re) { |
4234 | if (value < 0 || value > 2) { |
4235 | errmsg = e_invarg; |
4236 | } |
4237 | } else if (pp == &p_report) { |
4238 | if (value < 0) { |
4239 | errmsg = e_positive; |
4240 | } |
4241 | } else if (pp == &p_so) { |
4242 | if (value < 0 && full_screen) { |
4243 | errmsg = e_scroll; |
4244 | } |
4245 | } else if (pp == &p_siso) { |
4246 | if (value < 0 && full_screen) { |
4247 | errmsg = e_positive; |
4248 | } |
4249 | } else if (pp == &p_cwh) { |
4250 | if (value < 1) { |
4251 | errmsg = e_positive; |
4252 | } |
4253 | } else if (pp == &p_ut) { |
4254 | if (value < 0) { |
4255 | errmsg = e_positive; |
4256 | } |
4257 | } else if (pp == &p_ss) { |
4258 | if (value < 0) { |
4259 | errmsg = e_positive; |
4260 | } |
4261 | } else if (pp == &curwin->w_p_fdl || pp == &curwin->w_allbuf_opt.wo_fdl) { |
4262 | if (value < 0) { |
4263 | errmsg = e_positive; |
4264 | } |
4265 | } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) { |
4266 | if (value < 0) { |
4267 | errmsg = e_positive; |
4268 | } else if (value > 12) { |
4269 | errmsg = e_invarg; |
4270 | } |
4271 | } else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) { |
4272 | if (value < 0) { |
4273 | errmsg = e_positive; |
4274 | } else if (value > 3) { |
4275 | errmsg = e_invarg; |
4276 | } |
4277 | } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) { |
4278 | if (value < 1) { |
4279 | errmsg = e_positive; |
4280 | } else if (value > 20) { |
4281 | errmsg = e_invarg; |
4282 | } |
4283 | } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) { |
4284 | if (value < 0 || value > B_IMODE_LAST) { |
4285 | errmsg = e_invarg; |
4286 | } |
4287 | } else if (pp == &curbuf->b_p_imsearch || pp == &p_imsearch) { |
4288 | if (value < -1 || value > B_IMODE_LAST) { |
4289 | errmsg = e_invarg; |
4290 | } |
4291 | } else if (pp == &curbuf->b_p_channel || pp == &p_channel) { |
4292 | errmsg = e_invarg; |
4293 | } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) { |
4294 | if (value < -1 || value > SB_MAX) { |
4295 | errmsg = e_invarg; |
4296 | } |
4297 | } else if (pp == &curbuf->b_p_sw || pp == &p_sw) { |
4298 | if (value < 0) { |
4299 | errmsg = e_positive; |
4300 | } |
4301 | } else if (pp == &curbuf->b_p_ts || pp == &p_ts) { |
4302 | if (value < 1) { |
4303 | errmsg = e_positive; |
4304 | } |
4305 | } else if (pp == &curbuf->b_p_tw || pp == &p_tw) { |
4306 | if (value < 0) { |
4307 | errmsg = e_positive; |
4308 | } |
4309 | } |
4310 | |
4311 | // Don't change the value and return early if validation failed. |
4312 | if (errmsg != NULL) { |
4313 | return (char *)errmsg; |
4314 | } |
4315 | |
4316 | *pp = value; |
4317 | // Remember where the option was set. |
4318 | set_option_sctx_idx(opt_idx, opt_flags, current_sctx); |
4319 | |
4320 | // For these options we want to fix some invalid values. |
4321 | if (pp == &p_window) { |
4322 | if (p_window < 1) { |
4323 | p_window = Rows - 1; |
4324 | } else if (p_window >= Rows) { |
4325 | p_window = Rows - 1; |
4326 | } |
4327 | } else if (pp == &p_ch) { |
4328 | if (ui_has(kUIMessages)) { |
4329 | p_ch = 0; |
4330 | } |
4331 | if (p_ch > Rows - min_rows() + 1) { |
4332 | p_ch = Rows - min_rows() + 1; |
4333 | } |
4334 | } |
4335 | |
4336 | // Number options that need some action when changed |
4337 | if (pp == &p_wh) { |
4338 | // 'winheight' |
4339 | if (!ONE_WINDOW && curwin->w_height < p_wh) { |
4340 | win_setheight((int)p_wh); |
4341 | } |
4342 | } else if (pp == &p_hh) { |
4343 | // 'helpheight' |
4344 | if (!ONE_WINDOW && curbuf->b_help && curwin->w_height < p_hh) { |
4345 | win_setheight((int)p_hh); |
4346 | } |
4347 | } else if (pp == &p_wmh) { |
4348 | // 'winminheight' |
4349 | win_setminheight(); |
4350 | } else if (pp == &p_wiw) { |
4351 | // 'winwidth' |
4352 | if (!ONE_WINDOW && curwin->w_width < p_wiw) { |
4353 | win_setwidth((int)p_wiw); |
4354 | } |
4355 | } else if (pp == &p_wmw) { |
4356 | // 'winminwidth' |
4357 | win_setminwidth(); |
4358 | } else if (pp == &p_ls) { |
4359 | last_status(false); // (re)set last window status line. |
4360 | } else if (pp == &p_stal) { |
4361 | // (re)set tab page line |
4362 | shell_new_rows(); // recompute window positions and heights |
4363 | } else if (pp == &curwin->w_p_fdl) { |
4364 | newFoldLevel(); |
4365 | } else if (pp == &curwin->w_p_fml) { |
4366 | foldUpdateAll(curwin); |
4367 | } else if (pp == &curwin->w_p_fdn) { |
4368 | if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin)) { |
4369 | foldUpdateAll(curwin); |
4370 | } |
4371 | } else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts) { |
4372 | // 'shiftwidth' or 'tabstop' |
4373 | if (foldmethodIsIndent(curwin)) { |
4374 | foldUpdateAll(curwin); |
4375 | } |
4376 | // When 'shiftwidth' changes, or it's zero and 'tabstop' changes: |
4377 | // parse 'cinoptions'. |
4378 | if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) { |
4379 | parse_cino(curbuf); |
4380 | } |
4381 | } else if (pp == &curbuf->b_p_iminsert) { |
4382 | showmode(); |
4383 | // Show/unshow value of 'keymap' in status lines. |
4384 | status_redraw_curbuf(); |
4385 | } else if (pp == &p_titlelen) { |
4386 | // if 'titlelen' has changed, redraw the title |
4387 | if (starting != NO_SCREEN && old_value != p_titlelen) { |
4388 | need_maketitle = true; |
4389 | } |
4390 | } else if (pp == &p_ch) { |
4391 | // if p_ch changed value, change the command line height |
4392 | // Only compute the new window layout when startup has been |
4393 | // completed. Otherwise the frame sizes may be wrong. |
4394 | if (p_ch != old_value && full_screen) { |
4395 | command_height(); |
4396 | } |
4397 | } else if (pp == &p_uc) { |
4398 | // when 'updatecount' changes from zero to non-zero, open swap files |
4399 | if (p_uc && !old_value) { |
4400 | ml_open_files(); |
4401 | } |
4402 | } else if (pp == &p_pb) { |
4403 | p_pb = MAX(MIN(p_pb, 100), 0); |
4404 | hl_invalidate_blends(); |
4405 | pum_grid.blending = (p_pb > 0); |
4406 | if (pum_drawn()) { |
4407 | pum_redraw(); |
4408 | } |
4409 | } else if (pp == &p_pyx) { |
4410 | if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) { |
4411 | errmsg = e_invarg; |
4412 | } |
4413 | } else if (pp == &p_ul || pp == &curbuf->b_p_ul) { |
4414 | // sync undo before 'undolevels' changes |
4415 | // use the old value, otherwise u_sync() may not work properly |
4416 | *pp = old_value; |
4417 | u_sync(true); |
4418 | *pp = value; |
4419 | } else if (pp == &curbuf->b_p_tw) { |
4420 | FOR_ALL_TAB_WINDOWS(tp, wp) { |
4421 | check_colorcolumn(wp); |
4422 | } |
4423 | } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) { |
4424 | if (curbuf->terminal) { |
4425 | // Force the scrollback to take effect. |
4426 | terminal_check_size(curbuf->terminal); |
4427 | } |
4428 | } else if (pp == &curwin->w_p_nuw) { |
4429 | curwin->w_nrwidth_line_count = 0; |
4430 | } else if (pp == &curwin->w_p_winbl && value != old_value) { |
4431 | // 'floatblend' |
4432 | curwin->w_p_winbl = MAX(MIN(curwin->w_p_winbl, 100), 0); |
4433 | curwin->w_hl_needs_update = true; |
4434 | curwin->w_grid.blending = curwin->w_p_winbl > 0; |
4435 | } |
4436 | |
4437 | |
4438 | // Check the (new) bounds for Rows and Columns here. |
4439 | if (p_lines < min_rows() && full_screen) { |
4440 | if (errbuf != NULL) { |
4441 | vim_snprintf((char *)errbuf, errbuflen, |
4442 | _("E593: Need at least %d lines" ), min_rows()); |
4443 | errmsg = errbuf; |
4444 | } |
4445 | p_lines = min_rows(); |
4446 | } |
4447 | if (p_columns < MIN_COLUMNS && full_screen) { |
4448 | if (errbuf != NULL) { |
4449 | vim_snprintf((char *)errbuf, errbuflen, |
4450 | _("E594: Need at least %d columns" ), MIN_COLUMNS); |
4451 | errmsg = errbuf; |
4452 | } |
4453 | p_columns = MIN_COLUMNS; |
4454 | } |
4455 | |
4456 | // True max size is defined by check_shellsize() |
4457 | p_lines = MIN(p_lines, INT_MAX); |
4458 | p_columns = MIN(p_columns, INT_MAX); |
4459 | |
4460 | // If the screen (shell) height has been changed, assume it is the |
4461 | // physical screenheight. |
4462 | if (p_lines != Rows || p_columns != Columns) { |
4463 | // Changing the screen size is not allowed while updating the screen. |
4464 | if (updating_screen) { |
4465 | *pp = old_value; |
4466 | } else if (full_screen) { |
4467 | screen_resize((int)p_columns, (int)p_lines); |
4468 | } else { |
4469 | // TODO(bfredl): is this branch ever needed? |
4470 | // Postpone the resizing; check the size and cmdline position for |
4471 | // messages. |
4472 | Rows = (int)p_lines; |
4473 | Columns = (int)p_columns; |
4474 | check_shellsize(); |
4475 | if (cmdline_row > Rows - p_ch && Rows > p_ch) { |
4476 | assert(p_ch >= 0 && Rows - p_ch <= INT_MAX); |
4477 | cmdline_row = (int)(Rows - p_ch); |
4478 | } |
4479 | } |
4480 | if (p_window >= Rows || !option_was_set("window" )) { |
4481 | p_window = Rows - 1; |
4482 | } |
4483 | } |
4484 | |
4485 | if ((curwin->w_p_scr <= 0 |
4486 | || (curwin->w_p_scr > curwin->w_height |
4487 | && curwin->w_height > 0)) |
4488 | && full_screen) { |
4489 | if (pp == &(curwin->w_p_scr)) { |
4490 | if (curwin->w_p_scr != 0) { |
4491 | errmsg = e_scroll; |
4492 | } |
4493 | win_comp_scroll(curwin); |
4494 | } else if (curwin->w_p_scr <= 0) { |
4495 | // If 'scroll' became invalid because of a side effect silently adjust it. |
4496 | curwin->w_p_scr = 1; |
4497 | } else { // curwin->w_p_scr > curwin->w_height |
4498 | curwin->w_p_scr = curwin->w_height; |
4499 | } |
4500 | } |
4501 | if ((p_sj < -100 || p_sj >= Rows) && full_screen) { |
4502 | if (Rows != old_Rows) { // Rows changed, just adjust p_sj |
4503 | p_sj = Rows / 2; |
4504 | } else { |
4505 | errmsg = e_scroll; |
4506 | p_sj = 1; |
4507 | } |
4508 | } |
4509 | |
4510 | // May set global value for local option. |
4511 | if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { |
4512 | *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp; |
4513 | } |
4514 | |
4515 | options[opt_idx].flags |= P_WAS_SET; |
4516 | |
4517 | // Don't do this while starting up, failure or recursively. |
4518 | if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { |
4519 | char buf_old[NUMBUFLEN]; |
4520 | char buf_new[NUMBUFLEN]; |
4521 | char buf_type[7]; |
4522 | vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld" , old_value); |
4523 | vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld" , value); |
4524 | vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s" , |
4525 | (opt_flags & OPT_LOCAL) ? "local" : "global" ); |
4526 | set_vim_var_string(VV_OPTION_NEW, buf_new, -1); |
4527 | set_vim_var_string(VV_OPTION_OLD, buf_old, -1); |
4528 | set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); |
4529 | apply_autocmds(EVENT_OPTIONSET, |
4530 | (char_u *) options[opt_idx].fullname, |
4531 | NULL, false, NULL); |
4532 | reset_v_option_vars(); |
4533 | } |
4534 | |
4535 | if (errmsg == NULL && options[opt_idx].flags & P_UI_OPTION) { |
4536 | ui_call_option_set(cstr_as_string(options[opt_idx].fullname), |
4537 | INTEGER_OBJ(value)); |
4538 | } |
4539 | |
4540 | comp_col(); // in case 'columns' or 'ls' changed |
4541 | if (curwin->w_curswant != MAXCOL |
4542 | && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) { |
4543 | curwin->w_set_curswant = true; |
4544 | } |
4545 | check_redraw(options[opt_idx].flags); |
4546 | |
4547 | return (char *)errmsg; |
4548 | } |
4549 | |
4550 | static void trigger_optionsset_string(int opt_idx, int opt_flags, |
4551 | char *oldval, char *newval) |
4552 | { |
4553 | // Don't do this recursively. |
4554 | if (oldval != NULL |
4555 | && newval != NULL |
4556 | && *get_vim_var_str(VV_OPTION_TYPE) == NUL) { |
4557 | char buf_type[7]; |
4558 | |
4559 | vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s" , |
4560 | (opt_flags & OPT_LOCAL) ? "local" : "global" ); |
4561 | set_vim_var_string(VV_OPTION_OLD, oldval, -1); |
4562 | set_vim_var_string(VV_OPTION_NEW, newval, -1); |
4563 | set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); |
4564 | apply_autocmds(EVENT_OPTIONSET, |
4565 | (char_u *)options[opt_idx].fullname, NULL, false, NULL); |
4566 | reset_v_option_vars(); |
4567 | } |
4568 | } |
4569 | |
4570 | /* |
4571 | * Called after an option changed: check if something needs to be redrawn. |
4572 | */ |
4573 | static void check_redraw(uint32_t flags) |
4574 | { |
4575 | // Careful: P_RCLR and P_RALL are a combination of other P_ flags |
4576 | bool doclear = (flags & P_RCLR) == P_RCLR; |
4577 | bool all = ((flags & P_RALL) == P_RALL || doclear); |
4578 | |
4579 | if ((flags & P_RSTAT) || all) { // mark all status lines dirty |
4580 | status_redraw_all(); |
4581 | } |
4582 | |
4583 | if ((flags & P_RBUF) || (flags & P_RWIN) || all) { |
4584 | changed_window_setting(); |
4585 | } |
4586 | if (flags & P_RBUF) { |
4587 | redraw_curbuf_later(NOT_VALID); |
4588 | } |
4589 | if (flags & P_RWINONLY) { |
4590 | redraw_later(NOT_VALID); |
4591 | } |
4592 | if (doclear) { |
4593 | redraw_all_later(CLEAR); |
4594 | } else if (all) { |
4595 | redraw_all_later(NOT_VALID); |
4596 | } |
4597 | } |
4598 | |
4599 | /// Find index for named option |
4600 | /// |
4601 | /// @param[in] arg Option to find index for. |
4602 | /// @param[in] len Length of the option. |
4603 | /// |
4604 | /// @return Index of the option or -1 if option was not found. |
4605 | int findoption_len(const char *const arg, const size_t len) |
4606 | { |
4607 | const char *s; |
4608 | const char *p; |
4609 | static int quick_tab[27] = { 0, 0 }; // quick access table |
4610 | |
4611 | // For first call: Initialize the quick-access table. |
4612 | // It contains the index for the first option that starts with a certain |
4613 | // letter. There are 26 letters, plus the first "t_" option. |
4614 | if (quick_tab[1] == 0) { |
4615 | p = options[0].fullname; |
4616 | for (short int i = 1; (s = options[i].fullname) != NULL; i++) { |
4617 | if (s[0] != p[0]) { |
4618 | if (s[0] == 't' && s[1] == '_') { |
4619 | quick_tab[26] = i; |
4620 | } else { |
4621 | quick_tab[CharOrdLow(s[0])] = i; |
4622 | } |
4623 | } |
4624 | p = s; |
4625 | } |
4626 | } |
4627 | |
4628 | // Check for name starting with an illegal character. |
4629 | if (len == 0 || arg[0] < 'a' || arg[0] > 'z') { |
4630 | return -1; |
4631 | } |
4632 | |
4633 | int opt_idx; |
4634 | const bool is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_'); |
4635 | if (is_term_opt) { |
4636 | opt_idx = quick_tab[26]; |
4637 | } else { |
4638 | opt_idx = quick_tab[CharOrdLow(arg[0])]; |
4639 | } |
4640 | // Match full name |
4641 | for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) { |
4642 | if (strncmp(arg, s, len) == 0 && s[len] == NUL) { |
4643 | break; |
4644 | } |
4645 | } |
4646 | if (s == NULL && !is_term_opt) { |
4647 | opt_idx = quick_tab[CharOrdLow(arg[0])]; |
4648 | // Match short name |
4649 | for (; options[opt_idx].fullname != NULL; opt_idx++) { |
4650 | s = options[opt_idx].shortname; |
4651 | if (s != NULL && strncmp(arg, s, len) == 0 && s[len] == NUL) { |
4652 | break; |
4653 | } |
4654 | s = NULL; |
4655 | } |
4656 | } |
4657 | if (s == NULL) { |
4658 | opt_idx = -1; |
4659 | } else { |
4660 | // Nvim: handle option aliases. |
4661 | if (STRNCMP(options[opt_idx].fullname, "viminfo" , 7) == 0) { |
4662 | if (STRLEN(options[opt_idx].fullname) == 7) { |
4663 | return findoption_len("shada" , 5); |
4664 | } |
4665 | assert(STRCMP(options[opt_idx].fullname, "viminfofile" ) == 0); |
4666 | return findoption_len("shadafile" , 9); |
4667 | } |
4668 | } |
4669 | return opt_idx; |
4670 | } |
4671 | |
4672 | bool is_tty_option(const char *name) |
4673 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT |
4674 | { |
4675 | return (name[0] == 't' && name[1] == '_') |
4676 | || strequal(name, "term" ) |
4677 | || strequal(name, "ttytype" ); |
4678 | } |
4679 | |
4680 | #define TCO_BUFFER_SIZE 8 |
4681 | /// @param name TUI-related option |
4682 | /// @param[out,allocated] value option string value |
4683 | bool get_tty_option(char *name, char **value) |
4684 | { |
4685 | if (strequal(name, "t_Co" )) { |
4686 | if (value) { |
4687 | if (t_colors <= 1) { |
4688 | *value = xstrdup("" ); |
4689 | } else { |
4690 | *value = xmalloc(TCO_BUFFER_SIZE); |
4691 | snprintf(*value, TCO_BUFFER_SIZE, "%d" , t_colors); |
4692 | } |
4693 | } |
4694 | return true; |
4695 | } |
4696 | |
4697 | if (strequal(name, "term" )) { |
4698 | if (value) { |
4699 | *value = p_term ? xstrdup(p_term) : xstrdup("nvim" ); |
4700 | } |
4701 | return true; |
4702 | } |
4703 | |
4704 | if (strequal(name, "ttytype" )) { |
4705 | if (value) { |
4706 | *value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim" ); |
4707 | } |
4708 | return true; |
4709 | } |
4710 | |
4711 | if (is_tty_option(name)) { |
4712 | if (value) { |
4713 | // XXX: All other t_* options were removed in 3baba1e7. |
4714 | *value = xstrdup("" ); |
4715 | } |
4716 | return true; |
4717 | } |
4718 | |
4719 | return false; |
4720 | } |
4721 | |
4722 | bool set_tty_option(const char *name, char *value) |
4723 | { |
4724 | if (strequal(name, "term" )) { |
4725 | if (p_term) { |
4726 | xfree(p_term); |
4727 | } |
4728 | p_term = value; |
4729 | return true; |
4730 | } |
4731 | |
4732 | if (strequal(name, "ttytype" )) { |
4733 | if (p_ttytype) { |
4734 | xfree(p_ttytype); |
4735 | } |
4736 | p_ttytype = value; |
4737 | return true; |
4738 | } |
4739 | |
4740 | return false; |
4741 | } |
4742 | |
4743 | /// Find index for an option |
4744 | /// |
4745 | /// @param[in] arg Option name. |
4746 | /// |
4747 | /// @return Option index or -1 if option was not found. |
4748 | static int findoption(const char *const arg) |
4749 | { |
4750 | return findoption_len(arg, strlen(arg)); |
4751 | } |
4752 | |
4753 | /// Gets the value for an option. |
4754 | /// |
4755 | /// @returns: |
4756 | /// Number or Toggle option: 1, *numval gets value. |
4757 | /// String option: 0, *stringval gets allocated string. |
4758 | /// Hidden Number or Toggle option: -1. |
4759 | /// hidden String option: -2. |
4760 | /// unknown option: -3. |
4761 | int get_option_value( |
4762 | char_u *name, |
4763 | long *numval, |
4764 | char_u **stringval, ///< NULL when only checking existence |
4765 | int opt_flags |
4766 | ) |
4767 | { |
4768 | if (get_tty_option((char *)name, (char **)stringval)) { |
4769 | return 0; |
4770 | } |
4771 | |
4772 | int opt_idx = findoption((const char *)name); |
4773 | if (opt_idx < 0) { // Unknown option. |
4774 | return -3; |
4775 | } |
4776 | |
4777 | char_u *varp = get_varp_scope(&(options[opt_idx]), opt_flags); |
4778 | |
4779 | if (options[opt_idx].flags & P_STRING) { |
4780 | if (varp == NULL) { // hidden option |
4781 | return -2; |
4782 | } |
4783 | if (stringval != NULL) { |
4784 | *stringval = vim_strsave(*(char_u **)(varp)); |
4785 | } |
4786 | return 0; |
4787 | } |
4788 | |
4789 | if (varp == NULL) { // hidden option |
4790 | return -1; |
4791 | } |
4792 | if (options[opt_idx].flags & P_NUM) { |
4793 | *numval = *(long *)varp; |
4794 | } else { |
4795 | // Special case: 'modified' is b_changed, but we also want to consider |
4796 | // it set when 'ff' or 'fenc' changed. |
4797 | if ((int *)varp == &curbuf->b_changed) { |
4798 | *numval = curbufIsChanged(); |
4799 | } else { |
4800 | *numval = (long) *(int *)varp; // NOLINT(whitespace/cast) |
4801 | } |
4802 | } |
4803 | return 1; |
4804 | } |
4805 | |
4806 | // Returns the option attributes and its value. Unlike the above function it |
4807 | // will return either global value or local value of the option depending on |
4808 | // what was requested, but it will never return global value if it was |
4809 | // requested to return local one and vice versa. Neither it will return |
4810 | // buffer-local value if it was requested to return window-local one. |
4811 | // |
4812 | // Pretends that option is absent if it is not present in the requested scope |
4813 | // (i.e. has no global, window-local or buffer-local value depending on |
4814 | // opt_type). |
4815 | // |
4816 | // Returned flags: |
4817 | // 0 hidden or unknown option, also option that does not have requested |
4818 | // type (see SREQ_* in option_defs.h) |
4819 | // see SOPT_* in option_defs.h for other flags |
4820 | // |
4821 | // Possible opt_type values: see SREQ_* in option_defs.h |
4822 | int get_option_value_strict(char *name, |
4823 | int64_t *numval, |
4824 | char **stringval, |
4825 | int opt_type, |
4826 | void *from) |
4827 | { |
4828 | if (get_tty_option(name, stringval)) { |
4829 | return SOPT_STRING | SOPT_GLOBAL; |
4830 | } |
4831 | |
4832 | char_u *varp = NULL; |
4833 | int rv = 0; |
4834 | int opt_idx = findoption(name); |
4835 | if (opt_idx < 0) { |
4836 | return 0; |
4837 | } |
4838 | |
4839 | vimoption_T *p = &options[opt_idx]; |
4840 | |
4841 | // Hidden option |
4842 | if (p->var == NULL) { |
4843 | return 0; |
4844 | } |
4845 | |
4846 | if (p->flags & P_BOOL) { |
4847 | rv |= SOPT_BOOL; |
4848 | } else if (p->flags & P_NUM) { |
4849 | rv |= SOPT_NUM; |
4850 | } else if (p->flags & P_STRING) { |
4851 | rv |= SOPT_STRING; |
4852 | } |
4853 | |
4854 | if (p->indir == PV_NONE) { |
4855 | if (opt_type == SREQ_GLOBAL) { |
4856 | rv |= SOPT_GLOBAL; |
4857 | } else { |
4858 | return 0; // Did not request global-only option |
4859 | } |
4860 | } else { |
4861 | if (p->indir & PV_BOTH) { |
4862 | rv |= SOPT_GLOBAL; |
4863 | } |
4864 | |
4865 | if (p->indir & PV_WIN) { |
4866 | if (opt_type == SREQ_BUF) { |
4867 | return 0; // Requested buffer-local, not window-local option |
4868 | } else { |
4869 | rv |= SOPT_WIN; |
4870 | } |
4871 | } else if (p->indir & PV_BUF) { |
4872 | if (opt_type == SREQ_WIN) { |
4873 | return 0; // Requested window-local, not buffer-local option |
4874 | } else { |
4875 | rv |= SOPT_BUF; |
4876 | } |
4877 | } |
4878 | } |
4879 | |
4880 | if (stringval == NULL) { |
4881 | return rv; |
4882 | } |
4883 | |
4884 | if (opt_type == SREQ_GLOBAL) { |
4885 | if (p->var == VAR_WIN) { |
4886 | return 0; |
4887 | } else { |
4888 | varp = p->var; |
4889 | } |
4890 | } else { |
4891 | if (opt_type == SREQ_BUF) { |
4892 | // Special case: 'modified' is b_changed, but we also want to |
4893 | // consider it set when 'ff' or 'fenc' changed. |
4894 | if (p->indir == PV_MOD) { |
4895 | *numval = bufIsChanged((buf_T *)from); |
4896 | varp = NULL; |
4897 | } else { |
4898 | buf_T *save_curbuf = curbuf; |
4899 | |
4900 | // only getting a pointer, no need to use aucmd_prepbuf() |
4901 | curbuf = (buf_T *)from; |
4902 | curwin->w_buffer = curbuf; |
4903 | varp = get_varp(p); |
4904 | curbuf = save_curbuf; |
4905 | curwin->w_buffer = curbuf; |
4906 | } |
4907 | } else if (opt_type == SREQ_WIN) { |
4908 | win_T *save_curwin = curwin; |
4909 | curwin = (win_T *)from; |
4910 | curbuf = curwin->w_buffer; |
4911 | varp = get_varp(p); |
4912 | curwin = save_curwin; |
4913 | curbuf = curwin->w_buffer; |
4914 | } |
4915 | |
4916 | if (varp == p->var) { |
4917 | return (rv | SOPT_UNSET); |
4918 | } |
4919 | } |
4920 | |
4921 | if (varp != NULL) { |
4922 | if (p->flags & P_STRING) { |
4923 | *stringval = xstrdup(*(char **)(varp)); |
4924 | } else if (p->flags & P_NUM) { |
4925 | *numval = *(long *) varp; |
4926 | } else { |
4927 | *numval = *(int *)varp; |
4928 | } |
4929 | } |
4930 | |
4931 | return rv; |
4932 | } |
4933 | |
4934 | /// Set the value of an option |
4935 | /// |
4936 | /// @param[in] name Option name. |
4937 | /// @param[in] number New value for the number or boolean option. |
4938 | /// @param[in] string New value for string option. |
4939 | /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). |
4940 | /// |
4941 | /// @return NULL on success, error message on error. |
4942 | char *set_option_value(const char *const name, const long number, |
4943 | const char *const string, const int opt_flags) |
4944 | FUNC_ATTR_NONNULL_ARG(1) |
4945 | { |
4946 | if (is_tty_option(name)) { |
4947 | return NULL; // Fail silently; many old vimrcs set t_xx options. |
4948 | } |
4949 | |
4950 | int opt_idx; |
4951 | char_u *varp; |
4952 | |
4953 | opt_idx = findoption(name); |
4954 | if (opt_idx < 0) { |
4955 | EMSG2(_("E355: Unknown option: %s" ), name); |
4956 | } else { |
4957 | uint32_t flags = options[opt_idx].flags; |
4958 | // Disallow changing some options in the sandbox |
4959 | if (sandbox > 0 && (flags & P_SECURE)) { |
4960 | EMSG(_(e_sandbox)); |
4961 | return NULL; |
4962 | } |
4963 | if (flags & P_STRING) { |
4964 | const char *s = string; |
4965 | if (s == NULL) { |
4966 | s = "" ; |
4967 | } |
4968 | return set_string_option(opt_idx, s, opt_flags); |
4969 | } else { |
4970 | varp = get_varp_scope(&(options[opt_idx]), opt_flags); |
4971 | if (varp != NULL) { // hidden option is not changed |
4972 | if (number == 0 && string != NULL) { |
4973 | int idx; |
4974 | |
4975 | // Either we are given a string or we are setting option |
4976 | // to zero. |
4977 | for (idx = 0; string[idx] == '0'; idx++) {} |
4978 | if (string[idx] != NUL || idx == 0) { |
4979 | // There's another character after zeros or the string |
4980 | // is empty. In both cases, we are trying to set a |
4981 | // num option using a string. |
4982 | EMSG3(_("E521: Number required: &%s = '%s'" ), |
4983 | name, string); |
4984 | return NULL; // do nothing as we hit an error |
4985 | } |
4986 | } |
4987 | if (flags & P_NUM) { |
4988 | return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags); |
4989 | } else { |
4990 | return set_bool_option(opt_idx, varp, (int)number, opt_flags); |
4991 | } |
4992 | } |
4993 | } |
4994 | } |
4995 | return NULL; |
4996 | } |
4997 | |
4998 | // Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. |
4999 | // When "has_lt" is true there is a '<' before "*arg_arg". |
5000 | // Returns 0 when the key is not recognized. |
5001 | int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) |
5002 | { |
5003 | int key = 0; |
5004 | int modifiers; |
5005 | const char_u *arg = arg_arg; |
5006 | |
5007 | // Don't use get_special_key_code() for t_xx, we don't want it to call |
5008 | // add_termcap_entry(). |
5009 | if (len >= 4 && arg[0] == 't' && arg[1] == '_') { |
5010 | key = TERMCAP2KEY(arg[2], arg[3]); |
5011 | } else if (has_lt) { |
5012 | arg--; // put arg at the '<' |
5013 | modifiers = 0; |
5014 | key = find_special_key(&arg, len + 1, &modifiers, true, true, false); |
5015 | if (modifiers) { // can't handle modifiers here |
5016 | key = 0; |
5017 | } |
5018 | } |
5019 | return key; |
5020 | } |
5021 | |
5022 | static int find_key_option(const char_u *arg, bool has_lt) |
5023 | { |
5024 | return find_key_option_len(arg, STRLEN(arg), has_lt); |
5025 | } |
5026 | |
5027 | /* |
5028 | * if 'all' == 0: show changed options |
5029 | * if 'all' == 1: show all normal options |
5030 | */ |
5031 | static void |
5032 | showoptions( |
5033 | int all, |
5034 | int opt_flags // OPT_LOCAL and/or OPT_GLOBAL |
5035 | ) |
5036 | { |
5037 | vimoption_T *p; |
5038 | int col; |
5039 | char_u *varp; |
5040 | int item_count; |
5041 | int run; |
5042 | int row, rows; |
5043 | int cols; |
5044 | int i; |
5045 | int len; |
5046 | |
5047 | #define INC 20 |
5048 | #define GAP 3 |
5049 | |
5050 | vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT); |
5051 | |
5052 | // Highlight title |
5053 | if (opt_flags & OPT_GLOBAL) { |
5054 | MSG_PUTS_TITLE(_("\n--- Global option values ---" )); |
5055 | } else if (opt_flags & OPT_LOCAL) { |
5056 | MSG_PUTS_TITLE(_("\n--- Local option values ---" )); |
5057 | } else { |
5058 | MSG_PUTS_TITLE(_("\n--- Options ---" )); |
5059 | } |
5060 | |
5061 | // Do the loop two times: |
5062 | // 1. display the short items |
5063 | // 2. display the long items (only strings and numbers) |
5064 | for (run = 1; run <= 2 && !got_int; run++) { |
5065 | // collect the items in items[] |
5066 | item_count = 0; |
5067 | for (p = &options[0]; p->fullname != NULL; p++) { |
5068 | // apply :filter /pat/ |
5069 | if (message_filtered((char_u *)p->fullname)) { |
5070 | continue; |
5071 | } |
5072 | |
5073 | varp = NULL; |
5074 | if (opt_flags != 0) { |
5075 | if (p->indir != PV_NONE) { |
5076 | varp = get_varp_scope(p, opt_flags); |
5077 | } |
5078 | } else { |
5079 | varp = get_varp(p); |
5080 | } |
5081 | if (varp != NULL |
5082 | && (all == 1 || (all == 0 && !optval_default(p, varp)))) { |
5083 | if (p->flags & P_BOOL) { |
5084 | len = 1; // a toggle option fits always |
5085 | } else { |
5086 | option_value2string(p, opt_flags); |
5087 | len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1; |
5088 | } |
5089 | if ((len <= INC - GAP && run == 1) |
5090 | || (len > INC - GAP && run == 2)) { |
5091 | items[item_count++] = p; |
5092 | } |
5093 | } |
5094 | } |
5095 | |
5096 | /* |
5097 | * display the items |
5098 | */ |
5099 | if (run == 1) { |
5100 | assert(Columns <= INT_MAX - GAP |
5101 | && Columns + GAP >= INT_MIN + 3 |
5102 | && (Columns + GAP - 3) / INC >= INT_MIN |
5103 | && (Columns + GAP - 3) / INC <= INT_MAX); |
5104 | cols = (int)((Columns + GAP - 3) / INC); |
5105 | if (cols == 0) { |
5106 | cols = 1; |
5107 | } |
5108 | rows = (item_count + cols - 1) / cols; |
5109 | } else { // run == 2 |
5110 | rows = item_count; |
5111 | } |
5112 | for (row = 0; row < rows && !got_int; row++) { |
5113 | msg_putchar('\n'); // go to next line |
5114 | if (got_int) { // 'q' typed in more |
5115 | break; |
5116 | } |
5117 | col = 0; |
5118 | for (i = row; i < item_count; i += rows) { |
5119 | msg_col = col; // make columns |
5120 | showoneopt(items[i], opt_flags); |
5121 | col += INC; |
5122 | } |
5123 | ui_flush(); |
5124 | os_breakcheck(); |
5125 | } |
5126 | } |
5127 | xfree(items); |
5128 | } |
5129 | |
5130 | /// Return true if option "p" has its default value. |
5131 | static int optval_default(vimoption_T *p, char_u *varp) |
5132 | { |
5133 | int dvi; |
5134 | |
5135 | if (varp == NULL) { |
5136 | return true; // hidden option is always at default |
5137 | } |
5138 | dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT; |
5139 | if (p->flags & P_NUM) { |
5140 | return *(long *)varp == (long)(intptr_t)p->def_val[dvi]; |
5141 | } |
5142 | if (p->flags & P_BOOL) { |
5143 | return *(int *)varp == (int)(intptr_t)p->def_val[dvi]; |
5144 | } |
5145 | // P_STRING |
5146 | return STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0; |
5147 | } |
5148 | |
5149 | /// Send update to UIs with values of UI relevant options |
5150 | void ui_refresh_options(void) |
5151 | { |
5152 | for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { |
5153 | uint32_t flags = options[opt_idx].flags; |
5154 | if (!(flags & P_UI_OPTION)) { |
5155 | continue; |
5156 | } |
5157 | String name = cstr_as_string(options[opt_idx].fullname); |
5158 | void *varp = options[opt_idx].var; |
5159 | Object value = OBJECT_INIT; |
5160 | if (flags & P_BOOL) { |
5161 | value = BOOLEAN_OBJ(*(int *)varp); |
5162 | } else if (flags & P_NUM) { |
5163 | value = INTEGER_OBJ(*(long *)varp); |
5164 | } else if (flags & P_STRING) { |
5165 | // cstr_as_string handles NULL string |
5166 | value = STRING_OBJ(cstr_as_string(*(char **)varp)); |
5167 | } |
5168 | ui_call_option_set(name, value); |
5169 | } |
5170 | } |
5171 | |
5172 | /* |
5173 | * showoneopt: show the value of one option |
5174 | * must not be called with a hidden option! |
5175 | */ |
5176 | static void |
5177 | showoneopt( |
5178 | vimoption_T *p, |
5179 | int opt_flags // OPT_LOCAL or OPT_GLOBAL |
5180 | ) |
5181 | { |
5182 | char_u *varp; |
5183 | int save_silent = silent_mode; |
5184 | |
5185 | silent_mode = false; |
5186 | info_message = true; // use mch_msg(), not mch_errmsg() |
5187 | |
5188 | varp = get_varp_scope(p, opt_flags); |
5189 | |
5190 | // for 'modified' we also need to check if 'ff' or 'fenc' changed. |
5191 | if ((p->flags & P_BOOL) && ((int *)varp == &curbuf->b_changed |
5192 | ? !curbufIsChanged() : !*(int *)varp)) { |
5193 | MSG_PUTS("no" ); |
5194 | } else if ((p->flags & P_BOOL) && *(int *)varp < 0) { |
5195 | MSG_PUTS("--" ); |
5196 | } else { |
5197 | MSG_PUTS(" " ); |
5198 | } |
5199 | MSG_PUTS(p->fullname); |
5200 | if (!(p->flags & P_BOOL)) { |
5201 | msg_putchar('='); |
5202 | // put value string in NameBuff |
5203 | option_value2string(p, opt_flags); |
5204 | msg_outtrans(NameBuff); |
5205 | } |
5206 | |
5207 | silent_mode = save_silent; |
5208 | info_message = false; |
5209 | } |
5210 | |
5211 | /* |
5212 | * Write modified options as ":set" commands to a file. |
5213 | * |
5214 | * There are three values for "opt_flags": |
5215 | * OPT_GLOBAL: Write global option values and fresh values of |
5216 | * buffer-local options (used for start of a session |
5217 | * file). |
5218 | * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for |
5219 | * curwin (used for a vimrc file). |
5220 | * OPT_LOCAL: Write buffer-local option values for curbuf, fresh |
5221 | * and local values for window-local options of |
5222 | * curwin. Local values are also written when at the |
5223 | * default value, because a modeline or autocommand |
5224 | * may have set them when doing ":edit file" and the |
5225 | * user has set them back at the default or fresh |
5226 | * value. |
5227 | * When "local_only" is true, don't write fresh |
5228 | * values, only local values (for ":mkview"). |
5229 | * (fresh value = value used for a new buffer or window for a local option). |
5230 | * |
5231 | * Return FAIL on error, OK otherwise. |
5232 | */ |
5233 | int makeset(FILE *fd, int opt_flags, int local_only) |
5234 | { |
5235 | vimoption_T *p; |
5236 | char_u *varp; // currently used value |
5237 | char_u *varp_fresh; // local value |
5238 | char_u *varp_local = NULL; // fresh value |
5239 | char *cmd; |
5240 | int round; |
5241 | int pri; |
5242 | |
5243 | /* |
5244 | * Some options are never written: |
5245 | * - Options that don't have a default (terminal name, columns, lines). |
5246 | * - Terminal options. |
5247 | * - Hidden options. |
5248 | * |
5249 | * Do the loop over "options[]" twice: once for options with the |
5250 | * P_PRI_MKRC flag and once without. |
5251 | */ |
5252 | for (pri = 1; pri >= 0; pri--) { |
5253 | for (p = &options[0]; p->fullname; p++) { |
5254 | if (!(p->flags & P_NO_MKRC) |
5255 | && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) { |
5256 | // skip global option when only doing locals |
5257 | if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) { |
5258 | continue; |
5259 | } |
5260 | |
5261 | /* Do not store options like 'bufhidden' and 'syntax' in a vimrc |
5262 | * file, they are always buffer-specific. */ |
5263 | if ((opt_flags & OPT_GLOBAL) && (p->flags & P_NOGLOB)) { |
5264 | continue; |
5265 | } |
5266 | |
5267 | varp = get_varp_scope(p, opt_flags); |
5268 | // Hidden options are never written. |
5269 | if (!varp) { |
5270 | continue; |
5271 | } |
5272 | // Global values are only written when not at the default value. |
5273 | if ((opt_flags & OPT_GLOBAL) && optval_default(p, varp)) { |
5274 | continue; |
5275 | } |
5276 | |
5277 | round = 2; |
5278 | if (p->indir != PV_NONE) { |
5279 | if (p->var == VAR_WIN) { |
5280 | // skip window-local option when only doing globals |
5281 | if (!(opt_flags & OPT_LOCAL)) { |
5282 | continue; |
5283 | } |
5284 | // When fresh value of window-local option is not at the |
5285 | // default, need to write it too. |
5286 | if (!(opt_flags & OPT_GLOBAL) && !local_only) { |
5287 | varp_fresh = get_varp_scope(p, OPT_GLOBAL); |
5288 | if (!optval_default(p, varp_fresh)) { |
5289 | round = 1; |
5290 | varp_local = varp; |
5291 | varp = varp_fresh; |
5292 | } |
5293 | } |
5294 | } |
5295 | } |
5296 | |
5297 | /* Round 1: fresh value for window-local options. |
5298 | * Round 2: other values */ |
5299 | for (; round <= 2; varp = varp_local, round++) { |
5300 | if (round == 1 || (opt_flags & OPT_GLOBAL)) { |
5301 | cmd = "set" ; |
5302 | } else { |
5303 | cmd = "setlocal" ; |
5304 | } |
5305 | |
5306 | if (p->flags & P_BOOL) { |
5307 | if (put_setbool(fd, cmd, p->fullname, *(int *)varp) == FAIL) { |
5308 | return FAIL; |
5309 | } |
5310 | } else if (p->flags & P_NUM) { |
5311 | if (put_setnum(fd, cmd, p->fullname, (long *)varp) == FAIL) { |
5312 | return FAIL; |
5313 | } |
5314 | } else { // P_STRING |
5315 | int do_endif = false; |
5316 | |
5317 | // Don't set 'syntax' and 'filetype' again if the value is |
5318 | // already right, avoids reloading the syntax file. |
5319 | if (p->indir == PV_SYN || p->indir == PV_FT) { |
5320 | if (fprintf(fd, "if &%s != '%s'" , p->fullname, |
5321 | *(char_u **)(varp)) < 0 |
5322 | || put_eol(fd) < 0) { |
5323 | return FAIL; |
5324 | } |
5325 | do_endif = true; |
5326 | } |
5327 | if (put_setstring(fd, cmd, p->fullname, (char_u **)varp, |
5328 | (p->flags & P_EXPAND) != 0) == FAIL) |
5329 | return FAIL; |
5330 | if (do_endif) { |
5331 | if (put_line(fd, "endif" ) == FAIL) { |
5332 | return FAIL; |
5333 | } |
5334 | } |
5335 | } |
5336 | } |
5337 | } |
5338 | } |
5339 | } |
5340 | return OK; |
5341 | } |
5342 | |
5343 | /* |
5344 | * Generate set commands for the local fold options only. Used when |
5345 | * 'sessionoptions' or 'viewoptions' contains "folds" but not "options". |
5346 | */ |
5347 | int makefoldset(FILE *fd) |
5348 | { |
5349 | if (put_setstring(fd, "setlocal" , "fdm" , &curwin->w_p_fdm, false) == FAIL |
5350 | || put_setstring(fd, "setlocal" , "fde" , &curwin->w_p_fde, false) |
5351 | == FAIL |
5352 | || put_setstring(fd, "setlocal" , "fmr" , &curwin->w_p_fmr, false) |
5353 | == FAIL |
5354 | || put_setstring(fd, "setlocal" , "fdi" , &curwin->w_p_fdi, false) |
5355 | == FAIL |
5356 | || put_setnum(fd, "setlocal" , "fdl" , &curwin->w_p_fdl) == FAIL |
5357 | || put_setnum(fd, "setlocal" , "fml" , &curwin->w_p_fml) == FAIL |
5358 | || put_setnum(fd, "setlocal" , "fdn" , &curwin->w_p_fdn) == FAIL |
5359 | || put_setbool(fd, "setlocal" , "fen" , curwin->w_p_fen) == FAIL |
5360 | ) { |
5361 | return FAIL; |
5362 | } |
5363 | |
5364 | return OK; |
5365 | } |
5366 | |
5367 | static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, int expand) |
5368 | { |
5369 | char_u *s; |
5370 | char_u *buf; |
5371 | |
5372 | if (fprintf(fd, "%s %s=" , cmd, name) < 0) { |
5373 | return FAIL; |
5374 | } |
5375 | if (*valuep != NULL) { |
5376 | /* Output 'pastetoggle' as key names. For other |
5377 | * options some characters have to be escaped with |
5378 | * CTRL-V or backslash */ |
5379 | if (valuep == &p_pt) { |
5380 | s = *valuep; |
5381 | while (*s != NUL) { |
5382 | if (put_escstr(fd, (char_u *)str2special((const char **)&s, false, |
5383 | false), 2) |
5384 | == FAIL) { |
5385 | return FAIL; |
5386 | } |
5387 | } |
5388 | } else if (expand) { |
5389 | buf = xmalloc(MAXPATHL); |
5390 | home_replace(NULL, *valuep, buf, MAXPATHL, false); |
5391 | if (put_escstr(fd, buf, 2) == FAIL) { |
5392 | xfree(buf); |
5393 | return FAIL; |
5394 | } |
5395 | xfree(buf); |
5396 | } else if (put_escstr(fd, *valuep, 2) == FAIL) { |
5397 | return FAIL; |
5398 | } |
5399 | } |
5400 | if (put_eol(fd) < 0) { |
5401 | return FAIL; |
5402 | } |
5403 | return OK; |
5404 | } |
5405 | |
5406 | static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep) |
5407 | { |
5408 | long wc; |
5409 | |
5410 | if (fprintf(fd, "%s %s=" , cmd, name) < 0) { |
5411 | return FAIL; |
5412 | } |
5413 | if (wc_use_keyname((char_u *)valuep, &wc)) { |
5414 | // print 'wildchar' and 'wildcharm' as a key name |
5415 | if (fputs((char *)get_special_key_name((int)wc, 0), fd) < 0) { |
5416 | return FAIL; |
5417 | } |
5418 | } else if (fprintf(fd, "%" PRId64, (int64_t)(*valuep)) < 0) { |
5419 | return FAIL; |
5420 | } |
5421 | if (put_eol(fd) < 0) { |
5422 | return FAIL; |
5423 | } |
5424 | return OK; |
5425 | } |
5426 | |
5427 | static int put_setbool(FILE *fd, char *cmd, char *name, int value) |
5428 | { |
5429 | if (value < 0) { // global/local option using global value |
5430 | return OK; |
5431 | } |
5432 | if (fprintf(fd, "%s %s%s" , cmd, value ? "" : "no" , name) < 0 |
5433 | || put_eol(fd) < 0) { |
5434 | return FAIL; |
5435 | } |
5436 | return OK; |
5437 | } |
5438 | |
5439 | /* |
5440 | * Compute columns for ruler and shown command. 'sc_col' is also used to |
5441 | * decide what the maximum length of a message on the status line can be. |
5442 | * If there is a status line for the last window, 'sc_col' is independent |
5443 | * of 'ru_col'. |
5444 | */ |
5445 | |
5446 | #define COL_RULER 17 // columns needed by standard ruler |
5447 | |
5448 | void comp_col(void) |
5449 | { |
5450 | int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW)); |
5451 | |
5452 | sc_col = 0; |
5453 | ru_col = 0; |
5454 | if (p_ru) { |
5455 | ru_col = (ru_wid ? ru_wid : COL_RULER) + 1; |
5456 | // no last status line, adjust sc_col |
5457 | if (!last_has_status) { |
5458 | sc_col = ru_col; |
5459 | } |
5460 | } |
5461 | if (p_sc) { |
5462 | sc_col += SHOWCMD_COLS; |
5463 | if (!p_ru || last_has_status) { // no need for separating space |
5464 | sc_col++; |
5465 | } |
5466 | } |
5467 | assert(sc_col >= 0 |
5468 | && INT_MIN + sc_col <= Columns |
5469 | && Columns - sc_col <= INT_MAX); |
5470 | sc_col = (int)(Columns - sc_col); |
5471 | assert(ru_col >= 0 |
5472 | && INT_MIN + ru_col <= Columns |
5473 | && Columns - ru_col <= INT_MAX); |
5474 | ru_col = (int)(Columns - ru_col); |
5475 | if (sc_col <= 0) { // screen too narrow, will become a mess |
5476 | sc_col = 1; |
5477 | } |
5478 | if (ru_col <= 0) { |
5479 | ru_col = 1; |
5480 | } |
5481 | set_vim_var_nr(VV_ECHOSPACE, sc_col - 1); |
5482 | } |
5483 | |
5484 | // Unset local option value, similar to ":set opt<". |
5485 | void unset_global_local_option(char *name, void *from) |
5486 | { |
5487 | vimoption_T *p; |
5488 | buf_T *buf = (buf_T *)from; |
5489 | |
5490 | int opt_idx = findoption(name); |
5491 | if (opt_idx < 0) { |
5492 | EMSG2(_("E355: Unknown option: %s" ), name); |
5493 | return; |
5494 | } |
5495 | p = &(options[opt_idx]); |
5496 | |
5497 | switch ((int)p->indir) |
5498 | { |
5499 | // global option with local value: use local value if it's been set |
5500 | case PV_EP: |
5501 | clear_string_option(&buf->b_p_ep); |
5502 | break; |
5503 | case PV_KP: |
5504 | clear_string_option(&buf->b_p_kp); |
5505 | break; |
5506 | case PV_PATH: |
5507 | clear_string_option(&buf->b_p_path); |
5508 | break; |
5509 | case PV_AR: |
5510 | buf->b_p_ar = -1; |
5511 | break; |
5512 | case PV_BKC: |
5513 | clear_string_option(&buf->b_p_bkc); |
5514 | buf->b_bkc_flags = 0; |
5515 | break; |
5516 | case PV_TAGS: |
5517 | clear_string_option(&buf->b_p_tags); |
5518 | break; |
5519 | case PV_TC: |
5520 | clear_string_option(&buf->b_p_tc); |
5521 | buf->b_tc_flags = 0; |
5522 | break; |
5523 | case PV_DEF: |
5524 | clear_string_option(&buf->b_p_def); |
5525 | break; |
5526 | case PV_INC: |
5527 | clear_string_option(&buf->b_p_inc); |
5528 | break; |
5529 | case PV_DICT: |
5530 | clear_string_option(&buf->b_p_dict); |
5531 | break; |
5532 | case PV_TSR: |
5533 | clear_string_option(&buf->b_p_tsr); |
5534 | break; |
5535 | case PV_FP: |
5536 | clear_string_option(&buf->b_p_fp); |
5537 | break; |
5538 | case PV_EFM: |
5539 | clear_string_option(&buf->b_p_efm); |
5540 | break; |
5541 | case PV_GP: |
5542 | clear_string_option(&buf->b_p_gp); |
5543 | break; |
5544 | case PV_MP: |
5545 | clear_string_option(&buf->b_p_mp); |
5546 | break; |
5547 | case PV_STL: |
5548 | clear_string_option(&((win_T *)from)->w_p_stl); |
5549 | break; |
5550 | case PV_UL: |
5551 | buf->b_p_ul = NO_LOCAL_UNDOLEVEL; |
5552 | break; |
5553 | case PV_LW: |
5554 | clear_string_option(&buf->b_p_lw); |
5555 | break; |
5556 | case PV_MENC: |
5557 | clear_string_option(&buf->b_p_menc); |
5558 | break; |
5559 | } |
5560 | } |
5561 | |
5562 | /* |
5563 | * Get pointer to option variable, depending on local or global scope. |
5564 | */ |
5565 | static char_u *get_varp_scope(vimoption_T *p, int opt_flags) |
5566 | { |
5567 | if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { |
5568 | if (p->var == VAR_WIN) { |
5569 | return (char_u *)GLOBAL_WO(get_varp(p)); |
5570 | } |
5571 | return p->var; |
5572 | } |
5573 | if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { |
5574 | switch ((int)p->indir) { |
5575 | case PV_FP: return (char_u *)&(curbuf->b_p_fp); |
5576 | case PV_EFM: return (char_u *)&(curbuf->b_p_efm); |
5577 | case PV_GP: return (char_u *)&(curbuf->b_p_gp); |
5578 | case PV_MP: return (char_u *)&(curbuf->b_p_mp); |
5579 | case PV_EP: return (char_u *)&(curbuf->b_p_ep); |
5580 | case PV_KP: return (char_u *)&(curbuf->b_p_kp); |
5581 | case PV_PATH: return (char_u *)&(curbuf->b_p_path); |
5582 | case PV_AR: return (char_u *)&(curbuf->b_p_ar); |
5583 | case PV_TAGS: return (char_u *)&(curbuf->b_p_tags); |
5584 | case PV_TC: return (char_u *)&(curbuf->b_p_tc); |
5585 | case PV_DEF: return (char_u *)&(curbuf->b_p_def); |
5586 | case PV_INC: return (char_u *)&(curbuf->b_p_inc); |
5587 | case PV_DICT: return (char_u *)&(curbuf->b_p_dict); |
5588 | case PV_TSR: return (char_u *)&(curbuf->b_p_tsr); |
5589 | case PV_STL: return (char_u *)&(curwin->w_p_stl); |
5590 | case PV_UL: return (char_u *)&(curbuf->b_p_ul); |
5591 | case PV_LW: return (char_u *)&(curbuf->b_p_lw); |
5592 | case PV_BKC: return (char_u *)&(curbuf->b_p_bkc); |
5593 | case PV_MENC: return (char_u *)&(curbuf->b_p_menc); |
5594 | } |
5595 | return NULL; // "cannot happen" |
5596 | } |
5597 | return get_varp(p); |
5598 | } |
5599 | |
5600 | /* |
5601 | * Get pointer to option variable. |
5602 | */ |
5603 | static char_u *get_varp(vimoption_T *p) |
5604 | { |
5605 | // hidden option, always return NULL |
5606 | if (p->var == NULL) { |
5607 | return NULL; |
5608 | } |
5609 | |
5610 | switch ((int)p->indir) { |
5611 | case PV_NONE: return p->var; |
5612 | |
5613 | // global option with local value: use local value if it's been set |
5614 | case PV_EP: return *curbuf->b_p_ep != NUL |
5615 | ? (char_u *)&curbuf->b_p_ep : p->var; |
5616 | case PV_KP: return *curbuf->b_p_kp != NUL |
5617 | ? (char_u *)&curbuf->b_p_kp : p->var; |
5618 | case PV_PATH: return *curbuf->b_p_path != NUL |
5619 | ? (char_u *)&(curbuf->b_p_path) : p->var; |
5620 | case PV_AR: return curbuf->b_p_ar >= 0 |
5621 | ? (char_u *)&(curbuf->b_p_ar) : p->var; |
5622 | case PV_TAGS: return *curbuf->b_p_tags != NUL |
5623 | ? (char_u *)&(curbuf->b_p_tags) : p->var; |
5624 | case PV_TC: return *curbuf->b_p_tc != NUL |
5625 | ? (char_u *)&(curbuf->b_p_tc) : p->var; |
5626 | case PV_BKC: return *curbuf->b_p_bkc != NUL |
5627 | ? (char_u *)&(curbuf->b_p_bkc) : p->var; |
5628 | case PV_DEF: return *curbuf->b_p_def != NUL |
5629 | ? (char_u *)&(curbuf->b_p_def) : p->var; |
5630 | case PV_INC: return *curbuf->b_p_inc != NUL |
5631 | ? (char_u *)&(curbuf->b_p_inc) : p->var; |
5632 | case PV_DICT: return *curbuf->b_p_dict != NUL |
5633 | ? (char_u *)&(curbuf->b_p_dict) : p->var; |
5634 | case PV_TSR: return *curbuf->b_p_tsr != NUL |
5635 | ? (char_u *)&(curbuf->b_p_tsr) : p->var; |
5636 | case PV_FP: return *curbuf->b_p_fp != NUL |
5637 | ? (char_u *)&(curbuf->b_p_fp) : p->var; |
5638 | case PV_EFM: return *curbuf->b_p_efm != NUL |
5639 | ? (char_u *)&(curbuf->b_p_efm) : p->var; |
5640 | case PV_GP: return *curbuf->b_p_gp != NUL |
5641 | ? (char_u *)&(curbuf->b_p_gp) : p->var; |
5642 | case PV_MP: return *curbuf->b_p_mp != NUL |
5643 | ? (char_u *)&(curbuf->b_p_mp) : p->var; |
5644 | case PV_STL: return *curwin->w_p_stl != NUL |
5645 | ? (char_u *)&(curwin->w_p_stl) : p->var; |
5646 | case PV_UL: return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL |
5647 | ? (char_u *)&(curbuf->b_p_ul) : p->var; |
5648 | case PV_LW: return *curbuf->b_p_lw != NUL |
5649 | ? (char_u *)&(curbuf->b_p_lw) : p->var; |
5650 | case PV_MENC: return *curbuf->b_p_menc != NUL |
5651 | ? (char_u *)&(curbuf->b_p_menc) : p->var; |
5652 | |
5653 | case PV_ARAB: return (char_u *)&(curwin->w_p_arab); |
5654 | case PV_LIST: return (char_u *)&(curwin->w_p_list); |
5655 | case PV_SPELL: return (char_u *)&(curwin->w_p_spell); |
5656 | case PV_CUC: return (char_u *)&(curwin->w_p_cuc); |
5657 | case PV_CUL: return (char_u *)&(curwin->w_p_cul); |
5658 | case PV_CC: return (char_u *)&(curwin->w_p_cc); |
5659 | case PV_DIFF: return (char_u *)&(curwin->w_p_diff); |
5660 | case PV_FDC: return (char_u *)&(curwin->w_p_fdc); |
5661 | case PV_FEN: return (char_u *)&(curwin->w_p_fen); |
5662 | case PV_FDI: return (char_u *)&(curwin->w_p_fdi); |
5663 | case PV_FDL: return (char_u *)&(curwin->w_p_fdl); |
5664 | case PV_FDM: return (char_u *)&(curwin->w_p_fdm); |
5665 | case PV_FML: return (char_u *)&(curwin->w_p_fml); |
5666 | case PV_FDN: return (char_u *)&(curwin->w_p_fdn); |
5667 | case PV_FDE: return (char_u *)&(curwin->w_p_fde); |
5668 | case PV_FDT: return (char_u *)&(curwin->w_p_fdt); |
5669 | case PV_FMR: return (char_u *)&(curwin->w_p_fmr); |
5670 | case PV_NU: return (char_u *)&(curwin->w_p_nu); |
5671 | case PV_RNU: return (char_u *)&(curwin->w_p_rnu); |
5672 | case PV_NUW: return (char_u *)&(curwin->w_p_nuw); |
5673 | case PV_WFH: return (char_u *)&(curwin->w_p_wfh); |
5674 | case PV_WFW: return (char_u *)&(curwin->w_p_wfw); |
5675 | case PV_PVW: return (char_u *)&(curwin->w_p_pvw); |
5676 | case PV_RL: return (char_u *)&(curwin->w_p_rl); |
5677 | case PV_RLC: return (char_u *)&(curwin->w_p_rlc); |
5678 | case PV_SCROLL: return (char_u *)&(curwin->w_p_scr); |
5679 | case PV_WRAP: return (char_u *)&(curwin->w_p_wrap); |
5680 | case PV_LBR: return (char_u *)&(curwin->w_p_lbr); |
5681 | case PV_BRI: return (char_u *)&(curwin->w_p_bri); |
5682 | case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt); |
5683 | case PV_SCBIND: return (char_u *)&(curwin->w_p_scb); |
5684 | case PV_CRBIND: return (char_u *)&(curwin->w_p_crb); |
5685 | case PV_COCU: return (char_u *)&(curwin->w_p_cocu); |
5686 | case PV_COLE: return (char_u *)&(curwin->w_p_cole); |
5687 | |
5688 | case PV_AI: return (char_u *)&(curbuf->b_p_ai); |
5689 | case PV_BIN: return (char_u *)&(curbuf->b_p_bin); |
5690 | case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb); |
5691 | case PV_BH: return (char_u *)&(curbuf->b_p_bh); |
5692 | case PV_BT: return (char_u *)&(curbuf->b_p_bt); |
5693 | case PV_BL: return (char_u *)&(curbuf->b_p_bl); |
5694 | case PV_CHANNEL:return (char_u *)&(curbuf->b_p_channel); |
5695 | case PV_CI: return (char_u *)&(curbuf->b_p_ci); |
5696 | case PV_CIN: return (char_u *)&(curbuf->b_p_cin); |
5697 | case PV_CINK: return (char_u *)&(curbuf->b_p_cink); |
5698 | case PV_CINO: return (char_u *)&(curbuf->b_p_cino); |
5699 | case PV_CINW: return (char_u *)&(curbuf->b_p_cinw); |
5700 | case PV_COM: return (char_u *)&(curbuf->b_p_com); |
5701 | case PV_CMS: return (char_u *)&(curbuf->b_p_cms); |
5702 | case PV_CPT: return (char_u *)&(curbuf->b_p_cpt); |
5703 | case PV_CFU: return (char_u *)&(curbuf->b_p_cfu); |
5704 | case PV_OFU: return (char_u *)&(curbuf->b_p_ofu); |
5705 | case PV_EOL: return (char_u *)&(curbuf->b_p_eol); |
5706 | case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol); |
5707 | case PV_ET: return (char_u *)&(curbuf->b_p_et); |
5708 | case PV_FENC: return (char_u *)&(curbuf->b_p_fenc); |
5709 | case PV_FF: return (char_u *)&(curbuf->b_p_ff); |
5710 | case PV_FT: return (char_u *)&(curbuf->b_p_ft); |
5711 | case PV_FO: return (char_u *)&(curbuf->b_p_fo); |
5712 | case PV_FLP: return (char_u *)&(curbuf->b_p_flp); |
5713 | case PV_IMI: return (char_u *)&(curbuf->b_p_iminsert); |
5714 | case PV_IMS: return (char_u *)&(curbuf->b_p_imsearch); |
5715 | case PV_INF: return (char_u *)&(curbuf->b_p_inf); |
5716 | case PV_ISK: return (char_u *)&(curbuf->b_p_isk); |
5717 | case PV_INEX: return (char_u *)&(curbuf->b_p_inex); |
5718 | case PV_INDE: return (char_u *)&(curbuf->b_p_inde); |
5719 | case PV_INDK: return (char_u *)&(curbuf->b_p_indk); |
5720 | case PV_FEX: return (char_u *)&(curbuf->b_p_fex); |
5721 | case PV_LISP: return (char_u *)&(curbuf->b_p_lisp); |
5722 | case PV_ML: return (char_u *)&(curbuf->b_p_ml); |
5723 | case PV_MPS: return (char_u *)&(curbuf->b_p_mps); |
5724 | case PV_MA: return (char_u *)&(curbuf->b_p_ma); |
5725 | case PV_MOD: return (char_u *)&(curbuf->b_changed); |
5726 | case PV_NF: return (char_u *)&(curbuf->b_p_nf); |
5727 | case PV_PI: return (char_u *)&(curbuf->b_p_pi); |
5728 | case PV_QE: return (char_u *)&(curbuf->b_p_qe); |
5729 | case PV_RO: return (char_u *)&(curbuf->b_p_ro); |
5730 | case PV_SCBK: return (char_u *)&(curbuf->b_p_scbk); |
5731 | case PV_SI: return (char_u *)&(curbuf->b_p_si); |
5732 | case PV_STS: return (char_u *)&(curbuf->b_p_sts); |
5733 | case PV_SUA: return (char_u *)&(curbuf->b_p_sua); |
5734 | case PV_SWF: return (char_u *)&(curbuf->b_p_swf); |
5735 | case PV_SMC: return (char_u *)&(curbuf->b_p_smc); |
5736 | case PV_SYN: return (char_u *)&(curbuf->b_p_syn); |
5737 | case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc); |
5738 | case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf); |
5739 | case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl); |
5740 | case PV_SW: return (char_u *)&(curbuf->b_p_sw); |
5741 | case PV_TS: return (char_u *)&(curbuf->b_p_ts); |
5742 | case PV_TW: return (char_u *)&(curbuf->b_p_tw); |
5743 | case PV_UDF: return (char_u *)&(curbuf->b_p_udf); |
5744 | case PV_WM: return (char_u *)&(curbuf->b_p_wm); |
5745 | case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap); |
5746 | case PV_SCL: return (char_u *)&(curwin->w_p_scl); |
5747 | case PV_WINHL: return (char_u *)&(curwin->w_p_winhl); |
5748 | case PV_FCS: return (char_u *)&(curwin->w_p_fcs); |
5749 | case PV_LCS: return (char_u *)&(curwin->w_p_lcs); |
5750 | case PV_WINBL: return (char_u *)&(curwin->w_p_winbl); |
5751 | default: IEMSG(_("E356: get_varp ERROR" )); |
5752 | } |
5753 | // always return a valid pointer to avoid a crash! |
5754 | return (char_u *)&(curbuf->b_p_wm); |
5755 | } |
5756 | |
5757 | /* |
5758 | * Get the value of 'equalprg', either the buffer-local one or the global one. |
5759 | */ |
5760 | char_u *get_equalprg(void) |
5761 | { |
5762 | if (*curbuf->b_p_ep == NUL) { |
5763 | return p_ep; |
5764 | } |
5765 | return curbuf->b_p_ep; |
5766 | } |
5767 | |
5768 | /* |
5769 | * Copy options from one window to another. |
5770 | * Used when splitting a window. |
5771 | */ |
5772 | void win_copy_options(win_T *wp_from, win_T *wp_to) |
5773 | { |
5774 | copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt); |
5775 | copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt); |
5776 | } |
5777 | |
5778 | /* |
5779 | * Copy the options from one winopt_T to another. |
5780 | * Doesn't free the old option values in "to", use clear_winopt() for that. |
5781 | * The 'scroll' option is not copied, because it depends on the window height. |
5782 | * The 'previewwindow' option is reset, there can be only one preview window. |
5783 | */ |
5784 | void copy_winopt(winopt_T *from, winopt_T *to) |
5785 | { |
5786 | to->wo_arab = from->wo_arab; |
5787 | to->wo_list = from->wo_list; |
5788 | to->wo_nu = from->wo_nu; |
5789 | to->wo_rnu = from->wo_rnu; |
5790 | to->wo_nuw = from->wo_nuw; |
5791 | to->wo_rl = from->wo_rl; |
5792 | to->wo_rlc = vim_strsave(from->wo_rlc); |
5793 | to->wo_stl = vim_strsave(from->wo_stl); |
5794 | to->wo_wrap = from->wo_wrap; |
5795 | to->wo_wrap_save = from->wo_wrap_save; |
5796 | to->wo_lbr = from->wo_lbr; |
5797 | to->wo_bri = from->wo_bri; |
5798 | to->wo_briopt = vim_strsave(from->wo_briopt); |
5799 | to->wo_scb = from->wo_scb; |
5800 | to->wo_scb_save = from->wo_scb_save; |
5801 | to->wo_crb = from->wo_crb; |
5802 | to->wo_crb_save = from->wo_crb_save; |
5803 | to->wo_spell = from->wo_spell; |
5804 | to->wo_cuc = from->wo_cuc; |
5805 | to->wo_cul = from->wo_cul; |
5806 | to->wo_cc = vim_strsave(from->wo_cc); |
5807 | to->wo_diff = from->wo_diff; |
5808 | to->wo_diff_saved = from->wo_diff_saved; |
5809 | to->wo_cocu = vim_strsave(from->wo_cocu); |
5810 | to->wo_cole = from->wo_cole; |
5811 | to->wo_fdc = from->wo_fdc; |
5812 | to->wo_fdc_save = from->wo_fdc_save; |
5813 | to->wo_fen = from->wo_fen; |
5814 | to->wo_fen_save = from->wo_fen_save; |
5815 | to->wo_fdi = vim_strsave(from->wo_fdi); |
5816 | to->wo_fml = from->wo_fml; |
5817 | to->wo_fdl = from->wo_fdl; |
5818 | to->wo_fdl_save = from->wo_fdl_save; |
5819 | to->wo_fdm = vim_strsave(from->wo_fdm); |
5820 | to->wo_fdm_save = from->wo_diff_saved |
5821 | ? vim_strsave(from->wo_fdm_save) : empty_option; |
5822 | to->wo_fdn = from->wo_fdn; |
5823 | to->wo_fde = vim_strsave(from->wo_fde); |
5824 | to->wo_fdt = vim_strsave(from->wo_fdt); |
5825 | to->wo_fmr = vim_strsave(from->wo_fmr); |
5826 | to->wo_scl = vim_strsave(from->wo_scl); |
5827 | to->wo_winhl = vim_strsave(from->wo_winhl); |
5828 | to->wo_fcs = vim_strsave(from->wo_fcs); |
5829 | to->wo_lcs = vim_strsave(from->wo_lcs); |
5830 | to->wo_winbl = from->wo_winbl; |
5831 | check_winopt(to); // don't want NULL pointers |
5832 | } |
5833 | |
5834 | /* |
5835 | * Check string options in a window for a NULL value. |
5836 | */ |
5837 | void check_win_options(win_T *win) |
5838 | { |
5839 | check_winopt(&win->w_onebuf_opt); |
5840 | check_winopt(&win->w_allbuf_opt); |
5841 | } |
5842 | |
5843 | /* |
5844 | * Check for NULL pointers in a winopt_T and replace them with empty_option. |
5845 | */ |
5846 | static void check_winopt(winopt_T *wop) |
5847 | { |
5848 | check_string_option(&wop->wo_fdi); |
5849 | check_string_option(&wop->wo_fdm); |
5850 | check_string_option(&wop->wo_fdm_save); |
5851 | check_string_option(&wop->wo_fde); |
5852 | check_string_option(&wop->wo_fdt); |
5853 | check_string_option(&wop->wo_fmr); |
5854 | check_string_option(&wop->wo_scl); |
5855 | check_string_option(&wop->wo_rlc); |
5856 | check_string_option(&wop->wo_stl); |
5857 | check_string_option(&wop->wo_cc); |
5858 | check_string_option(&wop->wo_cocu); |
5859 | check_string_option(&wop->wo_briopt); |
5860 | check_string_option(&wop->wo_winhl); |
5861 | check_string_option(&wop->wo_fcs); |
5862 | check_string_option(&wop->wo_lcs); |
5863 | } |
5864 | |
5865 | /* |
5866 | * Free the allocated memory inside a winopt_T. |
5867 | */ |
5868 | void clear_winopt(winopt_T *wop) |
5869 | { |
5870 | clear_string_option(&wop->wo_fdi); |
5871 | clear_string_option(&wop->wo_fdm); |
5872 | clear_string_option(&wop->wo_fdm_save); |
5873 | clear_string_option(&wop->wo_fde); |
5874 | clear_string_option(&wop->wo_fdt); |
5875 | clear_string_option(&wop->wo_fmr); |
5876 | clear_string_option(&wop->wo_scl); |
5877 | clear_string_option(&wop->wo_rlc); |
5878 | clear_string_option(&wop->wo_stl); |
5879 | clear_string_option(&wop->wo_cc); |
5880 | clear_string_option(&wop->wo_cocu); |
5881 | clear_string_option(&wop->wo_briopt); |
5882 | clear_string_option(&wop->wo_winhl); |
5883 | clear_string_option(&wop->wo_fcs); |
5884 | clear_string_option(&wop->wo_lcs); |
5885 | } |
5886 | |
5887 | void didset_window_options(win_T *wp) |
5888 | { |
5889 | check_colorcolumn(wp); |
5890 | briopt_check(wp); |
5891 | set_chars_option(wp, &wp->w_p_fcs); |
5892 | set_chars_option(wp, &wp->w_p_lcs); |
5893 | parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl |
5894 | wp->w_grid.blending = wp->w_p_winbl > 0; |
5895 | } |
5896 | |
5897 | |
5898 | /* |
5899 | * Copy global option values to local options for one buffer. |
5900 | * Used when creating a new buffer and sometimes when entering a buffer. |
5901 | * flags: |
5902 | * BCO_ENTER We will enter the buf buffer. |
5903 | * BCO_ALWAYS Always copy the options, but only set b_p_initialized when |
5904 | * appropriate. |
5905 | * BCO_NOHELP Don't copy the values to a help buffer. |
5906 | */ |
5907 | void buf_copy_options(buf_T *buf, int flags) |
5908 | { |
5909 | int should_copy = true; |
5910 | char_u *save_p_isk = NULL; // init for GCC |
5911 | int dont_do_help; |
5912 | int did_isk = false; |
5913 | |
5914 | /* |
5915 | * Skip this when the option defaults have not been set yet. Happens when |
5916 | * main() allocates the first buffer. |
5917 | */ |
5918 | if (p_cpo != NULL) { |
5919 | // |
5920 | // Always copy when entering and 'cpo' contains 'S'. |
5921 | // Don't copy when already initialized. |
5922 | // Don't copy when 'cpo' contains 's' and not entering. |
5923 | // 'S' BCO_ENTER initialized 's' should_copy |
5924 | // yes yes X X true |
5925 | // yes no yes X false |
5926 | // no X yes X false |
5927 | // X no no yes false |
5928 | // X no no no true |
5929 | // no yes no X true |
5930 | /// |
5931 | if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER)) |
5932 | && (buf->b_p_initialized |
5933 | || (!(flags & BCO_ENTER) |
5934 | && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) { |
5935 | should_copy = false; |
5936 | } |
5937 | |
5938 | if (should_copy || (flags & BCO_ALWAYS)) { |
5939 | /* Don't copy the options specific to a help buffer when |
5940 | * BCO_NOHELP is given or the options were initialized already |
5941 | * (jumping back to a help file with CTRL-T or CTRL-O) */ |
5942 | dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) |
5943 | || buf->b_p_initialized; |
5944 | if (dont_do_help) { // don't free b_p_isk |
5945 | save_p_isk = buf->b_p_isk; |
5946 | buf->b_p_isk = NULL; |
5947 | } |
5948 | /* |
5949 | * Always free the allocated strings. |
5950 | * If not already initialized, set 'readonly' and copy 'fileformat'. |
5951 | */ |
5952 | if (!buf->b_p_initialized) { |
5953 | free_buf_options(buf, true); |
5954 | buf->b_p_ro = false; // don't copy readonly |
5955 | buf->b_p_fenc = vim_strsave(p_fenc); |
5956 | switch (*p_ffs) { |
5957 | case 'm': { |
5958 | buf->b_p_ff = vim_strsave((char_u *)FF_MAC); |
5959 | break; |
5960 | } |
5961 | case 'd': { |
5962 | buf->b_p_ff = vim_strsave((char_u *)FF_DOS); |
5963 | break; |
5964 | } |
5965 | case 'u': { |
5966 | buf->b_p_ff = vim_strsave((char_u *)FF_UNIX); |
5967 | break; |
5968 | } |
5969 | default: { |
5970 | buf->b_p_ff = vim_strsave(p_ff); |
5971 | break; |
5972 | } |
5973 | } |
5974 | buf->b_p_bh = empty_option; |
5975 | buf->b_p_bt = empty_option; |
5976 | } else { |
5977 | free_buf_options(buf, false); |
5978 | } |
5979 | |
5980 | buf->b_p_ai = p_ai; |
5981 | buf->b_p_ai_nopaste = p_ai_nopaste; |
5982 | buf->b_p_sw = p_sw; |
5983 | buf->b_p_scbk = p_scbk; |
5984 | buf->b_p_tw = p_tw; |
5985 | buf->b_p_tw_nopaste = p_tw_nopaste; |
5986 | buf->b_p_tw_nobin = p_tw_nobin; |
5987 | buf->b_p_wm = p_wm; |
5988 | buf->b_p_wm_nopaste = p_wm_nopaste; |
5989 | buf->b_p_wm_nobin = p_wm_nobin; |
5990 | buf->b_p_bin = p_bin; |
5991 | buf->b_p_bomb = p_bomb; |
5992 | buf->b_p_et = p_et; |
5993 | buf->b_p_fixeol = p_fixeol; |
5994 | buf->b_p_et_nobin = p_et_nobin; |
5995 | buf->b_p_et_nopaste = p_et_nopaste; |
5996 | buf->b_p_ml = p_ml; |
5997 | buf->b_p_ml_nobin = p_ml_nobin; |
5998 | buf->b_p_inf = p_inf; |
5999 | buf->b_p_swf = cmdmod.noswapfile ? false : p_swf; |
6000 | buf->b_p_cpt = vim_strsave(p_cpt); |
6001 | buf->b_p_cfu = vim_strsave(p_cfu); |
6002 | buf->b_p_ofu = vim_strsave(p_ofu); |
6003 | buf->b_p_sts = p_sts; |
6004 | buf->b_p_sts_nopaste = p_sts_nopaste; |
6005 | buf->b_p_com = vim_strsave(p_com); |
6006 | buf->b_p_cms = vim_strsave(p_cms); |
6007 | buf->b_p_fo = vim_strsave(p_fo); |
6008 | buf->b_p_flp = vim_strsave(p_flp); |
6009 | buf->b_p_nf = vim_strsave(p_nf); |
6010 | buf->b_p_mps = vim_strsave(p_mps); |
6011 | buf->b_p_si = p_si; |
6012 | buf->b_p_channel = 0; |
6013 | buf->b_p_ci = p_ci; |
6014 | buf->b_p_cin = p_cin; |
6015 | buf->b_p_cink = vim_strsave(p_cink); |
6016 | buf->b_p_cino = vim_strsave(p_cino); |
6017 | // Don't copy 'filetype', it must be detected |
6018 | buf->b_p_ft = empty_option; |
6019 | buf->b_p_pi = p_pi; |
6020 | buf->b_p_cinw = vim_strsave(p_cinw); |
6021 | buf->b_p_lisp = p_lisp; |
6022 | // Don't copy 'syntax', it must be set |
6023 | buf->b_p_syn = empty_option; |
6024 | buf->b_p_smc = p_smc; |
6025 | buf->b_s.b_syn_isk = empty_option; |
6026 | buf->b_s.b_p_spc = vim_strsave(p_spc); |
6027 | (void)compile_cap_prog(&buf->b_s); |
6028 | buf->b_s.b_p_spf = vim_strsave(p_spf); |
6029 | buf->b_s.b_p_spl = vim_strsave(p_spl); |
6030 | buf->b_p_inde = vim_strsave(p_inde); |
6031 | buf->b_p_indk = vim_strsave(p_indk); |
6032 | buf->b_p_fp = empty_option; |
6033 | buf->b_p_fex = vim_strsave(p_fex); |
6034 | buf->b_p_sua = vim_strsave(p_sua); |
6035 | buf->b_p_keymap = vim_strsave(p_keymap); |
6036 | buf->b_kmap_state |= KEYMAP_INIT; |
6037 | /* This isn't really an option, but copying the langmap and IME |
6038 | * state from the current buffer is better than resetting it. */ |
6039 | buf->b_p_iminsert = p_iminsert; |
6040 | buf->b_p_imsearch = p_imsearch; |
6041 | |
6042 | /* options that are normally global but also have a local value |
6043 | * are not copied, start using the global value */ |
6044 | buf->b_p_ar = -1; |
6045 | buf->b_p_ul = NO_LOCAL_UNDOLEVEL; |
6046 | buf->b_p_bkc = empty_option; |
6047 | buf->b_bkc_flags = 0; |
6048 | buf->b_p_gp = empty_option; |
6049 | buf->b_p_mp = empty_option; |
6050 | buf->b_p_efm = empty_option; |
6051 | buf->b_p_ep = empty_option; |
6052 | buf->b_p_kp = empty_option; |
6053 | buf->b_p_path = empty_option; |
6054 | buf->b_p_tags = empty_option; |
6055 | buf->b_p_tc = empty_option; |
6056 | buf->b_tc_flags = 0; |
6057 | buf->b_p_def = empty_option; |
6058 | buf->b_p_inc = empty_option; |
6059 | buf->b_p_inex = vim_strsave(p_inex); |
6060 | buf->b_p_dict = empty_option; |
6061 | buf->b_p_tsr = empty_option; |
6062 | buf->b_p_qe = vim_strsave(p_qe); |
6063 | buf->b_p_udf = p_udf; |
6064 | buf->b_p_lw = empty_option; |
6065 | buf->b_p_menc = empty_option; |
6066 | |
6067 | /* |
6068 | * Don't copy the options set by ex_help(), use the saved values, |
6069 | * when going from a help buffer to a non-help buffer. |
6070 | * Don't touch these at all when BCO_NOHELP is used and going from |
6071 | * or to a help buffer. |
6072 | */ |
6073 | if (dont_do_help) { |
6074 | buf->b_p_isk = save_p_isk; |
6075 | } else { |
6076 | buf->b_p_isk = vim_strsave(p_isk); |
6077 | did_isk = true; |
6078 | buf->b_p_ts = p_ts; |
6079 | buf->b_help = false; |
6080 | if (buf->b_p_bt[0] == 'h') { |
6081 | clear_string_option(&buf->b_p_bt); |
6082 | } |
6083 | buf->b_p_ma = p_ma; |
6084 | } |
6085 | } |
6086 | |
6087 | /* |
6088 | * When the options should be copied (ignoring BCO_ALWAYS), set the |
6089 | * flag that indicates that the options have been initialized. |
6090 | */ |
6091 | if (should_copy) { |
6092 | buf->b_p_initialized = true; |
6093 | } |
6094 | } |
6095 | |
6096 | check_buf_options(buf); // make sure we don't have NULLs |
6097 | if (did_isk) { |
6098 | (void)buf_init_chartab(buf, false); |
6099 | } |
6100 | } |
6101 | |
6102 | /* |
6103 | * Reset the 'modifiable' option and its default value. |
6104 | */ |
6105 | void reset_modifiable(void) |
6106 | { |
6107 | int opt_idx; |
6108 | |
6109 | curbuf->b_p_ma = false; |
6110 | p_ma = false; |
6111 | opt_idx = findoption("ma" ); |
6112 | if (opt_idx >= 0) { |
6113 | options[opt_idx].def_val[VI_DEFAULT] = false; |
6114 | } |
6115 | } |
6116 | |
6117 | /* |
6118 | * Set the global value for 'iminsert' to the local value. |
6119 | */ |
6120 | void set_iminsert_global(void) |
6121 | { |
6122 | p_iminsert = curbuf->b_p_iminsert; |
6123 | } |
6124 | |
6125 | /* |
6126 | * Set the global value for 'imsearch' to the local value. |
6127 | */ |
6128 | void set_imsearch_global(void) |
6129 | { |
6130 | p_imsearch = curbuf->b_p_imsearch; |
6131 | } |
6132 | |
6133 | static int expand_option_idx = -1; |
6134 | static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL}; |
6135 | static int expand_option_flags = 0; |
6136 | |
6137 | void |
6138 | set_context_in_set_cmd( |
6139 | expand_T *xp, |
6140 | char_u *arg, |
6141 | int opt_flags // OPT_GLOBAL and/or OPT_LOCAL |
6142 | ) |
6143 | { |
6144 | char_u nextchar; |
6145 | uint32_t flags = 0; // init for GCC |
6146 | int opt_idx = 0; // init for GCC |
6147 | char_u *p; |
6148 | char_u *s; |
6149 | int is_term_option = false; |
6150 | int key; |
6151 | |
6152 | expand_option_flags = opt_flags; |
6153 | |
6154 | xp->xp_context = EXPAND_SETTINGS; |
6155 | if (*arg == NUL) { |
6156 | xp->xp_pattern = arg; |
6157 | return; |
6158 | } |
6159 | p = arg + STRLEN(arg) - 1; |
6160 | if (*p == ' ' && *(p - 1) != '\\') { |
6161 | xp->xp_pattern = p + 1; |
6162 | return; |
6163 | } |
6164 | while (p > arg) { |
6165 | s = p; |
6166 | // count number of backslashes before ' ' or ',' |
6167 | if (*p == ' ' || *p == ',') { |
6168 | while (s > arg && *(s - 1) == '\\') { |
6169 | s--; |
6170 | } |
6171 | } |
6172 | // break at a space with an even number of backslashes |
6173 | if (*p == ' ' && ((p - s) & 1) == 0) { |
6174 | p++; |
6175 | break; |
6176 | } |
6177 | p--; |
6178 | } |
6179 | if (STRNCMP(p, "no" , 2) == 0) { |
6180 | xp->xp_context = EXPAND_BOOL_SETTINGS; |
6181 | p += 2; |
6182 | } |
6183 | if (STRNCMP(p, "inv" , 3) == 0) { |
6184 | xp->xp_context = EXPAND_BOOL_SETTINGS; |
6185 | p += 3; |
6186 | } |
6187 | xp->xp_pattern = arg = p; |
6188 | if (*arg == '<') { |
6189 | while (*p != '>') { |
6190 | if (*p++ == NUL) { // expand terminal option name |
6191 | return; |
6192 | } |
6193 | } |
6194 | key = get_special_key_code(arg + 1); |
6195 | if (key == 0) { // unknown name |
6196 | xp->xp_context = EXPAND_NOTHING; |
6197 | return; |
6198 | } |
6199 | nextchar = *++p; |
6200 | is_term_option = true; |
6201 | expand_option_name[2] = (char_u)KEY2TERMCAP0(key); |
6202 | expand_option_name[3] = KEY2TERMCAP1(key); |
6203 | } else { |
6204 | if (p[0] == 't' && p[1] == '_') { |
6205 | p += 2; |
6206 | if (*p != NUL) { |
6207 | p++; |
6208 | } |
6209 | if (*p == NUL) { |
6210 | return; // expand option name |
6211 | } |
6212 | nextchar = *++p; |
6213 | is_term_option = true; |
6214 | expand_option_name[2] = p[-2]; |
6215 | expand_option_name[3] = p[-1]; |
6216 | } else { |
6217 | // Allow * wildcard. |
6218 | while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*') { |
6219 | p++; |
6220 | } |
6221 | if (*p == NUL) { |
6222 | return; |
6223 | } |
6224 | nextchar = *p; |
6225 | opt_idx = findoption_len((const char *)arg, (size_t)(p - arg)); |
6226 | if (opt_idx == -1 || options[opt_idx].var == NULL) { |
6227 | xp->xp_context = EXPAND_NOTHING; |
6228 | return; |
6229 | } |
6230 | flags = options[opt_idx].flags; |
6231 | if (flags & P_BOOL) { |
6232 | xp->xp_context = EXPAND_NOTHING; |
6233 | return; |
6234 | } |
6235 | } |
6236 | } |
6237 | // handle "-=" and "+=" |
6238 | if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=') { |
6239 | p++; |
6240 | nextchar = '='; |
6241 | } |
6242 | if ((nextchar != '=' && nextchar != ':') |
6243 | || xp->xp_context == EXPAND_BOOL_SETTINGS) { |
6244 | xp->xp_context = EXPAND_UNSUCCESSFUL; |
6245 | return; |
6246 | } |
6247 | if (p[1] == NUL) { |
6248 | xp->xp_context = EXPAND_OLD_SETTING; |
6249 | if (is_term_option) { |
6250 | expand_option_idx = -1; |
6251 | } else { |
6252 | expand_option_idx = opt_idx; |
6253 | } |
6254 | xp->xp_pattern = p + 1; |
6255 | return; |
6256 | } |
6257 | xp->xp_context = EXPAND_NOTHING; |
6258 | if (is_term_option || (flags & P_NUM)) { |
6259 | return; |
6260 | } |
6261 | |
6262 | xp->xp_pattern = p + 1; |
6263 | |
6264 | if (flags & P_EXPAND) { |
6265 | p = options[opt_idx].var; |
6266 | if (p == (char_u *)&p_bdir |
6267 | || p == (char_u *)&p_dir |
6268 | || p == (char_u *)&p_path |
6269 | || p == (char_u *)&p_pp |
6270 | || p == (char_u *)&p_rtp |
6271 | || p == (char_u *)&p_cdpath |
6272 | || p == (char_u *)&p_vdir |
6273 | ) { |
6274 | xp->xp_context = EXPAND_DIRECTORIES; |
6275 | if (p == (char_u *)&p_path |
6276 | || p == (char_u *)&p_cdpath |
6277 | ) |
6278 | xp->xp_backslash = XP_BS_THREE; |
6279 | else |
6280 | xp->xp_backslash = XP_BS_ONE; |
6281 | } else { |
6282 | xp->xp_context = EXPAND_FILES; |
6283 | // for 'tags' need three backslashes for a space |
6284 | if (p == (char_u *)&p_tags) { |
6285 | xp->xp_backslash = XP_BS_THREE; |
6286 | } else { |
6287 | xp->xp_backslash = XP_BS_ONE; |
6288 | } |
6289 | } |
6290 | } |
6291 | |
6292 | /* For an option that is a list of file names, find the start of the |
6293 | * last file name. */ |
6294 | for (p = arg + STRLEN(arg) - 1; p > xp->xp_pattern; p--) { |
6295 | // count number of backslashes before ' ' or ',' |
6296 | if (*p == ' ' || *p == ',') { |
6297 | s = p; |
6298 | while (s > xp->xp_pattern && *(s - 1) == '\\') { |
6299 | s--; |
6300 | } |
6301 | if ((*p == ' ' && (xp->xp_backslash == XP_BS_THREE && (p - s) < 3)) |
6302 | || (*p == ',' && (flags & P_COMMA) && ((p - s) & 1) == 0)) { |
6303 | xp->xp_pattern = p + 1; |
6304 | break; |
6305 | } |
6306 | } |
6307 | |
6308 | // for 'spellsuggest' start at "file:" |
6309 | if (options[opt_idx].var == (char_u *)&p_sps |
6310 | && STRNCMP(p, "file:" , 5) == 0) { |
6311 | xp->xp_pattern = p + 5; |
6312 | break; |
6313 | } |
6314 | } |
6315 | |
6316 | return; |
6317 | } |
6318 | |
6319 | int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file) |
6320 | { |
6321 | int num_normal = 0; // Nr of matching non-term-code settings |
6322 | int match; |
6323 | int count = 0; |
6324 | char_u *str; |
6325 | int loop; |
6326 | static char *(names[]) = { "all" }; |
6327 | int ic = regmatch->rm_ic; // remember the ignore-case flag |
6328 | |
6329 | /* do this loop twice: |
6330 | * loop == 0: count the number of matching options |
6331 | * loop == 1: copy the matching options into allocated memory |
6332 | */ |
6333 | for (loop = 0; loop <= 1; loop++) { |
6334 | regmatch->rm_ic = ic; |
6335 | if (xp->xp_context != EXPAND_BOOL_SETTINGS) { |
6336 | for (match = 0; match < (int)ARRAY_SIZE(names); |
6337 | match++) { |
6338 | if (vim_regexec(regmatch, (char_u *)names[match], (colnr_T)0)) { |
6339 | if (loop == 0) { |
6340 | num_normal++; |
6341 | } else { |
6342 | (*file)[count++] = vim_strsave((char_u *)names[match]); |
6343 | } |
6344 | } |
6345 | } |
6346 | } |
6347 | for (size_t opt_idx = 0; (str = (char_u *)options[opt_idx].fullname) != NULL; |
6348 | opt_idx++) { |
6349 | if (options[opt_idx].var == NULL) { |
6350 | continue; |
6351 | } |
6352 | if (xp->xp_context == EXPAND_BOOL_SETTINGS |
6353 | && !(options[opt_idx].flags & P_BOOL)) { |
6354 | continue; |
6355 | } |
6356 | match = false; |
6357 | if (vim_regexec(regmatch, str, (colnr_T)0) |
6358 | || (options[opt_idx].shortname != NULL |
6359 | && vim_regexec(regmatch, |
6360 | (char_u *)options[opt_idx].shortname, |
6361 | (colnr_T)0))) { |
6362 | match = true; |
6363 | } |
6364 | |
6365 | if (match) { |
6366 | if (loop == 0) { |
6367 | num_normal++; |
6368 | } else |
6369 | (*file)[count++] = vim_strsave(str); |
6370 | } |
6371 | } |
6372 | |
6373 | if (loop == 0) { |
6374 | if (num_normal > 0) { |
6375 | *num_file = num_normal; |
6376 | } else { |
6377 | return OK; |
6378 | } |
6379 | *file = (char_u **)xmalloc((size_t)(*num_file) * sizeof(char_u *)); |
6380 | } |
6381 | } |
6382 | return OK; |
6383 | } |
6384 | |
6385 | void ExpandOldSetting(int *num_file, char_u ***file) |
6386 | { |
6387 | char_u *var = NULL; |
6388 | |
6389 | *num_file = 0; |
6390 | *file = (char_u **)xmalloc(sizeof(char_u *)); |
6391 | |
6392 | /* |
6393 | * For a terminal key code expand_option_idx is < 0. |
6394 | */ |
6395 | if (expand_option_idx < 0) { |
6396 | expand_option_idx = findoption((const char *)expand_option_name); |
6397 | } |
6398 | |
6399 | if (expand_option_idx >= 0) { |
6400 | // Put string of option value in NameBuff. |
6401 | option_value2string(&options[expand_option_idx], expand_option_flags); |
6402 | var = NameBuff; |
6403 | } else { |
6404 | var = (char_u *)"" ; |
6405 | } |
6406 | |
6407 | // A backslash is required before some characters. This is the reverse of |
6408 | // what happens in do_set(). |
6409 | char_u *buf = vim_strsave_escaped(var, escape_chars); |
6410 | |
6411 | #ifdef BACKSLASH_IN_FILENAME |
6412 | /* For MS-Windows et al. we don't double backslashes at the start and |
6413 | * before a file name character. */ |
6414 | for (var = buf; *var != NUL; MB_PTR_ADV(var)) { |
6415 | if (var[0] == '\\' && var[1] == '\\' |
6416 | && expand_option_idx >= 0 |
6417 | && (options[expand_option_idx].flags & P_EXPAND) |
6418 | && vim_isfilec(var[2]) |
6419 | && (var[2] != '\\' || (var == buf && var[4] != '\\'))) { |
6420 | STRMOVE(var, var + 1); |
6421 | } |
6422 | } |
6423 | #endif |
6424 | |
6425 | *file[0] = buf; |
6426 | *num_file = 1; |
6427 | } |
6428 | |
6429 | /* |
6430 | * Get the value for the numeric or string option *opp in a nice format into |
6431 | * NameBuff[]. Must not be called with a hidden option! |
6432 | */ |
6433 | static void |
6434 | option_value2string( |
6435 | vimoption_T *opp, |
6436 | int opt_flags // OPT_GLOBAL and/or OPT_LOCAL |
6437 | ) |
6438 | { |
6439 | char_u *varp; |
6440 | |
6441 | varp = get_varp_scope(opp, opt_flags); |
6442 | |
6443 | if (opp->flags & P_NUM) { |
6444 | long wc = 0; |
6445 | |
6446 | if (wc_use_keyname(varp, &wc)) { |
6447 | STRLCPY(NameBuff, get_special_key_name((int)wc, 0), sizeof(NameBuff)); |
6448 | } else if (wc != 0) { |
6449 | STRLCPY(NameBuff, transchar((int)wc), sizeof(NameBuff)); |
6450 | } else { |
6451 | snprintf((char *)NameBuff, |
6452 | sizeof(NameBuff), |
6453 | "%" PRId64, |
6454 | (int64_t)*(long *)varp); |
6455 | } |
6456 | } else { // P_STRING |
6457 | varp = *(char_u **)(varp); |
6458 | if (varp == NULL) { // Just in case. |
6459 | NameBuff[0] = NUL; |
6460 | } else if (opp->flags & P_EXPAND) { |
6461 | home_replace(NULL, varp, NameBuff, MAXPATHL, false); |
6462 | // Translate 'pastetoggle' into special key names. |
6463 | } else if ((char_u **)opp->var == &p_pt) { |
6464 | str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL); |
6465 | } else { |
6466 | STRLCPY(NameBuff, varp, MAXPATHL); |
6467 | } |
6468 | } |
6469 | } |
6470 | |
6471 | /// Return true if "varp" points to 'wildchar' or 'wildcharm' and it can be |
6472 | /// printed as a keyname. |
6473 | /// "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'. |
6474 | static int wc_use_keyname(char_u *varp, long *wcp) |
6475 | { |
6476 | if (((long *)varp == &p_wc) || ((long *)varp == &p_wcm)) { |
6477 | *wcp = *(long *)varp; |
6478 | if (IS_SPECIAL(*wcp) || find_special_key_in_table((int)(*wcp)) >= 0) { |
6479 | return true; |
6480 | } |
6481 | } |
6482 | return false; |
6483 | } |
6484 | |
6485 | /* |
6486 | * Any character has an equivalent 'langmap' character. This is used for |
6487 | * keyboards that have a special language mode that sends characters above |
6488 | * 128 (although other characters can be translated too). The "to" field is a |
6489 | * Vim command character. This avoids having to switch the keyboard back to |
6490 | * ASCII mode when leaving Insert mode. |
6491 | * |
6492 | * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim |
6493 | * commands. |
6494 | * langmap_mapga.ga_data is a sorted table of langmap_entry_T. |
6495 | * This does the same as langmap_mapchar[] for characters >= 256. |
6496 | */ |
6497 | /* |
6498 | * With multi-byte support use growarray for 'langmap' chars >= 256 |
6499 | */ |
6500 | typedef struct { |
6501 | int from; |
6502 | int to; |
6503 | } langmap_entry_T; |
6504 | |
6505 | static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE; |
6506 | |
6507 | /* |
6508 | * Search for an entry in "langmap_mapga" for "from". If found set the "to" |
6509 | * field. If not found insert a new entry at the appropriate location. |
6510 | */ |
6511 | static void langmap_set_entry(int from, int to) |
6512 | { |
6513 | langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); |
6514 | unsigned int a = 0; |
6515 | assert(langmap_mapga.ga_len >= 0); |
6516 | unsigned int b = (unsigned int)langmap_mapga.ga_len; |
6517 | |
6518 | // Do a binary search for an existing entry. |
6519 | while (a != b) { |
6520 | unsigned int i = (a + b) / 2; |
6521 | int d = entries[i].from - from; |
6522 | |
6523 | if (d == 0) { |
6524 | entries[i].to = to; |
6525 | return; |
6526 | } |
6527 | if (d < 0) { |
6528 | a = i + 1; |
6529 | } else { |
6530 | b = i; |
6531 | } |
6532 | } |
6533 | |
6534 | ga_grow(&langmap_mapga, 1); |
6535 | |
6536 | // insert new entry at position "a" |
6537 | entries = (langmap_entry_T *)(langmap_mapga.ga_data) + a; |
6538 | memmove(entries + 1, entries, |
6539 | ((unsigned int)langmap_mapga.ga_len - a) * sizeof(langmap_entry_T)); |
6540 | langmap_mapga.ga_len++; |
6541 | entries[0].from = from; |
6542 | entries[0].to = to; |
6543 | } |
6544 | |
6545 | /* |
6546 | * Apply 'langmap' to multi-byte character "c" and return the result. |
6547 | */ |
6548 | int langmap_adjust_mb(int c) |
6549 | { |
6550 | langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); |
6551 | int a = 0; |
6552 | int b = langmap_mapga.ga_len; |
6553 | |
6554 | while (a != b) { |
6555 | int i = (a + b) / 2; |
6556 | int d = entries[i].from - c; |
6557 | |
6558 | if (d == 0) { |
6559 | return entries[i].to; // found matching entry |
6560 | } |
6561 | if (d < 0) { |
6562 | a = i + 1; |
6563 | } else { |
6564 | b = i; |
6565 | } |
6566 | } |
6567 | return c; // no entry found, return "c" unmodified |
6568 | } |
6569 | |
6570 | static void langmap_init(void) |
6571 | { |
6572 | for (int i = 0; i < 256; i++) { |
6573 | langmap_mapchar[i] = (char_u)i; // we init with a one-to-one map |
6574 | } |
6575 | ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8); |
6576 | } |
6577 | |
6578 | /* |
6579 | * Called when langmap option is set; the language map can be |
6580 | * changed at any time! |
6581 | */ |
6582 | static void langmap_set(void) |
6583 | { |
6584 | char_u *p; |
6585 | char_u *p2; |
6586 | int from, to; |
6587 | |
6588 | ga_clear(&langmap_mapga); // clear the previous map first |
6589 | langmap_init(); // back to one-to-one map |
6590 | |
6591 | for (p = p_langmap; p[0] != NUL; ) { |
6592 | for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';'; |
6593 | MB_PTR_ADV(p2)) { |
6594 | if (p2[0] == '\\' && p2[1] != NUL) { |
6595 | p2++; |
6596 | } |
6597 | } |
6598 | if (p2[0] == ';') { |
6599 | p2++; // abcd;ABCD form, p2 points to A |
6600 | } else { |
6601 | p2 = NULL; // aAbBcCdD form, p2 is NULL |
6602 | } |
6603 | while (p[0]) { |
6604 | if (p[0] == ',') { |
6605 | p++; |
6606 | break; |
6607 | } |
6608 | if (p[0] == '\\' && p[1] != NUL) { |
6609 | p++; |
6610 | } |
6611 | from = utf_ptr2char(p); |
6612 | to = NUL; |
6613 | if (p2 == NULL) { |
6614 | MB_PTR_ADV(p); |
6615 | if (p[0] != ',') { |
6616 | if (p[0] == '\\') { |
6617 | p++; |
6618 | } |
6619 | to = utf_ptr2char(p); |
6620 | } |
6621 | } else { |
6622 | if (p2[0] != ',') { |
6623 | if (p2[0] == '\\') { |
6624 | p2++; |
6625 | } |
6626 | to = utf_ptr2char(p2); |
6627 | } |
6628 | } |
6629 | if (to == NUL) { |
6630 | EMSG2(_("E357: 'langmap': Matching character missing for %s" ), |
6631 | transchar(from)); |
6632 | return; |
6633 | } |
6634 | |
6635 | if (from >= 256) { |
6636 | langmap_set_entry(from, to); |
6637 | } else { |
6638 | assert(to <= UCHAR_MAX); |
6639 | langmap_mapchar[from & 255] = (char_u)to; |
6640 | } |
6641 | |
6642 | // Advance to next pair |
6643 | MB_PTR_ADV(p); |
6644 | if (p2 != NULL) { |
6645 | MB_PTR_ADV(p2); |
6646 | if (*p == ';') { |
6647 | p = p2; |
6648 | if (p[0] != NUL) { |
6649 | if (p[0] != ',') { |
6650 | EMSG2(_( |
6651 | "E358: 'langmap': Extra characters after semicolon: %s" ), |
6652 | p); |
6653 | return; |
6654 | } |
6655 | p++; |
6656 | } |
6657 | break; |
6658 | } |
6659 | } |
6660 | } |
6661 | } |
6662 | } |
6663 | |
6664 | /// Return true if format option 'x' is in effect. |
6665 | /// Take care of no formatting when 'paste' is set. |
6666 | int has_format_option(int x) |
6667 | { |
6668 | if (p_paste) { |
6669 | return false; |
6670 | } |
6671 | return vim_strchr(curbuf->b_p_fo, x) != NULL; |
6672 | } |
6673 | |
6674 | /// @returns true if "x" is present in 'shortmess' option, or |
6675 | /// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS. |
6676 | bool shortmess(int x) |
6677 | { |
6678 | return (p_shm != NULL |
6679 | && (vim_strchr(p_shm, x) != NULL |
6680 | || (vim_strchr(p_shm, 'a') != NULL |
6681 | && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL))); |
6682 | } |
6683 | |
6684 | /* |
6685 | * paste_option_changed() - Called after p_paste was set or reset. |
6686 | */ |
6687 | static void paste_option_changed(void) |
6688 | { |
6689 | static int old_p_paste = false; |
6690 | static int save_sm = 0; |
6691 | static int save_sta = 0; |
6692 | static int save_ru = 0; |
6693 | static int save_ri = 0; |
6694 | static int save_hkmap = 0; |
6695 | |
6696 | if (p_paste) { |
6697 | /* |
6698 | * Paste switched from off to on. |
6699 | * Save the current values, so they can be restored later. |
6700 | */ |
6701 | if (!old_p_paste) { |
6702 | // save options for each buffer |
6703 | FOR_ALL_BUFFERS(buf) { |
6704 | buf->b_p_tw_nopaste = buf->b_p_tw; |
6705 | buf->b_p_wm_nopaste = buf->b_p_wm; |
6706 | buf->b_p_sts_nopaste = buf->b_p_sts; |
6707 | buf->b_p_ai_nopaste = buf->b_p_ai; |
6708 | buf->b_p_et_nopaste = buf->b_p_et; |
6709 | } |
6710 | |
6711 | // save global options |
6712 | save_sm = p_sm; |
6713 | save_sta = p_sta; |
6714 | save_ru = p_ru; |
6715 | save_ri = p_ri; |
6716 | save_hkmap = p_hkmap; |
6717 | // save global values for local buffer options |
6718 | p_ai_nopaste = p_ai; |
6719 | p_et_nopaste = p_et; |
6720 | p_sts_nopaste = p_sts; |
6721 | p_tw_nopaste = p_tw; |
6722 | p_wm_nopaste = p_wm; |
6723 | } |
6724 | |
6725 | // Always set the option values, also when 'paste' is set when it is |
6726 | // already on. |
6727 | // set options for each buffer |
6728 | FOR_ALL_BUFFERS(buf) { |
6729 | buf->b_p_tw = 0; // textwidth is 0 |
6730 | buf->b_p_wm = 0; // wrapmargin is 0 |
6731 | buf->b_p_sts = 0; // softtabstop is 0 |
6732 | buf->b_p_ai = 0; // no auto-indent |
6733 | buf->b_p_et = 0; // no expandtab |
6734 | } |
6735 | |
6736 | // set global options |
6737 | p_sm = 0; // no showmatch |
6738 | p_sta = 0; // no smarttab |
6739 | if (p_ru) { |
6740 | status_redraw_all(); // redraw to remove the ruler |
6741 | } |
6742 | p_ru = 0; // no ruler |
6743 | p_ri = 0; // no reverse insert |
6744 | p_hkmap = 0; // no Hebrew keyboard |
6745 | // set global values for local buffer options |
6746 | p_tw = 0; |
6747 | p_wm = 0; |
6748 | p_sts = 0; |
6749 | p_ai = 0; |
6750 | } else if (old_p_paste) { |
6751 | // Paste switched from on to off: Restore saved values. |
6752 | |
6753 | // restore options for each buffer |
6754 | FOR_ALL_BUFFERS(buf) { |
6755 | buf->b_p_tw = buf->b_p_tw_nopaste; |
6756 | buf->b_p_wm = buf->b_p_wm_nopaste; |
6757 | buf->b_p_sts = buf->b_p_sts_nopaste; |
6758 | buf->b_p_ai = buf->b_p_ai_nopaste; |
6759 | buf->b_p_et = buf->b_p_et_nopaste; |
6760 | } |
6761 | |
6762 | // restore global options |
6763 | p_sm = save_sm; |
6764 | p_sta = save_sta; |
6765 | if (p_ru != save_ru) { |
6766 | status_redraw_all(); // redraw to draw the ruler |
6767 | } |
6768 | p_ru = save_ru; |
6769 | p_ri = save_ri; |
6770 | p_hkmap = save_hkmap; |
6771 | // set global values for local buffer options |
6772 | p_ai = p_ai_nopaste; |
6773 | p_et = p_et_nopaste; |
6774 | p_sts = p_sts_nopaste; |
6775 | p_tw = p_tw_nopaste; |
6776 | p_wm = p_wm_nopaste; |
6777 | } |
6778 | |
6779 | old_p_paste = p_paste; |
6780 | } |
6781 | |
6782 | /// vimrc_found() - Called when a vimrc or "VIMINIT" has been found. |
6783 | /// |
6784 | /// Set the values for options that didn't get set yet to the Vim defaults. |
6785 | /// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet. |
6786 | void vimrc_found(char_u *fname, char_u *envname) |
6787 | { |
6788 | if (fname != NULL && envname != NULL) { |
6789 | char *p = vim_getenv((char *)envname); |
6790 | if (p == NULL) { |
6791 | // Set $MYVIMRC to the first vimrc file found. |
6792 | p = FullName_save((char *)fname, false); |
6793 | if (p != NULL) { |
6794 | os_setenv((char *)envname, p, 1); |
6795 | xfree(p); |
6796 | } |
6797 | } else { |
6798 | xfree(p); |
6799 | } |
6800 | } |
6801 | } |
6802 | |
6803 | /// Check whether global option has been set |
6804 | /// |
6805 | /// @param[in] name Option name. |
6806 | /// |
6807 | /// @return True if it was set. |
6808 | bool option_was_set(const char *name) |
6809 | { |
6810 | int idx; |
6811 | |
6812 | idx = findoption(name); |
6813 | if (idx < 0) { // Unknown option. |
6814 | return false; |
6815 | } else if (options[idx].flags & P_WAS_SET) { |
6816 | return true; |
6817 | } |
6818 | return false; |
6819 | } |
6820 | |
6821 | /// Reset the flag indicating option "name" was set. |
6822 | /// |
6823 | /// @param[in] name Option name. |
6824 | void reset_option_was_set(const char *name) |
6825 | { |
6826 | const int idx = findoption(name); |
6827 | |
6828 | if (idx >= 0) { |
6829 | options[idx].flags &= ~P_WAS_SET; |
6830 | } |
6831 | } |
6832 | |
6833 | /* |
6834 | * fill_breakat_flags() -- called when 'breakat' changes value. |
6835 | */ |
6836 | static void fill_breakat_flags(void) |
6837 | { |
6838 | char_u *p; |
6839 | int i; |
6840 | |
6841 | for (i = 0; i < 256; i++) { |
6842 | breakat_flags[i] = false; |
6843 | } |
6844 | |
6845 | if (p_breakat != NULL) { |
6846 | for (p = p_breakat; *p; p++) { |
6847 | breakat_flags[*p] = true; |
6848 | } |
6849 | } |
6850 | } |
6851 | |
6852 | /* |
6853 | * Check an option that can be a range of string values. |
6854 | * |
6855 | * Return OK for correct value, FAIL otherwise. |
6856 | * Empty is always OK. |
6857 | */ |
6858 | static int check_opt_strings( |
6859 | char_u *val, |
6860 | char **values, |
6861 | int list // when true: accept a list of values |
6862 | ) |
6863 | { |
6864 | return opt_strings_flags(val, values, NULL, list); |
6865 | } |
6866 | |
6867 | /* |
6868 | * Handle an option that can be a range of string values. |
6869 | * Set a flag in "*flagp" for each string present. |
6870 | * |
6871 | * Return OK for correct value, FAIL otherwise. |
6872 | * Empty is always OK. |
6873 | */ |
6874 | static int opt_strings_flags( |
6875 | char_u *val, // new value |
6876 | char **values, // array of valid string values |
6877 | unsigned *flagp, |
6878 | bool list // when true: accept a list of values |
6879 | ) |
6880 | { |
6881 | unsigned int new_flags = 0; |
6882 | |
6883 | while (*val) { |
6884 | for (unsigned int i = 0;; i++) { |
6885 | if (values[i] == NULL) { // val not found in values[] |
6886 | return FAIL; |
6887 | } |
6888 | |
6889 | size_t len = STRLEN(values[i]); |
6890 | if (STRNCMP(values[i], val, len) == 0 |
6891 | && ((list && val[len] == ',') || val[len] == NUL)) { |
6892 | val += len + (val[len] == ','); |
6893 | assert(i < sizeof(1U) * 8); |
6894 | new_flags |= (1U << i); |
6895 | break; // check next item in val list |
6896 | } |
6897 | } |
6898 | } |
6899 | if (flagp != NULL) { |
6900 | *flagp = new_flags; |
6901 | } |
6902 | |
6903 | return OK; |
6904 | } |
6905 | |
6906 | /* |
6907 | * Read the 'wildmode' option, fill wim_flags[]. |
6908 | */ |
6909 | static int check_opt_wim(void) |
6910 | { |
6911 | char_u new_wim_flags[4]; |
6912 | char_u *p; |
6913 | int i; |
6914 | int idx = 0; |
6915 | |
6916 | for (i = 0; i < 4; i++) { |
6917 | new_wim_flags[i] = 0; |
6918 | } |
6919 | |
6920 | for (p = p_wim; *p; p++) { |
6921 | for (i = 0; ASCII_ISALPHA(p[i]); i++) {} |
6922 | if (p[i] != NUL && p[i] != ',' && p[i] != ':') { |
6923 | return FAIL; |
6924 | } |
6925 | if (i == 7 && STRNCMP(p, "longest" , 7) == 0) { |
6926 | new_wim_flags[idx] |= WIM_LONGEST; |
6927 | } else if (i == 4 && STRNCMP(p, "full" , 4) == 0) { |
6928 | new_wim_flags[idx] |= WIM_FULL; |
6929 | } else if (i == 4 && STRNCMP(p, "list" , 4) == 0) { |
6930 | new_wim_flags[idx] |= WIM_LIST; |
6931 | } else { |
6932 | return FAIL; |
6933 | } |
6934 | p += i; |
6935 | if (*p == NUL) { |
6936 | break; |
6937 | } |
6938 | if (*p == ',') { |
6939 | if (idx == 3) { |
6940 | return FAIL; |
6941 | } |
6942 | idx++; |
6943 | } |
6944 | } |
6945 | |
6946 | // fill remaining entries with last flag |
6947 | while (idx < 3) { |
6948 | new_wim_flags[idx + 1] = new_wim_flags[idx]; |
6949 | idx++; |
6950 | } |
6951 | |
6952 | // only when there are no errors, wim_flags[] is changed |
6953 | for (i = 0; i < 4; i++) { |
6954 | wim_flags[i] = new_wim_flags[i]; |
6955 | } |
6956 | return OK; |
6957 | } |
6958 | |
6959 | /* |
6960 | * Check if backspacing over something is allowed. |
6961 | * The parameter what is one of the following: whatBS_INDENT, BS_EOL |
6962 | * or BS_START |
6963 | */ |
6964 | bool can_bs(int what) |
6965 | { |
6966 | switch (*p_bs) { |
6967 | case '2': return true; |
6968 | case '1': return what != BS_START; |
6969 | case '0': return false; |
6970 | } |
6971 | return vim_strchr(p_bs, what) != NULL; |
6972 | } |
6973 | |
6974 | /* |
6975 | * Save the current values of 'fileformat' and 'fileencoding', so that we know |
6976 | * the file must be considered changed when the value is different. |
6977 | */ |
6978 | void save_file_ff(buf_T *buf) |
6979 | { |
6980 | buf->b_start_ffc = *buf->b_p_ff; |
6981 | buf->b_start_eol = buf->b_p_eol; |
6982 | buf->b_start_bomb = buf->b_p_bomb; |
6983 | |
6984 | // Only use free/alloc when necessary, they take time. |
6985 | if (buf->b_start_fenc == NULL |
6986 | || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) { |
6987 | xfree(buf->b_start_fenc); |
6988 | buf->b_start_fenc = vim_strsave(buf->b_p_fenc); |
6989 | } |
6990 | } |
6991 | |
6992 | /// Return true if 'fileformat' and/or 'fileencoding' has a different value |
6993 | /// from when editing started (save_file_ff() called). |
6994 | /// Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was |
6995 | /// changed and 'binary' is not set. |
6996 | /// Also when 'endofline' was changed and 'fixeol' is not set. |
6997 | /// When "ignore_empty" is true don't consider a new, empty buffer to be |
6998 | /// changed. |
6999 | bool file_ff_differs(buf_T *buf, bool ignore_empty) |
7000 | FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT |
7001 | { |
7002 | // In a buffer that was never loaded the options are not valid. |
7003 | if (buf->b_flags & BF_NEVERLOADED) { |
7004 | return false; |
7005 | } |
7006 | if (ignore_empty |
7007 | && (buf->b_flags & BF_NEW) |
7008 | && buf->b_ml.ml_line_count == 1 |
7009 | && *ml_get_buf(buf, (linenr_T)1, false) == NUL) { |
7010 | return false; |
7011 | } |
7012 | if (buf->b_start_ffc != *buf->b_p_ff) { |
7013 | return true; |
7014 | } |
7015 | if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol) { |
7016 | return true; |
7017 | } |
7018 | if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) { |
7019 | return true; |
7020 | } |
7021 | if (buf->b_start_fenc == NULL) { |
7022 | return *buf->b_p_fenc != NUL; |
7023 | } |
7024 | return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0; |
7025 | } |
7026 | |
7027 | /* |
7028 | * return OK if "p" is a valid fileformat name, FAIL otherwise. |
7029 | */ |
7030 | int check_ff_value(char_u *p) |
7031 | { |
7032 | return check_opt_strings(p, p_ff_values, false); |
7033 | } |
7034 | |
7035 | /* |
7036 | * Return the effective shiftwidth value for current buffer, using the |
7037 | * 'tabstop' value when 'shiftwidth' is zero. |
7038 | */ |
7039 | int get_sw_value(buf_T *buf) |
7040 | { |
7041 | long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts; |
7042 | assert(result >= 0 && result <= INT_MAX); |
7043 | return (int)result; |
7044 | } |
7045 | |
7046 | // Return the effective softtabstop value for the current buffer, |
7047 | // using the effective shiftwidth value when 'softtabstop' is negative. |
7048 | int get_sts_value(void) |
7049 | { |
7050 | long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts; |
7051 | assert(result >= 0 && result <= INT_MAX); |
7052 | return (int)result; |
7053 | } |
7054 | |
7055 | /* |
7056 | * Check matchpairs option for "*initc". |
7057 | * If there is a match set "*initc" to the matching character and "*findc" to |
7058 | * the opposite character. Set "*backwards" to the direction. |
7059 | * When "switchit" is true swap the direction. |
7060 | */ |
7061 | void find_mps_values(int *initc, int *findc, int *backwards, int switchit) |
7062 | { |
7063 | char_u *ptr = curbuf->b_p_mps; |
7064 | |
7065 | while (*ptr != NUL) { |
7066 | if (utf_ptr2char(ptr) == *initc) { |
7067 | if (switchit) { |
7068 | *findc = *initc; |
7069 | *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); |
7070 | *backwards = true; |
7071 | } else { |
7072 | *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); |
7073 | *backwards = false; |
7074 | } |
7075 | return; |
7076 | } |
7077 | char_u *prev = ptr; |
7078 | ptr += utfc_ptr2len(ptr) + 1; |
7079 | if (utf_ptr2char(ptr) == *initc) { |
7080 | if (switchit) { |
7081 | *findc = *initc; |
7082 | *initc = utf_ptr2char(prev); |
7083 | *backwards = false; |
7084 | } else { |
7085 | *findc = utf_ptr2char(prev); |
7086 | *backwards = true; |
7087 | } |
7088 | return; |
7089 | } |
7090 | ptr += utfc_ptr2len(ptr); |
7091 | if (*ptr == ',') { |
7092 | ptr++; |
7093 | } |
7094 | } |
7095 | } |
7096 | |
7097 | /// This is called when 'breakindentopt' is changed and when a window is |
7098 | /// initialized |
7099 | static bool briopt_check(win_T *wp) |
7100 | { |
7101 | int bri_shift = 0; |
7102 | int bri_min = 20; |
7103 | bool bri_sbr = false; |
7104 | |
7105 | char_u *p = wp->w_p_briopt; |
7106 | while (*p != NUL) |
7107 | { |
7108 | if (STRNCMP(p, "shift:" , 6) == 0 |
7109 | && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) |
7110 | { |
7111 | p += 6; |
7112 | bri_shift = getdigits_int(&p, true, 0); |
7113 | } |
7114 | else if (STRNCMP(p, "min:" , 4) == 0 && ascii_isdigit(p[4])) |
7115 | { |
7116 | p += 4; |
7117 | bri_min = getdigits_int(&p, true, 0); |
7118 | } |
7119 | else if (STRNCMP(p, "sbr" , 3) == 0) |
7120 | { |
7121 | p += 3; |
7122 | bri_sbr = true; |
7123 | } |
7124 | if (*p != ',' && *p != NUL) { |
7125 | return false; |
7126 | } |
7127 | if (*p == ',') { |
7128 | p++; |
7129 | } |
7130 | } |
7131 | |
7132 | wp->w_p_brishift = bri_shift; |
7133 | wp->w_p_brimin = bri_min; |
7134 | wp->w_p_brisbr = bri_sbr; |
7135 | |
7136 | return true; |
7137 | } |
7138 | |
7139 | /// Get the local or global value of 'backupcopy'. |
7140 | /// |
7141 | /// @param buf The buffer. |
7142 | unsigned int get_bkc_value(buf_T *buf) |
7143 | { |
7144 | return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; |
7145 | } |
7146 | |
7147 | /// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. |
7148 | int get_fileformat(buf_T *buf) |
7149 | { |
7150 | int c = *buf->b_p_ff; |
7151 | |
7152 | if (buf->b_p_bin || c == 'u') { |
7153 | return EOL_UNIX; |
7154 | } |
7155 | if (c == 'm') { |
7156 | return EOL_MAC; |
7157 | } |
7158 | return EOL_DOS; |
7159 | } |
7160 | |
7161 | /// Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val" |
7162 | /// argument. |
7163 | /// |
7164 | /// @param eap can be NULL! |
7165 | int get_fileformat_force(buf_T *buf, exarg_T *eap) |
7166 | { |
7167 | int c; |
7168 | |
7169 | if (eap != NULL && eap->force_ff != 0) { |
7170 | c = eap->cmd[eap->force_ff]; |
7171 | } else { |
7172 | if ((eap != NULL && eap->force_bin != 0) |
7173 | ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { |
7174 | return EOL_UNIX; |
7175 | } |
7176 | c = *buf->b_p_ff; |
7177 | } |
7178 | if (c == 'u') { |
7179 | return EOL_UNIX; |
7180 | } |
7181 | if (c == 'm') { |
7182 | return EOL_MAC; |
7183 | } |
7184 | return EOL_DOS; |
7185 | } |
7186 | |
7187 | /// Return the default fileformat from 'fileformats'. |
7188 | int default_fileformat(void) |
7189 | { |
7190 | switch (*p_ffs) { |
7191 | case 'm': return EOL_MAC; |
7192 | case 'd': return EOL_DOS; |
7193 | } |
7194 | return EOL_UNIX; |
7195 | } |
7196 | |
7197 | /// Set the current end-of-line type to EOL_UNIX, EOL_MAC, or EOL_DOS. |
7198 | /// |
7199 | /// Sets 'fileformat'. |
7200 | /// |
7201 | /// @param eol_style End-of-line style. |
7202 | /// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL |
7203 | void set_fileformat(int eol_style, int opt_flags) |
7204 | { |
7205 | char *p = NULL; |
7206 | |
7207 | switch (eol_style) { |
7208 | case EOL_UNIX: |
7209 | p = FF_UNIX; |
7210 | break; |
7211 | case EOL_MAC: |
7212 | p = FF_MAC; |
7213 | break; |
7214 | case EOL_DOS: |
7215 | p = FF_DOS; |
7216 | break; |
7217 | } |
7218 | |
7219 | // p is NULL if "eol_style" is EOL_UNKNOWN. |
7220 | if (p != NULL) { |
7221 | set_string_option_direct((char_u *)"ff" , |
7222 | -1, |
7223 | (char_u *)p, |
7224 | OPT_FREE | opt_flags, |
7225 | 0); |
7226 | } |
7227 | |
7228 | // This may cause the buffer to become (un)modified. |
7229 | check_status(curbuf); |
7230 | redraw_tabline = true; |
7231 | need_maketitle = true; // Set window title later. |
7232 | } |
7233 | |
7234 | /// Skip to next part of an option argument: skip space and comma |
7235 | char_u *skip_to_option_part(const char_u *p) |
7236 | { |
7237 | if (*p == ',') { |
7238 | p++; |
7239 | } |
7240 | while (*p == ' ') { |
7241 | p++; |
7242 | } |
7243 | return (char_u *)p; |
7244 | } |
7245 | |
7246 | /// Isolate one part of a string option separated by `sep_chars`. |
7247 | /// |
7248 | /// @param[in,out] option advanced to the next part |
7249 | /// @param[in,out] buf copy of the isolated part |
7250 | /// @param[in] maxlen length of `buf` |
7251 | /// @param[in] sep_chars chars that separate the option parts |
7252 | /// |
7253 | /// @return length of `*option` |
7254 | size_t copy_option_part(char_u **option, char_u *buf, size_t maxlen, |
7255 | char *sep_chars) |
7256 | { |
7257 | size_t len = 0; |
7258 | char_u *p = *option; |
7259 | |
7260 | // skip '.' at start of option part, for 'suffixes' |
7261 | if (*p == '.') { |
7262 | buf[len++] = *p++; |
7263 | } |
7264 | while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL) { |
7265 | // Skip backslash before a separator character and space. |
7266 | if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL) { |
7267 | p++; |
7268 | } |
7269 | if (len < maxlen - 1) { |
7270 | buf[len++] = *p; |
7271 | } |
7272 | p++; |
7273 | } |
7274 | buf[len] = NUL; |
7275 | |
7276 | if (*p != NUL && *p != ',') { // skip non-standard separator |
7277 | p++; |
7278 | } |
7279 | p = skip_to_option_part(p); // p points to next file name |
7280 | |
7281 | *option = p; |
7282 | return len; |
7283 | } |
7284 | |
7285 | /// Return true when 'shell' has "csh" in the tail. |
7286 | int csh_like_shell(void) |
7287 | { |
7288 | return strstr((char *)path_tail(p_sh), "csh" ) != NULL; |
7289 | } |
7290 | |
7291 | /// Return the number of requested sign columns, based on current |
7292 | /// buffer signs and on user configuration. |
7293 | int win_signcol_count(win_T *wp) |
7294 | { |
7295 | int maximum = 1, needed_signcols; |
7296 | const char *scl = (const char *)wp->w_p_scl; |
7297 | |
7298 | if (*scl == 'n') { |
7299 | return 0; |
7300 | } |
7301 | needed_signcols = buf_signcols(wp->w_buffer); |
7302 | |
7303 | // yes or yes |
7304 | if (!strncmp(scl, "yes:" , 4)) { |
7305 | // Fixed amount of columns |
7306 | return scl[4] - '0'; |
7307 | } |
7308 | if (*scl == 'y') { |
7309 | return 1; |
7310 | } |
7311 | |
7312 | // auto or auto:<NUM> |
7313 | if (!strncmp(scl, "auto:" , 5)) { |
7314 | // Variable depending on a configuration |
7315 | maximum = scl[5] - '0'; |
7316 | } |
7317 | |
7318 | return MIN(maximum, needed_signcols); |
7319 | } |
7320 | |
7321 | /// Get window or buffer local options |
7322 | dict_T *get_winbuf_options(const int bufopt) |
7323 | FUNC_ATTR_WARN_UNUSED_RESULT |
7324 | { |
7325 | dict_T *const d = tv_dict_alloc(); |
7326 | |
7327 | for (int opt_idx = 0; options[opt_idx].fullname; opt_idx++) { |
7328 | struct vimoption *opt = &options[opt_idx]; |
7329 | |
7330 | if ((bufopt && (opt->indir & PV_BUF)) |
7331 | || (!bufopt && (opt->indir & PV_WIN))) { |
7332 | char_u *varp = get_varp(opt); |
7333 | |
7334 | if (varp != NULL) { |
7335 | if (opt->flags & P_STRING) { |
7336 | tv_dict_add_str(d, opt->fullname, strlen(opt->fullname), |
7337 | *(const char **)varp); |
7338 | } else if (opt->flags & P_NUM) { |
7339 | tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), |
7340 | *(long *)varp); |
7341 | } else { |
7342 | tv_dict_add_nr(d, opt->fullname, strlen(opt->fullname), *(int *)varp); |
7343 | } |
7344 | } |
7345 | } |
7346 | } |
7347 | |
7348 | return d; |
7349 | } |
7350 | |