option.c (196442B)
1 // User-settable options. Checklist for adding a new option: 2 // - Put it in options.lua 3 // - For a global option: Add a variable for it in option_vars.h. 4 // - For a buffer or window local option: 5 // - Add a variable to the window or buffer struct in buffer_defs.h. 6 // - For a window option, add some code to copy_winopt(). 7 // - For a window string option, add code to check_winopt() 8 // and clear_winopt(). If setting the option needs parsing, 9 // add some code to didset_window_options(). 10 // - For a buffer option, add some code to buf_copy_options(). 11 // - For a buffer string option, add code to check_buf_options(). 12 // - If it's a numeric option, add any necessary bounds checks to check_num_option_bounds(). 13 // - If it's a list of flags, add some code in do_set(), search for WW_ALL. 14 // - Add documentation! "desc" in options.lua, and any other related places. 15 // - Add an entry in runtime/scripts/optwin.lua. 16 17 #define IN_OPTION_C 18 #include <assert.h> 19 #include <inttypes.h> 20 #include <limits.h> 21 #include <stdbool.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <uv.h> 26 27 #include "auto/config.h" 28 #include "klib/kvec.h" 29 #include "nvim/api/extmark.h" 30 #include "nvim/api/private/defs.h" 31 #include "nvim/api/private/helpers.h" 32 #include "nvim/api/private/validate.h" 33 #include "nvim/ascii_defs.h" 34 #include "nvim/assert_defs.h" 35 #include "nvim/autocmd.h" 36 #include "nvim/autocmd_defs.h" 37 #include "nvim/buffer.h" 38 #include "nvim/buffer_defs.h" 39 #include "nvim/change.h" 40 #include "nvim/charset.h" 41 #include "nvim/cmdexpand.h" 42 #include "nvim/cmdexpand_defs.h" 43 #include "nvim/cursor_shape.h" 44 #include "nvim/decoration_defs.h" 45 #include "nvim/decoration_provider.h" 46 #include "nvim/diff.h" 47 #include "nvim/drawscreen.h" 48 #include "nvim/errors.h" 49 #include "nvim/eval.h" 50 #include "nvim/eval/typval.h" 51 #include "nvim/eval/typval_defs.h" 52 #include "nvim/eval/vars.h" 53 #include "nvim/eval/window.h" 54 #include "nvim/ex_cmds_defs.h" 55 #include "nvim/ex_docmd.h" 56 #include "nvim/ex_getln.h" 57 #include "nvim/ex_session.h" 58 #include "nvim/fold.h" 59 #include "nvim/fuzzy.h" 60 #include "nvim/garray.h" 61 #include "nvim/garray_defs.h" 62 #include "nvim/gettext_defs.h" 63 #include "nvim/globals.h" 64 #include "nvim/grid_defs.h" 65 #include "nvim/highlight.h" 66 #include "nvim/highlight_defs.h" 67 #include "nvim/highlight_group.h" 68 #include "nvim/indent.h" 69 #include "nvim/indent_c.h" 70 #include "nvim/insexpand.h" 71 #include "nvim/keycodes.h" 72 #include "nvim/log.h" 73 #include "nvim/lua/executor.h" 74 #include "nvim/macros_defs.h" 75 #include "nvim/mapping.h" 76 #include "nvim/math.h" 77 #include "nvim/mbyte.h" 78 #include "nvim/memfile.h" 79 #include "nvim/memline.h" 80 #include "nvim/memory.h" 81 #include "nvim/memory_defs.h" 82 #include "nvim/message.h" 83 #include "nvim/mouse.h" 84 #include "nvim/move.h" 85 #include "nvim/normal.h" 86 #include "nvim/ops.h" 87 #include "nvim/option.h" 88 #include "nvim/option_defs.h" 89 #include "nvim/option_vars.h" 90 #include "nvim/optionstr.h" 91 #include "nvim/os/input.h" 92 #include "nvim/os/lang.h" 93 #include "nvim/os/os.h" 94 #include "nvim/os/os_defs.h" 95 #include "nvim/path.h" 96 #include "nvim/popupmenu.h" 97 #include "nvim/pos_defs.h" 98 #include "nvim/regexp.h" 99 #include "nvim/regexp_defs.h" 100 #include "nvim/runtime.h" 101 #include "nvim/spell.h" 102 #include "nvim/spellfile.h" 103 #include "nvim/spellsuggest.h" 104 #include "nvim/state_defs.h" 105 #include "nvim/strings.h" 106 #include "nvim/tag.h" 107 #include "nvim/terminal.h" 108 #include "nvim/types_defs.h" 109 #include "nvim/ui.h" 110 #include "nvim/undo.h" 111 #include "nvim/undo_defs.h" 112 #include "nvim/vim_defs.h" 113 #include "nvim/window.h" 114 #include "nvim/winfloat.h" 115 116 #ifdef BACKSLASH_IN_FILENAME 117 # include "nvim/arglist.h" 118 #endif 119 120 static const char e_unknown_option[] 121 = N_("E518: Unknown option"); 122 static const char e_not_allowed_in_modeline[] 123 = N_("E520: Not allowed in a modeline"); 124 static const char e_not_allowed_in_modeline_when_modelineexpr_is_off[] 125 = N_("E992: Not allowed in a modeline when 'modelineexpr' is off"); 126 static const char e_number_required_after_equal[] 127 = N_("E521: Number required after ="); 128 static const char e_preview_window_already_exists[] 129 = N_("E590: A preview window already exists"); 130 static const char e_cannot_have_negative_or_zero_number_of_quickfix[] 131 = N_("E1542: Cannot have a negative or zero number of quickfix/location lists"); 132 static const char e_cannot_have_more_than_hundred_quickfix[] 133 = N_("E1543: Cannot have more than a hundred quickfix/location lists"); 134 135 static char *p_term = NULL; 136 static char *p_ttytype = NULL; 137 138 // Saved values for when 'bin' is set. 139 static int p_et_nobin; 140 static int p_ml_nobin; 141 static OptInt p_tw_nobin; 142 static OptInt p_wm_nobin; 143 144 // Saved values for when 'paste' is set. 145 static int p_ai_nopaste; 146 static int p_et_nopaste; 147 static OptInt p_sts_nopaste; 148 static OptInt p_tw_nopaste; 149 static OptInt p_wm_nopaste; 150 static char *p_vsts_nopaste; 151 152 #define OPTION_COUNT ARRAY_SIZE(options) 153 154 /// :set boolean option prefix 155 typedef enum { 156 PREFIX_NO = 0, ///< "no" prefix 157 PREFIX_NONE, ///< no prefix 158 PREFIX_INV, ///< "inv" prefix 159 } set_prefix_T; 160 161 #include "option.c.generated.h" 162 163 // options[] is initialized in options.generated.h. 164 // The options with a NULL variable are 'hidden': a set command for them is 165 // ignored and they are not printed. 166 167 #include "options.generated.h" 168 #include "options_map.generated.h" 169 170 static int p_bin_dep_opts[] = { 171 kOptTextwidth, kOptWrapmargin, kOptModeline, kOptExpandtab, kOptInvalid 172 }; 173 174 static int p_paste_dep_opts[] = { 175 kOptAutoindent, kOptExpandtab, kOptRuler, kOptShowmatch, kOptSmarttab, kOptSofttabstop, 176 kOptTextwidth, kOptWrapmargin, kOptRevins, kOptVarsofttabstop, kOptInvalid 177 }; 178 179 void set_init_tablocal(void) 180 { 181 // susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal! 182 p_ch = options[kOptCmdheight].def_val.data.number; 183 } 184 185 /// Initialize the 'shell' option to a default value. 186 static void set_init_default_shell(void) 187 { 188 // Find default value for 'shell' option. 189 // Don't use it if it is empty. 190 char *shell = os_getenv("SHELL"); 191 if (shell != NULL) { 192 if (vim_strchr(shell, ' ') != NULL) { 193 const size_t len = strlen(shell) + 3; // two quotes and a trailing NUL 194 char *const cmd = xmalloc(len); 195 snprintf(cmd, len, "\"%s\"", shell); 196 set_string_default(kOptShell, cmd, true); 197 } else { 198 set_string_default(kOptShell, shell, false); 199 } 200 xfree(shell); 201 } 202 } 203 204 /// Set the default for 'backupskip' to include environment variables for 205 /// temp files. 206 static void set_init_default_backupskip(void) 207 { 208 #ifdef UNIX 209 static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" }; 210 #else 211 static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" }; 212 #endif 213 garray_T ga; 214 OptIndex opt_idx = kOptBackupskip; 215 216 ga_init(&ga, 1, 100); 217 for (size_t i = 0; i < ARRAY_SIZE(names); i++) { 218 bool mustfree = true; 219 char *p; 220 size_t plen; 221 #ifdef UNIX 222 if (*names[i] == NUL) { 223 # ifdef __APPLE__ 224 p = "/private/tmp"; 225 plen = STRLEN_LITERAL("/private/tmp"); 226 # else 227 p = "/tmp"; 228 plen = STRLEN_LITERAL("/tmp"); 229 # endif 230 mustfree = false; 231 } else 232 #endif 233 { 234 p = vim_getenv(names[i]); 235 plen = 0; // will be calculated below 236 } 237 if (p != NULL && *p != NUL) { 238 bool has_trailing_path_sep = false; 239 240 if (plen == 0) { 241 // the value was retrieved from the environment 242 plen = strlen(p); 243 // does the value include a trailing path separator? 244 if (after_pathsep(p, p + plen)) { 245 has_trailing_path_sep = true; 246 } 247 } 248 249 // item size needs to be large enough to include "/*" and a trailing NUL 250 // note: the value (and therefore plen) may already include a path separator 251 size_t itemsize = plen + (has_trailing_path_sep ? 0 : 1) + 2; 252 char *item = xmalloc(itemsize); 253 // add a preceding comma as a separator after the first item 254 size_t itemseplen = (ga.ga_len == 0) ? 0 : 1; 255 256 size_t itemlen = (size_t)vim_snprintf(item, itemsize, "%s%s*", p, 257 has_trailing_path_sep ? "" : PATHSEPSTR); 258 259 if (find_dup_item(ga.ga_data, item, itemlen, options[opt_idx].flags) == NULL) { 260 ga_grow(&ga, (int)(itemseplen + itemlen + 1)); 261 ga.ga_len += vim_snprintf((char *)ga.ga_data + ga.ga_len, 262 itemseplen + itemlen + 1, 263 "%s%s", (itemseplen > 0) ? "," : "", item); 264 } 265 xfree(item); 266 } 267 if (mustfree) { 268 xfree(p); 269 } 270 } 271 if (ga.ga_data != NULL) { 272 set_string_default(kOptBackupskip, ga.ga_data, true); 273 } 274 } 275 276 /// Initialize the 'cdpath' option to a default value. 277 static void set_init_default_cdpath(void) 278 { 279 char *cdpath = vim_getenv("CDPATH"); 280 if (cdpath == NULL) { 281 return; 282 } 283 284 char *buf = xmalloc(2 * strlen(cdpath) + 2); 285 buf[0] = ','; // start with ",", current dir first 286 int j = 1; 287 for (int i = 0; cdpath[i] != NUL; i++) { 288 if (vim_ispathlistsep(cdpath[i])) { 289 buf[j++] = ','; 290 } else { 291 if (cdpath[i] == ' ' || cdpath[i] == ',') { 292 buf[j++] = '\\'; 293 } 294 buf[j++] = cdpath[i]; 295 } 296 } 297 buf[j] = NUL; 298 change_option_default(kOptCdpath, CSTR_AS_OPTVAL(buf)); 299 300 xfree(cdpath); 301 } 302 303 /// Expand environment variables and things like "~" for the defaults. 304 /// If option_expand() returns non-NULL the variable is expanded. This can 305 /// only happen for non-indirect options. 306 /// Also set the default to the expanded value, so ":set" does not list 307 /// them. 308 static void set_init_expand_env(void) 309 { 310 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 311 vimoption_T *opt = &options[opt_idx]; 312 if (opt->flags & kOptFlagNoDefExp) { 313 continue; 314 } 315 char *p; 316 if ((opt->flags & kOptFlagGettext) && opt->var != NULL) { 317 p = _(*(char **)opt->var); 318 } else { 319 p = option_expand(opt_idx, NULL); 320 } 321 if (p != NULL) { 322 set_option_varp(opt_idx, opt->var, CSTR_TO_OPTVAL(p), true); 323 change_option_default(opt_idx, CSTR_TO_OPTVAL(p)); 324 } 325 } 326 } 327 328 /// Initialize the encoding used for "default" in 'fileencodings'. 329 static void set_init_fenc_default(void) 330 { 331 // enc_locale() will try to find the encoding of the current locale. 332 // This will be used when "default" is used as encoding specifier 333 // in 'fileencodings'. 334 char *p = enc_locale(); 335 if (p == NULL) { 336 // Use utf-8 as "default" if locale encoding can't be detected. 337 p = xmemdupz(S_LEN("utf-8")); 338 } 339 fenc_default = p; 340 } 341 342 /// Initialize the options, first part. 343 /// 344 /// Called only once from main(), just after creating the first buffer. 345 /// If "clean_arg" is true, Nvim was started with --clean. 346 /// 347 /// NOTE: ELOG() etc calls are not allowed here, as log location depends on 348 /// env var expansion which depends on expression evaluation and other 349 /// editor state initialized here. Do logging in set_init_2 or later. 350 void set_init_1(bool clean_arg) 351 { 352 langmap_init(); 353 354 // Allocate the default option values. 355 alloc_options_default(); 356 357 set_init_default_shell(); 358 set_init_default_backupskip(); 359 set_init_default_cdpath(); 360 361 char *backupdir = stdpaths_user_state_subpath("backup", 2, true); 362 const size_t backupdir_len = strlen(backupdir); 363 backupdir = xrealloc(backupdir, backupdir_len + 3); 364 memmove(backupdir + 2, backupdir, backupdir_len + 1); 365 memmove(backupdir, ".,", 2); 366 set_string_default(kOptBackupdir, backupdir, true); 367 set_string_default(kOptViewdir, stdpaths_user_state_subpath("view", 2, true), 368 true); 369 set_string_default(kOptDirectory, stdpaths_user_state_subpath("swap", 2, true), 370 true); 371 set_string_default(kOptUndodir, stdpaths_user_state_subpath("undo", 2, true), 372 true); 373 // Set default for &runtimepath. All necessary expansions are performed in 374 // this function. 375 char *rtp = runtimepath_default(clean_arg); 376 if (rtp) { 377 set_string_default(kOptRuntimepath, rtp, true); 378 // Make a copy of 'rtp' for 'packpath' 379 set_string_default(kOptPackpath, rtp, false); 380 rtp = NULL; // ownership taken 381 } 382 383 // Set all the options (except the terminal options) to their default 384 // value. Also set the global value for local options. 385 set_options_default(0); 386 387 curbuf->b_p_initialized = true; 388 curbuf->b_p_ac = -1; 389 curbuf->b_p_ar = -1; // no local 'autoread' value 390 curbuf->b_p_fs = -1; // no local 'fsync' value 391 curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL; 392 check_buf_options(curbuf); 393 check_win_options(curwin); 394 check_options(); 395 396 // set 'laststatus' 397 last_status(false); 398 399 // Must be before option_expand(), because that one needs vim_isIDc() 400 didset_options(); 401 402 // Use the current chartab for the generic chartab. This is not in 403 // didset_options() because it only depends on 'encoding'. 404 init_spell_chartab(); 405 406 // Expand environment variables and things like "~" for the defaults. 407 set_init_expand_env(); 408 409 save_file_ff(curbuf); // Buffer is unchanged 410 411 // Detect use of mlterm. 412 // Mlterm is a terminal emulator akin to xterm that has some special 413 // abilities (bidi namely). 414 // NOTE: mlterm's author is being asked to 'set' a variable 415 // instead of an environment variable due to inheritance. 416 if (os_env_exists("MLTERM", false)) { 417 set_option_value_give_err(kOptTermbidi, BOOLEAN_OPTVAL(true), 0); 418 } 419 420 didset_options2(); 421 422 lang_init(); 423 set_init_fenc_default(); 424 425 #ifdef HAVE_WORKING_LIBINTL 426 // GNU gettext 0.10.37 supports this feature: set the codeset used for 427 // translated messages independently from the current locale. 428 (void)bind_textdomain_codeset(PROJECT_NAME, p_enc); 429 #endif 430 431 // Set the default for 'helplang'. 432 set_helplang_default(get_mess_lang()); 433 } 434 435 /// Get default value for option, based on the option's type and scope. 436 /// 437 /// @param opt_idx Option index in options[] table. 438 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 439 /// 440 /// @return Default value of option for the scope specified in opt_flags. 441 OptVal get_option_default(const OptIndex opt_idx, int opt_flags) 442 { 443 vimoption_T *opt = &options[opt_idx]; 444 bool is_global_local_option = option_is_global_local(opt_idx); 445 446 #ifdef UNIX 447 if (opt_idx == kOptModeline && getuid() == ROOT_UID) { 448 // 'modeline' defaults to off for root. 449 return BOOLEAN_OPTVAL(false); 450 } 451 #endif 452 453 if ((opt_flags & OPT_LOCAL) && is_global_local_option) { 454 // Use unset local value instead of default value for local scope of global-local options. 455 return get_option_unset_value(opt_idx); 456 } else if (option_has_type(opt_idx, kOptValTypeString) && !(opt->flags & kOptFlagNoDefExp)) { 457 // For string options, expand environment variables and ~ since the default value was already 458 // expanded, only required when an environment variable was set later. 459 char *s = option_expand(opt_idx, opt->def_val.data.string.data); 460 return s == NULL ? opt->def_val : CSTR_AS_OPTVAL(s); 461 } else { 462 return opt->def_val; 463 } 464 } 465 466 /// Allocate the default values for all options by copying them from the stack. 467 /// This ensures that we don't need to always check if the option default is allocated or not. 468 static void alloc_options_default(void) 469 { 470 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 471 options[opt_idx].def_val = optval_copy(options[opt_idx].def_val); 472 } 473 } 474 475 /// Change the default value for an option. 476 /// 477 /// @param opt_idx Option index in options[] table. 478 /// @param value New default value. Must be allocated. 479 static void change_option_default(const OptIndex opt_idx, OptVal value) 480 { 481 optval_free(options[opt_idx].def_val); 482 options[opt_idx].def_val = value; 483 } 484 485 /// Set an option to its default value. 486 /// This does not take care of side effects! 487 /// 488 /// @param opt_idx Option index in options[] table. 489 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 490 static void set_option_default(const OptIndex opt_idx, int opt_flags) 491 { 492 bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; 493 OptVal def_val = get_option_default(opt_idx, opt_flags); 494 set_option_direct(opt_idx, def_val, opt_flags, current_sctx.sc_sid); 495 496 if (opt_idx == kOptScroll) { 497 win_comp_scroll(curwin); 498 } 499 500 // The default value is not insecure. 501 uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); 502 *flagsp = *flagsp & ~(unsigned)kOptFlagInsecure; 503 if (both) { 504 flagsp = insecure_flag(curwin, opt_idx, OPT_LOCAL); 505 *flagsp = *flagsp & ~(unsigned)kOptFlagInsecure; 506 } 507 } 508 509 /// Set all options (except terminal options) to their default value. 510 /// 511 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 512 static void set_options_default(int opt_flags) 513 { 514 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 515 if (!(options[opt_idx].flags & kOptFlagNoDefault)) { 516 set_option_default(opt_idx, opt_flags); 517 } 518 } 519 520 // The 'scroll' option must be computed for all windows. 521 FOR_ALL_TAB_WINDOWS(tp, wp) { 522 win_comp_scroll(wp); 523 } 524 525 parse_cino(curbuf); 526 } 527 528 /// Set the Vi-default value of a string option. 529 /// Used for 'sh', 'backupskip' and 'term'. 530 /// 531 /// @param opt_idx Option index in options[] table. 532 /// @param val The value of the option. 533 /// @param allocated If true, do not copy default as it was already allocated. 534 /// 535 /// TODO(famiu): Remove this. 536 static void set_string_default(OptIndex opt_idx, char *val, bool allocated) 537 FUNC_ATTR_NONNULL_ALL 538 { 539 assert(opt_idx != kOptInvalid); 540 change_option_default(opt_idx, CSTR_AS_OPTVAL(allocated ? val : xstrdup(val))); 541 } 542 543 /// For an option value that contains comma separated items, find "newval" in 544 /// "origval". Return NULL if not found. 545 static const char *find_dup_item(const char *origval, const char *newval, const size_t newvallen, 546 uint32_t flags) 547 FUNC_ATTR_NONNULL_ARG(2) 548 { 549 if (origval == NULL) { 550 return NULL; 551 } 552 553 int bs = 0; 554 555 for (const char *s = origval; *s != NUL; s++) { 556 if ((!(flags & kOptFlagComma) || s == origval || (s[-1] == ',' && !(bs & 1))) 557 && strncmp(s, newval, newvallen) == 0 558 && (!(flags & kOptFlagComma) || s[newvallen] == ',' || s[newvallen] == NUL)) { 559 return s; 560 } 561 // Count backslashes. Only a comma with an even number of backslashes 562 // or a single backslash preceded by a comma before it is recognized as 563 // a separator. 564 if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',') 565 || (s == origval + 1 && s[-1] == '\\')) { 566 bs++; 567 } else { 568 bs = 0; 569 } 570 } 571 return NULL; 572 } 573 574 #if defined(EXITFREE) 575 /// Free all options. 576 void free_all_options(void) 577 { 578 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 579 bool hidden = is_option_hidden(opt_idx); 580 581 if (option_is_global_only(opt_idx) || hidden) { 582 // global option: free value and default value. 583 // hidden option: free default value only. 584 if (!hidden) { 585 optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); 586 } 587 } else if (!option_is_window_local(opt_idx)) { 588 // buffer-local option: free global value. 589 optval_free(optval_from_varp(opt_idx, options[opt_idx].var)); 590 } 591 optval_free(options[opt_idx].def_val); 592 } 593 free_operatorfunc_option(); 594 free_tagfunc_option(); 595 free_findfunc_option(); 596 XFREE_CLEAR(fenc_default); 597 XFREE_CLEAR(p_term); 598 XFREE_CLEAR(p_ttytype); 599 } 600 #endif 601 602 /// Initialize the options, part two: After getting Rows and Columns. 603 void set_init_2(bool headless) 604 { 605 // set in set_init_1 but logging is not allowed there 606 ILOG("startup runtimepath/packpath value: %s", p_rtp); 607 608 // 'scroll' defaults to half the window height. The stored default is zero, 609 // which results in the actual value computed from the window height. 610 if (!(options[kOptScroll].flags & kOptFlagWasSet)) { 611 set_option_default(kOptScroll, OPT_LOCAL); 612 } 613 comp_col(); 614 615 // 'window' is only for backwards compatibility with Vi. 616 // Default is Rows - 1. 617 if (!option_was_set(kOptWindow)) { 618 p_window = Rows - 1; 619 } 620 change_option_default(kOptWindow, NUMBER_OPTVAL(Rows - 1)); 621 } 622 623 /// Initialize the options, part three: After reading the .vimrc 624 void set_init_3(void) 625 { 626 parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor' 627 628 // Set 'shellpipe' and 'shellredir', depending on the 'shell' option. 629 // This is done after other initializations, where 'shell' might have been 630 // set, but only if they have not been set before. 631 bool do_srr = !(options[kOptShellredir].flags & kOptFlagWasSet); 632 bool do_sp = !(options[kOptShellpipe].flags & kOptFlagWasSet); 633 634 size_t len = 0; 635 char *p = (char *)invocation_path_tail(p_sh, &len); 636 p = xmemdupz(p, len); 637 638 bool is_csh = path_fnamecmp(p, "csh") == 0 || path_fnamecmp(p, "tcsh") == 0; 639 bool is_known_shell = path_fnamecmp(p, "sh") == 0 || path_fnamecmp(p, "ksh") == 0 640 || path_fnamecmp(p, "mksh") == 0 || path_fnamecmp(p, "pdksh") == 0 641 || path_fnamecmp(p, "zsh") == 0 || path_fnamecmp(p, "zsh-beta") == 0 642 || path_fnamecmp(p, "bash") == 0 || path_fnamecmp(p, "fish") == 0 643 || path_fnamecmp(p, "ash") == 0 || path_fnamecmp(p, "dash") == 0; 644 645 // Default for p_sp is "| tee", for p_srr is ">". 646 // For known shells it is changed here to include stderr. 647 if (is_csh || is_known_shell) { 648 if (do_sp) { 649 const OptVal sp = 650 is_csh ? STATIC_CSTR_AS_OPTVAL("|& tee") : STATIC_CSTR_AS_OPTVAL("2>&1| tee"); 651 set_option_direct(kOptShellpipe, sp, 0, SID_NONE); 652 change_option_default(kOptShellpipe, optval_copy(sp)); 653 } 654 if (do_srr) { 655 const OptVal srr = is_csh ? STATIC_CSTR_AS_OPTVAL(">&") : STATIC_CSTR_AS_OPTVAL(">%s 2>&1"); 656 set_option_direct(kOptShellredir, srr, 0, SID_NONE); 657 change_option_default(kOptShellredir, optval_copy(srr)); 658 } 659 } 660 xfree(p); 661 662 if (buf_is_empty(curbuf)) { 663 // Apply the first entry of 'fileformats' to the initial buffer. 664 if (options[kOptFileformats].flags & kOptFlagWasSet) { 665 set_fileformat(default_fileformat(), OPT_LOCAL); 666 } 667 } 668 669 set_title_defaults(); // 'title', 'icon' 670 } 671 672 /// When 'helplang' is still at its default value, set it to "lang". 673 /// Only the first two characters of "lang" are used. 674 void set_helplang_default(const char *lang) 675 { 676 if (lang == NULL) { 677 return; 678 } 679 680 const size_t lang_len = strlen(lang); 681 if (lang_len < 2) { // safety check 682 return; 683 } 684 if (options[kOptHelplang].flags & kOptFlagWasSet) { 685 return; 686 } 687 688 free_string_option(p_hlg); 689 p_hlg = xmemdupz(lang, lang_len); 690 // zh_CN becomes "cn", zh_TW becomes "tw". 691 if (STRNICMP(p_hlg, "zh_", 3) == 0 && lang_len >= 5) { 692 p_hlg[0] = (char)TOLOWER_ASC(p_hlg[3]); 693 p_hlg[1] = (char)TOLOWER_ASC(p_hlg[4]); 694 } else if (lang_len && *p_hlg == 'C') { 695 // any C like setting, such as C.UTF-8, becomes "en" 696 p_hlg[0] = 'e'; 697 p_hlg[1] = 'n'; 698 } 699 p_hlg[2] = NUL; 700 } 701 702 /// 'title' and 'icon' only default to true if they have not been set or reset 703 /// in .vimrc and we can read the old value. 704 /// When 'title' and 'icon' have been reset in .vimrc, we won't even check if 705 /// they can be reset. This reduces startup time when using X on a remote 706 /// machine. 707 void set_title_defaults(void) 708 { 709 // If GUI is (going to be) used, we can always set the window title and 710 // icon name. Saves a bit of time, because the X11 display server does 711 // not need to be contacted. 712 if (!(options[kOptTitle].flags & kOptFlagWasSet)) { 713 change_option_default(kOptTitle, BOOLEAN_OPTVAL(false)); 714 p_title = 0; 715 } 716 if (!(options[kOptIcon].flags & kOptFlagWasSet)) { 717 change_option_default(kOptIcon, BOOLEAN_OPTVAL(false)); 718 p_icon = 0; 719 } 720 } 721 722 void ex_set(exarg_T *eap) 723 { 724 int flags = 0; 725 726 if (eap->cmdidx == CMD_setlocal) { 727 flags = OPT_LOCAL; 728 } else if (eap->cmdidx == CMD_setglobal) { 729 flags = OPT_GLOBAL; 730 } 731 if (eap->forceit) { 732 flags |= OPT_ONECOLUMN; 733 } 734 do_set(eap->arg, flags); 735 } 736 737 /// Copy the new string value into allocated memory for the option. 738 /// Can't use set_option_direct(), because we need to remove the backslashes. 739 static char *stropt_copy_value(const char *origval, char **argp, set_op_T op, 740 uint32_t flags FUNC_ATTR_UNUSED) 741 { 742 char *arg = *argp; 743 744 // get a bit too much 745 size_t newlen = strlen(arg) + 1; 746 if (op != OP_NONE) { 747 newlen += strlen(origval) + 1; 748 } 749 char *newval = xmalloc(newlen); 750 char *s = newval; 751 752 // Copy the string, skip over escaped chars. 753 // For MS-Windows backslashes before normal file name characters 754 // are not removed, and keep backslash at start, for "\\machine\path", 755 // but do remove it for "\\\\machine\\path". 756 // The reverse is found in escape_option_str_cmdline(). 757 while (*arg != NUL && !ascii_iswhite(*arg)) { 758 if (*arg == '\\' && arg[1] != NUL 759 #ifdef BACKSLASH_IN_FILENAME 760 && !((flags & kOptFlagExpand) 761 && vim_isfilec((uint8_t)arg[1]) 762 && !ascii_iswhite(arg[1]) 763 && (arg[1] != '\\' 764 || (s == newval && arg[2] != '\\'))) 765 #endif 766 ) { 767 arg++; // remove backslash 768 } 769 int i = utfc_ptr2len(arg); 770 if (i > 1) { 771 // copy multibyte char 772 memmove(s, arg, (size_t)i); 773 arg += i; 774 s += i; 775 } else { 776 *s++ = *arg++; 777 } 778 } 779 *s = NUL; 780 781 *argp = arg; 782 return newval; 783 } 784 785 /// Expand environment variables and ~ in string option value 'newval'. 786 static char *stropt_expand_envvar(OptIndex opt_idx, const char *origval, char *newval, set_op_T op) 787 { 788 char *s = option_expand(opt_idx, newval); 789 if (s == NULL) { 790 return newval; 791 } 792 793 xfree(newval); 794 uint32_t newlen = (unsigned)strlen(s) + 1; 795 if (op != OP_NONE) { 796 newlen += (unsigned)strlen(origval) + 1; 797 } 798 newval = xmalloc(newlen); 799 STRCPY(newval, s); 800 801 return newval; 802 } 803 804 /// Concatenate the original and new values of a string option, adding a "," if 805 /// needed. 806 static void stropt_concat_with_comma(const char *origval, char *newval, set_op_T op, uint32_t flags) 807 { 808 int len = 0; 809 int comma = ((flags & kOptFlagComma) && *origval != NUL && *newval != NUL); 810 if (op == OP_ADDING) { 811 len = (int)strlen(origval); 812 // Strip a trailing comma, would get 2. 813 if (comma && len > 1 814 && (flags & kOptFlagOneComma) == kOptFlagOneComma 815 && origval[len - 1] == ',' 816 && origval[len - 2] != '\\') { 817 len--; 818 } 819 memmove(newval + len + comma, newval, strlen(newval) + 1); 820 memmove(newval, origval, (size_t)len); 821 } else { 822 len = (int)strlen(newval); 823 STRMOVE(newval + len + comma, origval); 824 } 825 if (comma) { 826 newval[len] = ','; 827 } 828 } 829 830 /// Remove a value from a string option. Copy string option value in "origval" 831 /// to "newval" and then remove the string "strval" of length "len". 832 static void stropt_remove_val(const char *origval, char *newval, uint32_t flags, const char *strval, 833 int len) 834 { 835 // Remove newval[] from origval[]. (Note: "len" has been set above 836 // and is used here). 837 STRCPY(newval, origval); 838 if (*strval) { 839 // may need to remove a comma 840 if (flags & kOptFlagComma) { 841 if (strval == origval) { 842 // include comma after string 843 if (strval[len] == ',') { 844 len++; 845 } 846 } else { 847 // include comma before string 848 strval--; 849 len++; 850 } 851 } 852 STRMOVE(newval + (strval - origval), strval + len); 853 } 854 } 855 856 /// Remove flags that appear twice in the string option value 'newval'. 857 static void stropt_remove_dupflags(char *newval, uint32_t flags) 858 { 859 char *s = newval; 860 // Remove flags that appear twice. 861 for (s = newval; *s;) { 862 // if options have kOptFlagFlagList and kOptFlagOneComma such as 'whichwrap' 863 if (flags & kOptFlagOneComma) { 864 if (*s != ',' && *(s + 1) == ',' 865 && vim_strchr(s + 2, (uint8_t)(*s)) != NULL) { 866 // Remove the duplicated value and the next comma. 867 STRMOVE(s, s + 2); 868 continue; 869 } 870 } else { 871 if ((!(flags & kOptFlagComma) || *s != ',') 872 && vim_strchr(s + 1, (uint8_t)(*s)) != NULL) { 873 STRMOVE(s, s + 1); 874 continue; 875 } 876 } 877 s++; 878 } 879 } 880 881 /// Get the string value specified for a ":set" command. The following set options are supported: 882 /// set {opt}={val} 883 /// set {opt}:{val} 884 static char *stropt_get_newval(int nextchar, OptIndex opt_idx, char **argp, void *varp, 885 const char *origval, set_op_T *op_arg, uint32_t flags) 886 { 887 char *arg = *argp; 888 set_op_T op = *op_arg; 889 char *save_arg = NULL; 890 char *newval; 891 const char *s = NULL; 892 893 arg++; // jump to after the '=' or ':' 894 895 // Set 'keywordprg' to ":help" if an empty 896 // value was passed to :set by the user. 897 if (varp == &p_kp && (*arg == NUL || *arg == ' ')) { 898 save_arg = arg; 899 arg = ":help"; 900 } 901 902 // Copy the new string into allocated memory. 903 newval = stropt_copy_value(origval, &arg, op, flags); 904 905 // Expand environment variables and ~. 906 // Don't do it when adding without inserting a comma. 907 if (op == OP_NONE || (flags & kOptFlagComma)) { 908 newval = stropt_expand_envvar(opt_idx, origval, newval, op); 909 } 910 911 // locate newval[] in origval[] when removing it 912 // and when adding to avoid duplicates 913 int len = 0; 914 if (op == OP_REMOVING || (flags & kOptFlagNoDup)) { 915 len = (int)strlen(newval); 916 s = find_dup_item(origval, newval, (size_t)len, flags); 917 918 // do not add if already there 919 if ((op == OP_ADDING || op == OP_PREPENDING) && s != NULL) { 920 op = OP_NONE; 921 STRCPY(newval, origval); 922 } 923 924 // if no duplicate, move pointer to end of original value 925 if (s == NULL) { 926 s = origval + (int)strlen(origval); 927 } 928 } 929 930 // concatenate the two strings; add a ',' if needed 931 if (op == OP_ADDING || op == OP_PREPENDING) { 932 stropt_concat_with_comma(origval, newval, op, flags); 933 } else if (op == OP_REMOVING) { 934 // Remove newval[] from origval[]. (Note: "len" has been set above 935 // and is used here). 936 stropt_remove_val(origval, newval, flags, s, len); 937 } 938 939 if (flags & kOptFlagFlagList) { 940 // Remove flags that appear twice. 941 stropt_remove_dupflags(newval, flags); 942 } 943 944 if (save_arg != NULL) { 945 arg = save_arg; // arg was temporarily changed, restore it 946 } 947 *argp = arg; 948 *op_arg = op; 949 950 return newval; 951 } 952 953 static set_op_T get_op(const char *arg) 954 { 955 set_op_T op = OP_NONE; 956 if (*arg != NUL && *(arg + 1) == '=') { 957 if (*arg == '+') { 958 op = OP_ADDING; // "+=" 959 } else if (*arg == '^') { 960 op = OP_PREPENDING; // "^=" 961 } else if (*arg == '-') { 962 op = OP_REMOVING; // "-=" 963 } 964 } 965 return op; 966 } 967 968 static set_prefix_T get_option_prefix(char **argp) 969 { 970 if (strncmp(*argp, "no", 2) == 0) { 971 *argp += 2; 972 return PREFIX_NO; 973 } else if (strncmp(*argp, "inv", 3) == 0) { 974 *argp += 3; 975 return PREFIX_INV; 976 } 977 978 return PREFIX_NONE; 979 } 980 981 static int validate_opt_idx(win_T *win, OptIndex opt_idx, int opt_flags, uint32_t flags, 982 set_prefix_T prefix, const char **errmsg) 983 { 984 // Only bools can have a prefix of 'inv' or 'no' 985 if (!option_has_type(opt_idx, kOptValTypeBoolean) && prefix != PREFIX_NONE) { 986 *errmsg = e_invarg; 987 return FAIL; 988 } 989 990 // Skip all options that are not window-local (used when showing 991 // an already loaded buffer in a window). 992 if ((opt_flags & OPT_WINONLY) && !option_is_window_local(opt_idx)) { 993 return FAIL; 994 } 995 996 // Skip all options that are window-local (used for :vimgrep). 997 if ((opt_flags & OPT_NOWIN) && option_is_window_local(opt_idx)) { 998 return FAIL; 999 } 1000 1001 // Disallow changing some options from modelines. 1002 if (opt_flags & OPT_MODELINE) { 1003 if (flags & (kOptFlagSecure | kOptFlagNoML)) { 1004 *errmsg = e_not_allowed_in_modeline; 1005 return FAIL; 1006 } 1007 if ((flags & kOptFlagMLE) && !p_mle) { 1008 *errmsg = e_not_allowed_in_modeline_when_modelineexpr_is_off; 1009 return FAIL; 1010 } 1011 // In diff mode some options are overruled. This avoids that 1012 // 'foldmethod' becomes "marker" instead of "diff" and that 1013 // "wrap" gets set. 1014 if (win->w_p_diff && (opt_idx == kOptFoldmethod || opt_idx == kOptWrap)) { 1015 return FAIL; 1016 } 1017 } 1018 1019 // Disallow changing some options in the sandbox 1020 if (sandbox != 0 && (flags & kOptFlagSecure)) { 1021 *errmsg = e_sandbox; 1022 return FAIL; 1023 } 1024 1025 return OK; 1026 } 1027 1028 /// Skip over the name of a TTY option or keycode option. 1029 /// 1030 /// @param[in] arg Start of TTY or keycode option name. 1031 /// 1032 /// @return NULL when option isn't a TTY or keycode option. Otherwise pointer to the char after the 1033 /// option name. 1034 static const char *find_tty_option_end(const char *arg) 1035 { 1036 if (strequal(arg, "term")) { 1037 return arg + sizeof("term") - 1; 1038 } else if (strequal(arg, "ttytype")) { 1039 return arg + sizeof("ttytype") - 1; 1040 } 1041 1042 const char *p = arg; 1043 bool delimit = false; // whether to delimit < 1044 1045 if (arg[0] == '<') { 1046 // look out for <t_>;> 1047 delimit = true; 1048 p++; 1049 } 1050 if (p[0] == 't' && p[1] == '_' && p[2] && p[3]) { 1051 // "t_xx" ("t_Co") option. 1052 p += 4; 1053 } else if (delimit) { 1054 // Search for delimiting >. 1055 while (*p != NUL && *p != '>') { 1056 p++; 1057 } 1058 } 1059 // Return NULL when delimiting > is not found. 1060 if (delimit) { 1061 if (*p != '>') { 1062 return NULL; 1063 } 1064 p++; 1065 } 1066 1067 return arg == p ? NULL : p; 1068 } 1069 1070 /// Skip over the name of an option. 1071 /// 1072 /// @param[in] arg Start of option name. 1073 /// @param[out] opt_idxp Set to option index in options[] table. 1074 /// 1075 /// @return NULL when no option name found. Otherwise pointer to the char after the option name. 1076 const char *find_option_end(const char *arg, OptIndex *opt_idxp) 1077 { 1078 const char *p; 1079 1080 // Handle TTY and keycode options separately. 1081 if ((p = find_tty_option_end(arg)) != NULL) { 1082 *opt_idxp = kOptInvalid; 1083 return p; 1084 } else { 1085 p = arg; 1086 } 1087 1088 if (!ASCII_ISALPHA(*p)) { 1089 *opt_idxp = kOptInvalid; 1090 return NULL; 1091 } 1092 while (ASCII_ISALPHA(*p)) { 1093 p++; 1094 } 1095 1096 *opt_idxp = find_option_len(arg, (size_t)(p - arg)); 1097 return p; 1098 } 1099 1100 /// Get new option value from argp. Allocated OptVal must be freed by caller. 1101 /// Can unset local value of an option when ":set {option}<" is used. 1102 static OptVal get_option_newval(OptIndex opt_idx, int opt_flags, set_prefix_T prefix, char **argp, 1103 int nextchar, set_op_T op, uint32_t flags, void *varp, char *errbuf, 1104 const size_t errbuflen, const char **errmsg) 1105 FUNC_ATTR_WARN_UNUSED_RESULT 1106 { 1107 assert(varp != NULL); 1108 1109 vimoption_T *opt = &options[opt_idx]; 1110 char *arg = *argp; 1111 // When setting the local value of a global option, the old value may be the global value. 1112 const bool oldval_is_global = option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL); 1113 OptVal oldval = optval_from_varp(opt_idx, oldval_is_global ? get_varp(opt) : varp); 1114 OptVal newval = NIL_OPTVAL; 1115 1116 if (nextchar == '&') { 1117 // ":set opt&": Reset to default value. 1118 // NOTE: Use OPT_GLOBAL instead of opt_flags to ensure we don't use the unset local value for 1119 // global-local options when OPT_LOCAL is used. 1120 return optval_copy(get_option_default(opt_idx, OPT_GLOBAL)); 1121 } else if (nextchar == '<') { 1122 // ":set opt<": Reset to global value. 1123 // ":setlocal opt<": Copy global value to local value. 1124 if (option_is_global_local(opt_idx) && !(opt_flags & OPT_LOCAL)) { 1125 unset_option_local_value(opt_idx); 1126 } 1127 return get_option_value(opt_idx, OPT_GLOBAL); 1128 } 1129 1130 switch (oldval.type) { 1131 case kOptValTypeNil: 1132 abort(); 1133 case kOptValTypeBoolean: { 1134 TriState newval_bool; 1135 1136 // ":set opt!": invert 1137 if (nextchar == '!') { 1138 switch (oldval.data.boolean) { 1139 case kNone: 1140 newval_bool = kNone; 1141 break; 1142 case kTrue: 1143 newval_bool = kFalse; 1144 break; 1145 case kFalse: 1146 newval_bool = kTrue; 1147 break; 1148 } 1149 } else { 1150 // ":set invopt": invert 1151 // ":set opt" or ":set noopt": set or reset 1152 if (prefix == PREFIX_INV) { 1153 newval_bool = *(int *)varp ^ 1; 1154 } else { 1155 newval_bool = prefix == PREFIX_NO ? 0 : 1; 1156 } 1157 } 1158 1159 newval = BOOLEAN_OPTVAL(newval_bool); 1160 break; 1161 } 1162 case kOptValTypeNumber: { 1163 OptInt oldval_num = oldval.data.number; 1164 OptInt newval_num; 1165 1166 // Different ways to set a number option: 1167 // <xx> accept special key codes for 'wildchar' or 'wildcharm' 1168 // ^x accept ctrl key codes for 'wildchar' or 'wildcharm' 1169 // c accept any non-digit for 'wildchar' or 'wildcharm' 1170 // [-]0-9 set number 1171 // other error 1172 arg++; 1173 if (((OptInt *)varp == &p_wc || (OptInt *)varp == &p_wcm) 1174 && (*arg == '<' || *arg == '^' 1175 || (*arg != NUL && (!arg[1] || ascii_iswhite(arg[1])) && !ascii_isdigit(*arg)))) { 1176 newval_num = string_to_key(arg); 1177 if (newval_num == 0) { 1178 *errmsg = e_invarg; 1179 return newval; 1180 } 1181 } else if (*arg == '-' || ascii_isdigit(*arg)) { 1182 int i; 1183 // Allow negative, octal and hex numbers. 1184 vim_str2nr(arg, NULL, &i, STR2NR_ALL, &newval_num, NULL, 0, true, NULL); 1185 if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) { 1186 *errmsg = e_number_required_after_equal; 1187 return newval; 1188 } 1189 } else { 1190 *errmsg = e_number_required_after_equal; 1191 return newval; 1192 } 1193 1194 if (op == OP_ADDING) { 1195 newval_num = oldval_num + newval_num; 1196 } 1197 if (op == OP_PREPENDING) { 1198 newval_num = oldval_num * newval_num; 1199 } 1200 if (op == OP_REMOVING) { 1201 newval_num = oldval_num - newval_num; 1202 } 1203 1204 newval = NUMBER_OPTVAL(newval_num); 1205 break; 1206 } 1207 case kOptValTypeString: { 1208 const char *oldval_str = oldval.data.string.data; 1209 // Get the new value for the option 1210 const char *newval_str = stropt_get_newval(nextchar, opt_idx, argp, varp, oldval_str, &op, 1211 flags); 1212 newval = CSTR_AS_OPTVAL(newval_str); 1213 break; 1214 } 1215 } 1216 1217 return newval; 1218 } 1219 1220 static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *errbuf, 1221 size_t errbuflen, const char **errmsg) 1222 { 1223 // 1: nothing, 0: "no", 2: "inv" in front of name 1224 set_prefix_T prefix = get_option_prefix(argp); 1225 1226 char *arg = *argp; 1227 1228 // find end of name 1229 OptIndex opt_idx; 1230 const char *const option_end = find_option_end(arg, &opt_idx); 1231 1232 if (opt_idx != kOptInvalid) { 1233 assert(option_end >= arg); 1234 } else if (is_tty_option(arg)) { // Silently ignore TTY options. 1235 return; 1236 } else { // Invalid option name, skip. 1237 *errmsg = e_unknown_option; 1238 return; 1239 } 1240 1241 // Remember character after option name. 1242 uint8_t afterchar = (uint8_t)(*option_end); 1243 char *p = (char *)option_end; 1244 1245 // Skip white space, allow ":set ai ?". 1246 while (ascii_iswhite(*p)) { 1247 p++; 1248 } 1249 1250 set_op_T op = get_op(p); 1251 if (op != OP_NONE) { 1252 p++; 1253 } 1254 1255 uint8_t nextchar = (uint8_t)(*p); // next non-white char after option name 1256 // flags for current option 1257 uint32_t flags = options[opt_idx].flags; 1258 // pointer to variable for current option 1259 void *varp = get_varp_scope(&(options[opt_idx]), opt_flags); 1260 1261 if (validate_opt_idx(curwin, opt_idx, opt_flags, flags, prefix, errmsg) == FAIL) { 1262 return; 1263 } 1264 1265 if (vim_strchr("?=:!&<", nextchar) != NULL) { 1266 *argp = p; 1267 1268 if (nextchar == '&' && (*argp)[1] == 'v' && (*argp)[2] == 'i') { 1269 if ((*argp)[3] == 'm') { // "opt&vim": set to Vim default 1270 *argp += 3; 1271 } else { // "opt&vi": set to Vi default 1272 *argp += 2; 1273 } 1274 } 1275 if (vim_strchr("?!&<", nextchar) != NULL 1276 && (*argp)[1] != NUL && !ascii_iswhite((*argp)[1])) { 1277 *errmsg = e_trailing; 1278 return; 1279 } 1280 } 1281 1282 // Allow '=' and ':' as MS-DOS command.com allows only one '=' character per "set" command line. 1283 if (nextchar == '?' 1284 || (prefix == PREFIX_NONE && vim_strchr("=:&<", nextchar) == NULL 1285 && !option_has_type(opt_idx, kOptValTypeBoolean))) { 1286 // print value 1287 if (*did_show) { 1288 msg_putchar('\n'); // cursor below last one 1289 } else { 1290 msg_ext_set_kind("list_cmd"); 1291 gotocmdline(true); // cursor at status line 1292 *did_show = true; // remember that we did a line 1293 } 1294 showoneopt(&options[opt_idx], opt_flags); 1295 1296 if (p_verbose > 0) { 1297 // Mention where the option was last set. 1298 if (varp == options[opt_idx].var) { 1299 last_set_msg(options[opt_idx].script_ctx); 1300 } else if (option_has_scope(opt_idx, kOptScopeWin)) { 1301 last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]); 1302 } else if (option_has_scope(opt_idx, kOptScopeBuf)) { 1303 last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]); 1304 } 1305 } 1306 1307 if (nextchar != '?' && nextchar != NUL && !ascii_iswhite(afterchar)) { 1308 *errmsg = e_trailing; 1309 } 1310 return; 1311 } 1312 1313 if (option_has_type(opt_idx, kOptValTypeBoolean)) { 1314 if (vim_strchr("=:", nextchar) != NULL) { 1315 *errmsg = e_invarg; 1316 return; 1317 } 1318 1319 if (vim_strchr("!&<", nextchar) == NULL && nextchar != NUL && !ascii_iswhite(afterchar)) { 1320 *errmsg = e_trailing; 1321 return; 1322 } 1323 } else { 1324 if (vim_strchr("=:&<", nextchar) == NULL) { 1325 *errmsg = e_invarg; 1326 return; 1327 } 1328 } 1329 1330 OptVal newval = get_option_newval(opt_idx, opt_flags, prefix, argp, nextchar, op, flags, varp, 1331 errbuf, errbuflen, errmsg); 1332 1333 if (newval.type == kOptValTypeNil || *errmsg != NULL) { 1334 return; 1335 } 1336 1337 *errmsg = set_option(opt_idx, newval, opt_flags, 0, false, op == OP_NONE, errbuf, errbuflen); 1338 } 1339 1340 /// Parse 'arg' for option settings. 1341 /// 1342 /// 'arg' may be IObuff, but only when no errors can be present and option 1343 /// does not need to be expanded with option_expand(). 1344 /// "opt_flags": 1345 /// 0 for ":set" 1346 /// OPT_GLOBAL for ":setglobal" 1347 /// OPT_LOCAL for ":setlocal" and a modeline 1348 /// OPT_MODELINE for a modeline 1349 /// OPT_WINONLY to only set window-local options 1350 /// OPT_NOWIN to skip setting window-local options 1351 /// 1352 /// @param arg option string (may be written to!) 1353 /// 1354 /// @return FAIL if an error is detected, OK otherwise 1355 int do_set(char *arg, int opt_flags) 1356 { 1357 bool did_show = false; // already showed one value 1358 1359 if (*arg == NUL) { 1360 showoptions(false, opt_flags); 1361 did_show = true; 1362 } else { 1363 while (*arg != NUL) { // loop to process all options 1364 if (strncmp(arg, "all", 3) == 0 && !ASCII_ISALPHA(arg[3]) 1365 && !(opt_flags & OPT_MODELINE)) { 1366 // ":set all" show all options. 1367 // ":set all&" set all options to their default value. 1368 arg += 3; 1369 if (*arg == '&') { 1370 arg++; 1371 // Only for :set command set global value of local options. 1372 set_options_default(opt_flags); 1373 didset_options(); 1374 didset_options2(); 1375 ui_refresh_options(); 1376 redraw_all_later(UPD_CLEAR); 1377 } else { 1378 showoptions(true, opt_flags); 1379 did_show = true; 1380 } 1381 } else { 1382 char *startarg = arg; // remember for error message 1383 const char *errmsg = NULL; 1384 char errbuf[ERR_BUFLEN]; 1385 1386 do_one_set_option(opt_flags, &arg, &did_show, errbuf, sizeof(errbuf), &errmsg); 1387 1388 // Advance to next argument. 1389 // - skip until a blank found, taking care of backslashes 1390 // - skip blanks 1391 // - skip one "=val" argument (for hidden options ":set gfn =xx") 1392 for (int i = 0; i < 2; i++) { 1393 arg = skiptowhite_esc(arg); 1394 arg = skipwhite(arg); 1395 if (*arg != '=') { 1396 break; 1397 } 1398 } 1399 1400 if (errmsg != NULL) { 1401 int i = vim_snprintf((char *)IObuff, IOSIZE, "%s", _(errmsg)) + 2; 1402 if (i + (arg - startarg) < IOSIZE) { 1403 // append the argument with the error 1404 xstrlcpy(IObuff + i - 2, ": ", (size_t)(IOSIZE - i + 2)); 1405 assert(arg >= startarg); 1406 memmove(IObuff + i, startarg, (size_t)(arg - startarg)); 1407 IObuff[i + (arg - startarg)] = NUL; 1408 } 1409 // make sure all characters are printable 1410 trans_characters(IObuff, IOSIZE); 1411 1412 no_wait_return++; // wait_return() done later 1413 emsg(IObuff); // show error highlighted 1414 no_wait_return--; 1415 1416 return FAIL; 1417 } 1418 } 1419 1420 arg = skipwhite(arg); 1421 } 1422 } 1423 1424 if (silent_mode && did_show) { 1425 // After displaying option values in silent mode. 1426 silent_mode = false; 1427 info_message = true; // use stdout, not stderr 1428 msg_putchar('\n'); 1429 silent_mode = true; 1430 info_message = false; // use stdout, not stderr 1431 } 1432 1433 return OK; 1434 } 1435 1436 // Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. 1437 // When "has_lt" is true there is a '<' before "*arg_arg". 1438 // Returns 0 when the key is not recognized. 1439 static int find_key_len(const char *arg_arg, size_t len, bool has_lt) 1440 { 1441 int key = 0; 1442 const char *arg = arg_arg; 1443 1444 // Don't use get_special_key_code() for t_xx, we don't want it to call 1445 // add_termcap_entry(). 1446 if (len >= 4 && arg[0] == 't' && arg[1] == '_') { 1447 if (!has_lt || arg[4] == '>') { 1448 key = TERMCAP2KEY((uint8_t)arg[2], (uint8_t)arg[3]); 1449 } 1450 } else if (has_lt) { 1451 arg--; // put arg at the '<' 1452 int modifiers = 0; 1453 key = find_special_key(&arg, len + 1, &modifiers, FSK_KEYCODE | FSK_KEEP_X_KEY | FSK_SIMPLIFY, 1454 NULL); 1455 if (modifiers) { // can't handle modifiers here 1456 key = 0; 1457 } 1458 } 1459 return key; 1460 } 1461 1462 /// Convert a key name or string into a key value. 1463 /// Used for 'cedit', 'wildchar' and 'wildcharm' options. 1464 int string_to_key(char *arg) 1465 { 1466 if (*arg == '<' && arg[1]) { 1467 return find_key_len(arg + 1, strlen(arg), true); 1468 } 1469 if (*arg == '^' && arg[1]) { 1470 int key = CTRL_CHR((uint8_t)arg[1]); 1471 if (key == 0) { // ^@ is <Nul> 1472 key = K_ZERO; 1473 } 1474 return key; 1475 } 1476 return (uint8_t)(*arg); 1477 } 1478 1479 // When changing 'title', 'titlestring', 'icon' or 'iconstring', call 1480 // maketitle() to create and display it. 1481 // When switching the title or icon off, call ui_set_{icon,title}(NULL) to get 1482 // the old value back. 1483 void did_set_title(void) 1484 { 1485 if (starting != NO_SCREEN) { 1486 maketitle(); 1487 } 1488 } 1489 1490 /// set_options_bin - called when 'bin' changes value. 1491 /// 1492 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 1493 void set_options_bin(int oldval, int newval, int opt_flags) 1494 { 1495 // The option values that are changed when 'bin' changes are 1496 // copied when 'bin is set and restored when 'bin' is reset. 1497 if (newval) { 1498 if (!oldval) { // switched on 1499 if (!(opt_flags & OPT_GLOBAL)) { 1500 curbuf->b_p_tw_nobin = curbuf->b_p_tw; 1501 curbuf->b_p_wm_nobin = curbuf->b_p_wm; 1502 curbuf->b_p_ml_nobin = curbuf->b_p_ml; 1503 curbuf->b_p_et_nobin = curbuf->b_p_et; 1504 } 1505 if (!(opt_flags & OPT_LOCAL)) { 1506 p_tw_nobin = p_tw; 1507 p_wm_nobin = p_wm; 1508 p_ml_nobin = p_ml; 1509 p_et_nobin = p_et; 1510 } 1511 } 1512 1513 if (!(opt_flags & OPT_GLOBAL)) { 1514 curbuf->b_p_tw = 0; // no automatic line wrap 1515 curbuf->b_p_wm = 0; // no automatic line wrap 1516 curbuf->b_p_ml = 0; // no modelines 1517 curbuf->b_p_et = 0; // no expandtab 1518 } 1519 if (!(opt_flags & OPT_LOCAL)) { 1520 p_tw = 0; 1521 p_wm = 0; 1522 p_ml = false; 1523 p_et = false; 1524 p_bin = true; // needed when called for the "-b" argument 1525 } 1526 } else if (oldval) { // switched off 1527 if (!(opt_flags & OPT_GLOBAL)) { 1528 curbuf->b_p_tw = curbuf->b_p_tw_nobin; 1529 curbuf->b_p_wm = curbuf->b_p_wm_nobin; 1530 curbuf->b_p_ml = curbuf->b_p_ml_nobin; 1531 curbuf->b_p_et = curbuf->b_p_et_nobin; 1532 } 1533 if (!(opt_flags & OPT_LOCAL)) { 1534 p_tw = p_tw_nobin; 1535 p_wm = p_wm_nobin; 1536 p_ml = p_ml_nobin; 1537 p_et = p_et_nobin; 1538 } 1539 } 1540 1541 // Remember where the dependent option were reset 1542 didset_options_sctx(opt_flags, p_bin_dep_opts); 1543 } 1544 1545 /// Expand environment variables for some string options. 1546 /// These string options cannot be indirect! 1547 /// If "val" is NULL expand the current value of the option. 1548 /// Return pointer to NameBuff, or NULL when not expanded. 1549 static char *option_expand(OptIndex opt_idx, const char *val) 1550 { 1551 // if option doesn't need expansion nothing to do 1552 if (!(options[opt_idx].flags & kOptFlagExpand) || is_option_hidden(opt_idx)) { 1553 return NULL; 1554 } 1555 1556 if (val == NULL) { 1557 val = *(char **)options[opt_idx].var; 1558 } 1559 1560 // If val is longer than MAXPATHL no meaningful expansion can be done, 1561 // expand_env() would truncate the string. 1562 if (val == NULL || strlen(val) > MAXPATHL) { 1563 return NULL; 1564 } 1565 1566 // Expanding this with NameBuff, expand_env() must not be passed IObuff. 1567 // Escape spaces when expanding 'tags' or 'path', they are used to separate 1568 // file names. 1569 // For 'spellsuggest' expand after "file:". 1570 char **var = (char **)options[opt_idx].var; 1571 bool esc = var == &p_tags || var == &p_path; 1572 expand_env_esc(val, NameBuff, MAXPATHL, esc, false, 1573 (char **)options[opt_idx].var == &p_sps ? "file:" : NULL); 1574 if (strcmp(NameBuff, val) == 0) { // they are the same 1575 return NULL; 1576 } 1577 1578 return NameBuff; 1579 } 1580 1581 /// After setting various option values: recompute variables that depend on 1582 /// option values. 1583 static void didset_options(void) 1584 { 1585 // initialize the table for 'iskeyword' et.al. 1586 init_chartab(); 1587 1588 didset_string_options(); 1589 1590 spell_check_msm(); 1591 spell_check_sps(); 1592 compile_cap_prog(curwin->w_s); 1593 did_set_spell_option(); 1594 // set cedit_key 1595 did_set_cedit(NULL); 1596 // initialize the table for 'breakat'. 1597 did_set_breakat(NULL); 1598 didset_window_options(curwin, true); 1599 } 1600 1601 // More side effects of setting options. 1602 static void didset_options2(void) 1603 { 1604 // Initialize the highlight_attr[] table. 1605 highlight_changed(); 1606 1607 // Parse default for 'fillchars'. 1608 set_chars_option(curwin, curwin->w_p_fcs, kFillchars, true, NULL, 0); 1609 1610 // Parse default for 'listchars'. 1611 set_chars_option(curwin, curwin->w_p_lcs, kListchars, true, NULL, 0); 1612 1613 // Parse default for 'wildmode'. 1614 check_opt_wim(); 1615 xfree(curbuf->b_p_vsts_array); 1616 tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array); 1617 xfree(curbuf->b_p_vts_array); 1618 tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array); 1619 } 1620 1621 /// Check for string options that are NULL (normally only termcap options). 1622 void check_options(void) 1623 { 1624 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 1625 if ((option_has_type(opt_idx, kOptValTypeString)) && options[opt_idx].var != NULL) { 1626 check_string_option((char **)get_varp(&(options[opt_idx]))); 1627 } 1628 } 1629 } 1630 1631 /// Check if option was set insecurely. 1632 /// 1633 /// @param wp Window. 1634 /// @param opt_idx Option index in options[] table. 1635 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 1636 /// 1637 /// @return True if option was set from a modeline or in secure mode, false if it wasn't. 1638 int was_set_insecurely(win_T *const wp, OptIndex opt_idx, int opt_flags) 1639 { 1640 assert(opt_idx != kOptInvalid); 1641 1642 uint32_t *flagp = insecure_flag(wp, opt_idx, opt_flags); 1643 return (*flagp & kOptFlagInsecure) != 0; 1644 } 1645 1646 /// Get a pointer to the flags used for the kOptFlagInsecure flag of option 1647 /// "opt_idx". For some local options a local flags field is used. 1648 /// NOTE: Caller must make sure that "wp" is set to the window from which 1649 /// the option is used. 1650 uint32_t *insecure_flag(win_T *const wp, OptIndex opt_idx, int opt_flags) 1651 { 1652 if (opt_flags & OPT_LOCAL) { 1653 assert(wp != NULL); 1654 switch (opt_idx) { 1655 case kOptWrap: 1656 return &wp->w_p_wrap_flags; 1657 case kOptStatusline: 1658 return &wp->w_p_stl_flags; 1659 case kOptWinbar: 1660 return &wp->w_p_wbr_flags; 1661 case kOptFoldexpr: 1662 return &wp->w_p_fde_flags; 1663 case kOptFoldtext: 1664 return &wp->w_p_fdt_flags; 1665 case kOptIndentexpr: 1666 return &wp->w_buffer->b_p_inde_flags; 1667 case kOptFormatexpr: 1668 return &wp->w_buffer->b_p_fex_flags; 1669 case kOptIncludeexpr: 1670 return &wp->w_buffer->b_p_inex_flags; 1671 default: 1672 break; 1673 } 1674 } else { 1675 // For global value of window-local options, use flags in w_allbuf_opt. 1676 switch (opt_idx) { 1677 case kOptWrap: 1678 return &wp->w_allbuf_opt.wo_wrap_flags; 1679 case kOptFoldexpr: 1680 return &wp->w_allbuf_opt.wo_fde_flags; 1681 case kOptFoldtext: 1682 return &wp->w_allbuf_opt.wo_fdt_flags; 1683 default: 1684 break; 1685 } 1686 } 1687 // Nothing special, return global flags field. 1688 return &options[opt_idx].flags; 1689 } 1690 1691 /// Redraw the window title and/or tab page text later. 1692 void redraw_titles(void) 1693 { 1694 need_maketitle = true; 1695 redraw_tabline = true; 1696 } 1697 1698 /// Return true if "val" is a valid name: only consists of alphanumeric ASCII 1699 /// characters or characters in "allowed". 1700 bool valid_name(const char *val, const char *allowed) 1701 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 1702 { 1703 for (const char *s = val; *s != NUL; s++) { 1704 if (!ASCII_ISALNUM(*s) 1705 && vim_strchr(allowed, (uint8_t)(*s)) == NULL) { 1706 return false; 1707 } 1708 } 1709 return true; 1710 } 1711 1712 void check_blending(win_T *wp) 1713 { 1714 wp->w_grid_alloc.blending = 1715 wp->w_p_winbl > 0 || (wp->w_floating && wp->w_config.shadow); 1716 } 1717 1718 /// Handle setting `winhighlight' in window "wp" 1719 /// 1720 /// @param winhl when NULL: use "wp->w_p_winhl" 1721 /// @param wp when NULL: only parse "winhl" 1722 /// 1723 /// @return whether the option value is valid. 1724 bool parse_winhl_opt(const char *winhl, win_T *wp) 1725 { 1726 const char *p = empty_string_option; 1727 if (winhl != NULL) { 1728 p = winhl; 1729 } else if (wp != NULL) { 1730 p = wp->w_p_winhl; 1731 } 1732 1733 if (!*p) { 1734 if (wp != NULL && wp->w_ns_hl_winhl > 0 && wp->w_ns_hl == wp->w_ns_hl_winhl) { 1735 wp->w_ns_hl = 0; 1736 wp->w_hl_needs_update = true; 1737 } 1738 1739 return true; 1740 } 1741 1742 int ns_hl = 0; 1743 if (wp != NULL) { 1744 if (wp->w_ns_hl_winhl == 0) { 1745 wp->w_ns_hl_winhl = (int)nvim_create_namespace(NULL_STRING); 1746 } else { 1747 // Namespace already exists. Invalidate existing items. 1748 DecorProvider *dp = get_decor_provider(wp->w_ns_hl_winhl, true); 1749 dp->hl_valid++; 1750 } 1751 ns_hl = wp->w_ns_hl_winhl; 1752 if (wp->w_ns_hl <= 0) { 1753 wp->w_ns_hl = wp->w_ns_hl_winhl; 1754 } 1755 } 1756 1757 while (*p) { 1758 const char *colon = strchr(p, ':'); 1759 if (!colon) { 1760 return false; 1761 } 1762 size_t nlen = (size_t)(colon - p); 1763 const char *hi = colon + 1; 1764 const char *commap = xstrchrnul(hi, ','); 1765 size_t len = (size_t)(commap - hi); 1766 int hl_id = len ? syn_check_group(hi, len) : -1; 1767 if (hl_id == 0) { 1768 return false; 1769 } 1770 int hl_id_link = nlen ? syn_check_group(p, nlen) : 0; 1771 if (hl_id_link == 0) { 1772 return false; 1773 } 1774 1775 if (wp != NULL) { 1776 HlAttrs attrs = HLATTRS_INIT; 1777 attrs.rgb_ae_attr |= HL_GLOBAL; 1778 ns_hl_def(ns_hl, hl_id_link, attrs, hl_id, NULL); 1779 } 1780 1781 p = *commap ? commap + 1 : ""; 1782 } 1783 1784 if (wp != NULL) { 1785 wp->w_hl_needs_update = true; 1786 } 1787 return true; 1788 } 1789 1790 /// Get the script context of global option at index opt_idx. 1791 sctx_T *get_option_sctx(OptIndex opt_idx) 1792 { 1793 assert(opt_idx != kOptInvalid); 1794 return &options[opt_idx].script_ctx; 1795 } 1796 1797 /// Set the script_ctx for an option, taking care of setting the buffer- or 1798 /// window-local value. 1799 void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx) 1800 { 1801 bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; 1802 1803 // Modeline already has the line number set. 1804 if (!(opt_flags & OPT_MODELINE)) { 1805 script_ctx.sc_lnum += SOURCING_LNUM; 1806 } 1807 nlua_set_sctx(&script_ctx); 1808 1809 // Remember where the option was set. For local options need to do that 1810 // in the buffer or window structure. 1811 if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) { 1812 options[opt_idx].script_ctx = script_ctx; 1813 } 1814 if (both || (opt_flags & OPT_LOCAL)) { 1815 if (option_has_scope(opt_idx, kOptScopeBuf)) { 1816 curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = script_ctx; 1817 } else if ((option_has_scope(opt_idx, kOptScopeWin))) { 1818 curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = script_ctx; 1819 if (both) { 1820 // also setting the "all buffers" value 1821 curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = script_ctx; 1822 } 1823 } 1824 } 1825 } 1826 1827 /// Apply the OptionSet autocommand. 1828 static void apply_optionset_autocmd(OptIndex opt_idx, int opt_flags, OptVal oldval, OptVal oldval_g, 1829 OptVal oldval_l, OptVal newval, const char *errmsg) 1830 { 1831 // Don't do this while starting up, failure or recursively. 1832 if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL) { 1833 return; 1834 } 1835 1836 char buf_type[7]; 1837 typval_T oldval_tv = optval_as_tv(oldval, false); 1838 typval_T oldval_g_tv = optval_as_tv(oldval_g, false); 1839 typval_T oldval_l_tv = optval_as_tv(oldval_l, false); 1840 typval_T newval_tv = optval_as_tv(newval, false); 1841 1842 vim_snprintf(buf_type, sizeof(buf_type), "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); 1843 set_vim_var_tv(VV_OPTION_NEW, &newval_tv); 1844 set_vim_var_tv(VV_OPTION_OLD, &oldval_tv); 1845 set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); 1846 if (opt_flags & OPT_LOCAL) { 1847 set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1); 1848 set_vim_var_tv(VV_OPTION_OLDLOCAL, &oldval_tv); 1849 } 1850 if (opt_flags & OPT_GLOBAL) { 1851 set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1); 1852 set_vim_var_tv(VV_OPTION_OLDGLOBAL, &oldval_tv); 1853 } 1854 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { 1855 set_vim_var_string(VV_OPTION_COMMAND, "set", -1); 1856 set_vim_var_tv(VV_OPTION_OLDLOCAL, &oldval_l_tv); 1857 set_vim_var_tv(VV_OPTION_OLDGLOBAL, &oldval_g_tv); 1858 } 1859 if (opt_flags & OPT_MODELINE) { 1860 set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1); 1861 set_vim_var_tv(VV_OPTION_OLDLOCAL, &oldval_tv); 1862 } 1863 apply_autocmds(EVENT_OPTIONSET, options[opt_idx].fullname, NULL, false, NULL); 1864 reset_v_option_vars(); 1865 } 1866 1867 /// Process the updated 'arabic' option value. 1868 static const char *did_set_arabic(optset_T *args) 1869 { 1870 win_T *win = (win_T *)args->os_win; 1871 const char *errmsg = NULL; 1872 1873 if (win->w_p_arab) { 1874 // 'arabic' is set, handle various sub-settings. 1875 if (!p_tbidi) { 1876 // set rightleft mode 1877 if (!win->w_p_rl) { 1878 win->w_p_rl = true; 1879 changed_window_setting(win); 1880 } 1881 1882 // Enable Arabic shaping (major part of what Arabic requires) 1883 if (!p_arshape) { 1884 p_arshape = true; 1885 redraw_all_later(UPD_NOT_VALID); 1886 } 1887 } 1888 1889 // Arabic requires a utf-8 encoding, inform the user if it's not 1890 // set. 1891 if (strcmp(p_enc, "utf-8") != 0) { 1892 static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'"); 1893 1894 msg_source(HLF_W); 1895 msg(_(w_arabic), HLF_W); 1896 set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1); 1897 } 1898 1899 // set 'delcombine' 1900 p_deco = true; 1901 1902 // Force-set the necessary keymap for arabic. 1903 errmsg = set_option_value(kOptKeymap, STATIC_CSTR_AS_OPTVAL("arabic"), OPT_LOCAL); 1904 } else { 1905 // 'arabic' is reset, handle various sub-settings. 1906 if (!p_tbidi) { 1907 // reset rightleft mode 1908 if (win->w_p_rl) { 1909 win->w_p_rl = false; 1910 changed_window_setting(win); 1911 } 1912 1913 // 'arabicshape' isn't reset, it is a global option and 1914 // another window may still need it "on". 1915 } 1916 1917 // 'delcombine' isn't reset, it is a global option and another 1918 // window may still want it "on". 1919 1920 // Revert to the default keymap 1921 win->w_buffer->b_p_iminsert = B_IMODE_NONE; 1922 win->w_buffer->b_p_imsearch = B_IMODE_USE_INSERT; 1923 } 1924 1925 return errmsg; 1926 } 1927 1928 /// Process the updated 'autochdir' option value. 1929 static const char *did_set_autochdir(optset_T *args FUNC_ATTR_UNUSED) 1930 { 1931 // Change directories when the 'acd' option is set now. 1932 do_autochdir(); 1933 return NULL; 1934 } 1935 1936 /// Process the updated 'binary' option value. 1937 static const char *did_set_binary(optset_T *args) 1938 { 1939 buf_T *buf = (buf_T *)args->os_buf; 1940 1941 // when 'bin' is set also set some other options 1942 set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags); 1943 redraw_titles(); 1944 1945 return NULL; 1946 } 1947 1948 /// Process the updated 'buflisted' option value. 1949 static const char *did_set_buflisted(optset_T *args) 1950 { 1951 buf_T *buf = (buf_T *)args->os_buf; 1952 1953 // when 'buflisted' changes, trigger autocommands 1954 if (args->os_oldval.boolean != buf->b_p_bl) { 1955 apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE, 1956 NULL, NULL, true, buf); 1957 } 1958 return NULL; 1959 } 1960 1961 /// Process the new 'cmdheight' option value. 1962 static const char *did_set_cmdheight(optset_T *args) 1963 { 1964 OptInt old_value = args->os_oldval.number; 1965 1966 if (p_ch > Rows - min_rows(curtab) + 1) { 1967 p_ch = Rows - min_rows(curtab) + 1; 1968 } 1969 1970 // if p_ch changed value, change the command line height 1971 // Only compute the new window layout when startup has been 1972 // completed. Otherwise the frame sizes may be wrong. 1973 if ((p_ch != old_value 1974 || tabline_height() + global_stl_height() + topframe->fr_height != Rows - p_ch) 1975 && full_screen) { 1976 command_height(); 1977 } 1978 1979 return NULL; 1980 } 1981 1982 /// Process the updated 'diff' option value. 1983 static const char *did_set_diff(optset_T *args) 1984 { 1985 win_T *win = (win_T *)args->os_win; 1986 // May add or remove the buffer from the list of diff buffers. 1987 diff_buf_adjust(win); 1988 if (foldmethodIsDiff(win)) { 1989 foldUpdateAll(win); 1990 } 1991 return NULL; 1992 } 1993 1994 /// Process the updated 'endoffile' or 'endofline' or 'fixendofline' or 'bomb' 1995 /// option value. 1996 static const char *did_set_eof_eol_fixeol_bomb(optset_T *args FUNC_ATTR_UNUSED) 1997 { 1998 // redraw the window title and tab page text 1999 redraw_titles(); 2000 return NULL; 2001 } 2002 2003 /// Process the updated 'equalalways' option value. 2004 static const char *did_set_equalalways(optset_T *args) 2005 { 2006 win_T *win = (win_T *)args->os_win; 2007 if (p_ea && !args->os_oldval.boolean) { 2008 win_equal(win, false, 0); 2009 } 2010 2011 return NULL; 2012 } 2013 2014 /// Process the new 'foldlevel' option value. 2015 static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED) 2016 { 2017 newFoldLevel(); 2018 return NULL; 2019 } 2020 2021 /// Process the new 'foldminlines' option value. 2022 static const char *did_set_foldminlines(optset_T *args) 2023 { 2024 win_T *win = (win_T *)args->os_win; 2025 foldUpdateAll(win); 2026 return NULL; 2027 } 2028 2029 /// Process the new 'foldnestmax' option value. 2030 static const char *did_set_foldnestmax(optset_T *args) 2031 { 2032 win_T *win = (win_T *)args->os_win; 2033 if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) { 2034 foldUpdateAll(win); 2035 } 2036 return NULL; 2037 } 2038 2039 /// Process the new 'helpheight' option value. 2040 static const char *did_set_helpheight(optset_T *args) 2041 { 2042 // Change window height NOW 2043 if (!ONE_WINDOW) { 2044 if (curbuf->b_help && curwin->w_height < p_hh) { 2045 win_setheight((int)p_hh); 2046 } 2047 } 2048 2049 return NULL; 2050 } 2051 2052 /// Process the updated 'hlsearch' option value. 2053 static const char *did_set_hlsearch(optset_T *args FUNC_ATTR_UNUSED) 2054 { 2055 // when 'hlsearch' is set or reset: reset no_hlsearch 2056 set_no_hlsearch(false); 2057 return NULL; 2058 } 2059 2060 /// Process the updated 'ignorecase' option value. 2061 static const char *did_set_ignorecase(optset_T *args FUNC_ATTR_UNUSED) 2062 { 2063 // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw 2064 if (p_hls) { 2065 redraw_all_later(UPD_SOME_VALID); 2066 } 2067 return NULL; 2068 } 2069 2070 /// Process the new 'iminset' option value. 2071 static const char *did_set_iminsert(optset_T *args FUNC_ATTR_UNUSED) 2072 { 2073 showmode(); 2074 // Show/unshow value of 'keymap' in status lines. 2075 status_redraw_curbuf(); 2076 2077 return NULL; 2078 } 2079 2080 /// Process the updated 'langnoremap' option value. 2081 static const char *did_set_langnoremap(optset_T *args FUNC_ATTR_UNUSED) 2082 { 2083 // 'langnoremap' -> !'langremap' 2084 p_lrm = !p_lnr; 2085 return NULL; 2086 } 2087 2088 /// Process the updated 'langremap' option value. 2089 static const char *did_set_langremap(optset_T *args FUNC_ATTR_UNUSED) 2090 { 2091 // 'langremap' -> !'langnoremap' 2092 p_lnr = !p_lrm; 2093 return NULL; 2094 } 2095 2096 /// Process the new 'laststatus' option value. 2097 static const char *did_set_laststatus(optset_T *args) 2098 { 2099 OptInt old_value = args->os_oldval.number; 2100 OptInt value = args->os_newval.number; 2101 2102 // When switching to global statusline, decrease topframe height 2103 // Also clear the cmdline to remove the ruler if there is one 2104 if (value == 3 && old_value != 3) { 2105 frame_new_height(topframe, topframe->fr_height - STATUS_HEIGHT, false, false, false); 2106 win_comp_pos(); 2107 clear_cmdline = true; 2108 } 2109 // When switching from global statusline, increase height of topframe by STATUS_HEIGHT 2110 // in order to to re-add the space that was previously taken by the global statusline 2111 if (old_value == 3 && value != 3) { 2112 frame_new_height(topframe, topframe->fr_height + STATUS_HEIGHT, false, false, false); 2113 win_comp_pos(); 2114 } 2115 2116 status_redraw_curbuf(); 2117 last_status(false); // (re)set last window status line. 2118 win_float_update_statusline(); 2119 return NULL; 2120 } 2121 2122 /// Process the updated 'lines' or 'columns' option value. 2123 static const char *did_set_lines_or_columns(optset_T *args) 2124 { 2125 // If the screen (shell) height has been changed, assume it is the 2126 // physical screenheight. 2127 if (p_lines != Rows || p_columns != Columns) { 2128 // Changing the screen size is not allowed while updating the screen. 2129 if (updating_screen) { 2130 OptVal oldval = (OptVal){ .type = kOptValTypeNumber, .data = args->os_oldval }; 2131 set_option_varp(args->os_idx, args->os_varp, oldval, false); 2132 } else if (full_screen) { 2133 screen_resize((int)p_columns, (int)p_lines); 2134 } else { 2135 // TODO(bfredl): is this branch ever needed? 2136 // Postpone the resizing; check the size and cmdline position for 2137 // messages. 2138 Rows = (int)p_lines; 2139 Columns = (int)p_columns; 2140 check_screensize(); 2141 int new_row = (int)(Rows - MAX(p_ch, 1)); 2142 if (cmdline_row > new_row && Rows > p_ch) { 2143 assert(p_ch >= 0 && new_row <= INT_MAX); 2144 cmdline_row = new_row; 2145 } 2146 } 2147 if (p_window >= Rows || !option_was_set(kOptWindow)) { 2148 p_window = Rows - 1; 2149 } 2150 } 2151 2152 // Adjust 'scrolljump' if needed. 2153 if (p_sj >= Rows && full_screen) { 2154 p_sj = Rows / 2; 2155 } 2156 2157 return NULL; 2158 } 2159 2160 /// Process the updated 'lisp' option value. 2161 static const char *did_set_lisp(optset_T *args) 2162 { 2163 buf_T *buf = (buf_T *)args->os_buf; 2164 // When 'lisp' option changes include/exclude '-' in keyword characters. 2165 buf_init_chartab(buf, false); // ignore errors 2166 return NULL; 2167 } 2168 2169 /// Process the updated 'modifiable' option value. 2170 static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED) 2171 { 2172 // when 'modifiable' is changed, redraw the window title 2173 redraw_titles(); 2174 2175 return NULL; 2176 } 2177 2178 /// Process the updated 'modified' option value. 2179 static const char *did_set_modified(optset_T *args) 2180 { 2181 buf_T *buf = (buf_T *)args->os_buf; 2182 if (!args->os_newval.boolean) { 2183 save_file_ff(buf); // Buffer is unchanged 2184 } 2185 redraw_titles(); 2186 buf->b_modified_was_set = (int)args->os_newval.boolean; 2187 return NULL; 2188 } 2189 2190 /// Process the updated 'number' or 'relativenumber' option value. 2191 static const char *did_set_number_relativenumber(optset_T *args) 2192 { 2193 win_T *win = (win_T *)args->os_win; 2194 if (*win->w_p_stc != NUL) { 2195 // When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width. 2196 win->w_nrwidth_line_count = 0; 2197 } 2198 check_signcolumn(NULL, win); 2199 return NULL; 2200 } 2201 2202 /// Process the new 'numberwidth' option value. 2203 static const char *did_set_numberwidth(optset_T *args) 2204 { 2205 win_T *win = (win_T *)args->os_win; 2206 win->w_nrwidth_line_count = 0; // trigger a redraw 2207 2208 return NULL; 2209 } 2210 2211 /// Process the updated 'paste' option value. 2212 static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED) 2213 { 2214 static int old_p_paste = false; 2215 static int save_sm = 0; 2216 static int save_sta = 0; 2217 static int save_ru = 0; 2218 static int save_ri = 0; 2219 2220 if (p_paste) { 2221 // Paste switched from off to on. 2222 // Save the current values, so they can be restored later. 2223 if (!old_p_paste) { 2224 // save options for each buffer 2225 FOR_ALL_BUFFERS(buf) { 2226 buf->b_p_tw_nopaste = buf->b_p_tw; 2227 buf->b_p_wm_nopaste = buf->b_p_wm; 2228 buf->b_p_sts_nopaste = buf->b_p_sts; 2229 buf->b_p_ai_nopaste = buf->b_p_ai; 2230 buf->b_p_et_nopaste = buf->b_p_et; 2231 if (buf->b_p_vsts_nopaste) { 2232 xfree(buf->b_p_vsts_nopaste); 2233 } 2234 buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_string_option 2235 ? xstrdup(buf->b_p_vsts) 2236 : NULL; 2237 } 2238 2239 // save global options 2240 save_sm = p_sm; 2241 save_sta = p_sta; 2242 save_ru = p_ru; 2243 save_ri = p_ri; 2244 // save global values for local buffer options 2245 p_ai_nopaste = p_ai; 2246 p_et_nopaste = p_et; 2247 p_sts_nopaste = p_sts; 2248 p_tw_nopaste = p_tw; 2249 p_wm_nopaste = p_wm; 2250 if (p_vsts_nopaste) { 2251 xfree(p_vsts_nopaste); 2252 } 2253 p_vsts_nopaste = p_vsts && p_vsts != empty_string_option ? xstrdup(p_vsts) : NULL; 2254 } 2255 2256 // Always set the option values, also when 'paste' is set when it is 2257 // already on. 2258 // set options for each buffer 2259 FOR_ALL_BUFFERS(buf) { 2260 buf->b_p_tw = 0; // textwidth is 0 2261 buf->b_p_wm = 0; // wrapmargin is 0 2262 buf->b_p_sts = 0; // softtabstop is 0 2263 buf->b_p_ai = 0; // no auto-indent 2264 buf->b_p_et = 0; // no expandtab 2265 if (buf->b_p_vsts) { 2266 free_string_option(buf->b_p_vsts); 2267 } 2268 buf->b_p_vsts = empty_string_option; 2269 XFREE_CLEAR(buf->b_p_vsts_array); 2270 } 2271 2272 // set global options 2273 p_sm = 0; // no showmatch 2274 p_sta = 0; // no smarttab 2275 if (p_ru) { 2276 status_redraw_all(); // redraw to remove the ruler 2277 } 2278 p_ru = 0; // no ruler 2279 p_ri = 0; // no reverse insert 2280 // set global values for local buffer options 2281 p_tw = 0; 2282 p_wm = 0; 2283 p_sts = 0; 2284 p_ai = 0; 2285 p_et = 0; 2286 if (p_vsts) { 2287 free_string_option(p_vsts); 2288 } 2289 p_vsts = empty_string_option; 2290 } else if (old_p_paste) { 2291 // Paste switched from on to off: Restore saved values. 2292 2293 // restore options for each buffer 2294 FOR_ALL_BUFFERS(buf) { 2295 buf->b_p_tw = buf->b_p_tw_nopaste; 2296 buf->b_p_wm = buf->b_p_wm_nopaste; 2297 buf->b_p_sts = buf->b_p_sts_nopaste; 2298 buf->b_p_ai = buf->b_p_ai_nopaste; 2299 buf->b_p_et = buf->b_p_et_nopaste; 2300 if (buf->b_p_vsts) { 2301 free_string_option(buf->b_p_vsts); 2302 } 2303 buf->b_p_vsts = buf->b_p_vsts_nopaste ? xstrdup(buf->b_p_vsts_nopaste) : empty_string_option; 2304 xfree(buf->b_p_vsts_array); 2305 if (buf->b_p_vsts && buf->b_p_vsts != empty_string_option) { 2306 tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array); 2307 } else { 2308 buf->b_p_vsts_array = NULL; 2309 } 2310 } 2311 2312 // restore global options 2313 p_sm = save_sm; 2314 p_sta = save_sta; 2315 if (p_ru != save_ru) { 2316 status_redraw_all(); // redraw to draw the ruler 2317 } 2318 p_ru = save_ru; 2319 p_ri = save_ri; 2320 // set global values for local buffer options 2321 p_ai = p_ai_nopaste; 2322 p_et = p_et_nopaste; 2323 p_sts = p_sts_nopaste; 2324 p_tw = p_tw_nopaste; 2325 p_wm = p_wm_nopaste; 2326 if (p_vsts) { 2327 free_string_option(p_vsts); 2328 } 2329 p_vsts = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : empty_string_option; 2330 } 2331 2332 old_p_paste = p_paste; 2333 2334 // Remember where the dependent options were reset 2335 didset_options_sctx((OPT_LOCAL | OPT_GLOBAL), p_paste_dep_opts); 2336 2337 return NULL; 2338 } 2339 2340 /// Process the updated 'previewwindow' option value. 2341 static const char *did_set_previewwindow(optset_T *args) 2342 { 2343 win_T *win = (win_T *)args->os_win; 2344 2345 if (!win->w_p_pvw) { 2346 return NULL; 2347 } 2348 2349 // There can be only one window with 'previewwindow' set. 2350 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 2351 if (wp->w_p_pvw && wp != win) { 2352 win->w_p_pvw = false; 2353 return e_preview_window_already_exists; 2354 } 2355 } 2356 2357 return NULL; 2358 } 2359 2360 /// Process the new 'pumblend' option value. 2361 static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED) 2362 { 2363 hl_invalidate_blends(); 2364 if (pum_drawn()) { 2365 pum_redraw(); 2366 } 2367 2368 return NULL; 2369 } 2370 2371 /// Process the updated 'readonly' option value. 2372 static const char *did_set_readonly(optset_T *args) 2373 { 2374 buf_T *buf = (buf_T *)args->os_buf; 2375 2376 // when 'readonly' is reset globally, also reset readonlymode 2377 if (!buf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) { 2378 readonlymode = false; 2379 } 2380 2381 // when 'readonly' is set may give W10 again 2382 if (buf->b_p_ro) { 2383 buf->b_did_warn = false; 2384 } 2385 2386 redraw_titles(); 2387 2388 return NULL; 2389 } 2390 2391 /// Process the new 'scrollback' option value. 2392 static const char *did_set_scrollback(optset_T *args) 2393 { 2394 buf_T *buf = (buf_T *)args->os_buf; 2395 OptInt old_value = args->os_oldval.number; 2396 OptInt value = args->os_newval.number; 2397 2398 if (buf->terminal && value < old_value) { 2399 // Force the scrollback to take immediate effect only when decreasing it. 2400 on_scrollback_option_changed(buf->terminal); 2401 } 2402 return NULL; 2403 } 2404 2405 /// Process the updated 'scrollbind' option value. 2406 static const char *did_set_scrollbind(optset_T *args) 2407 { 2408 win_T *win = (win_T *)args->os_win; 2409 2410 // when 'scrollbind' is set: snapshot the current position to avoid a jump 2411 // at the end of normal_cmd() 2412 if (!win->w_p_scb) { 2413 return NULL; 2414 } 2415 do_check_scrollbind(false); 2416 win->w_scbind_pos = get_vtopline(win); 2417 return NULL; 2418 } 2419 2420 #ifdef BACKSLASH_IN_FILENAME 2421 /// Process the updated 'shellslash' option value. 2422 static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED) 2423 { 2424 if (p_ssl) { 2425 psepc = '/'; 2426 psepcN = '\\'; 2427 pseps[0] = '/'; 2428 } else { 2429 psepc = '\\'; 2430 psepcN = '/'; 2431 pseps[0] = '\\'; 2432 } 2433 2434 // need to adjust the file name arguments and buffer names. 2435 buflist_slash_adjust(); 2436 alist_slash_adjust(); 2437 scriptnames_slash_adjust(); 2438 return NULL; 2439 } 2440 #endif 2441 2442 /// Process the new 'shiftwidth' or the 'tabstop' option value. 2443 static const char *did_set_shiftwidth_tabstop(optset_T *args) 2444 { 2445 buf_T *buf = (buf_T *)args->os_buf; 2446 win_T *win = (win_T *)args->os_win; 2447 OptInt *pp = (OptInt *)args->os_varp; 2448 2449 if (foldmethodIsIndent(win)) { 2450 foldUpdateAll(win); 2451 } 2452 // When 'shiftwidth' changes, or it's zero and 'tabstop' changes: 2453 // parse 'cinoptions'. 2454 if (pp == &buf->b_p_sw || buf->b_p_sw == 0) { 2455 parse_cino(buf); 2456 } 2457 2458 return NULL; 2459 } 2460 2461 /// Process the new 'showtabline' option value. 2462 static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED) 2463 { 2464 // (re)set tab page line 2465 win_new_screen_rows(); // recompute window positions and heights 2466 return NULL; 2467 } 2468 2469 /// Process the updated 'smoothscroll' option value. 2470 static const char *did_set_smoothscroll(optset_T *args FUNC_ATTR_UNUSED) 2471 { 2472 win_T *win = (win_T *)args->os_win; 2473 if (!win->w_p_sms) { 2474 win->w_skipcol = 0; 2475 } 2476 2477 return NULL; 2478 } 2479 2480 /// Process the updated 'spell' option value. 2481 static const char *did_set_spell(optset_T *args) 2482 { 2483 win_T *win = (win_T *)args->os_win; 2484 if (win->w_p_spell) { 2485 return parse_spelllang(win); 2486 } 2487 2488 return NULL; 2489 } 2490 2491 /// Process the updated 'swapfile' option value. 2492 static const char *did_set_swapfile(optset_T *args) 2493 { 2494 buf_T *buf = (buf_T *)args->os_buf; 2495 // when 'swf' is set, create swapfile, when reset remove swapfile 2496 if (buf->b_p_swf && p_uc) { 2497 ml_open_file(buf); // create the swap file 2498 } else { 2499 // no need to reset buf->b_may_swap, ml_open_file() will check buf->b_p_swf 2500 mf_close_file(buf, true); // remove the swap file 2501 } 2502 return NULL; 2503 } 2504 2505 /// Process the new 'textwidth' option value. 2506 static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED) 2507 { 2508 FOR_ALL_TAB_WINDOWS(tp, wp) { 2509 check_colorcolumn(NULL, wp); 2510 } 2511 2512 return NULL; 2513 } 2514 2515 /// Process the updated 'title' or the 'icon' option value. 2516 static const char *did_set_title_icon(optset_T *args FUNC_ATTR_UNUSED) 2517 { 2518 // when 'title' changed, may need to change the title; same for 'icon' 2519 did_set_title(); 2520 return NULL; 2521 } 2522 2523 /// Process the new 'titlelen' option value. 2524 static const char *did_set_titlelen(optset_T *args) 2525 { 2526 OptInt old_value = args->os_oldval.number; 2527 2528 // if 'titlelen' has changed, redraw the title 2529 if (starting != NO_SCREEN && old_value != p_titlelen) { 2530 need_maketitle = true; 2531 } 2532 2533 return NULL; 2534 } 2535 2536 /// Process the updated 'undofile' option value. 2537 static const char *did_set_undofile(optset_T *args) 2538 { 2539 buf_T *buf = (buf_T *)args->os_buf; 2540 2541 // Only take action when the option was set. 2542 if (!buf->b_p_udf && !p_udf) { 2543 return NULL; 2544 } 2545 2546 // When reset we do not delete the undo file, the option may be set again 2547 // without making any changes in between. 2548 uint8_t hash[UNDO_HASH_SIZE]; 2549 2550 FOR_ALL_BUFFERS(bp) { 2551 // When 'undofile' is set globally: for every buffer, otherwise 2552 // only for the current buffer: Try to read in the undofile, 2553 // if one exists, the buffer wasn't changed and the buffer was 2554 // loaded 2555 if ((buf == bp 2556 || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0) 2557 && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) { 2558 u_compute_hash(bp, hash); 2559 u_read_undo(NULL, hash, bp->b_fname); 2560 } 2561 } 2562 2563 return NULL; 2564 } 2565 2566 /// Process the new global 'undolevels' option value. 2567 const char *did_set_global_undolevels(OptInt value, OptInt old_value) 2568 { 2569 // sync undo before 'undolevels' changes 2570 // use the old value, otherwise u_sync() may not work properly 2571 p_ul = old_value; 2572 u_sync(true); 2573 p_ul = value; 2574 return NULL; 2575 } 2576 2577 /// Process the new buffer local 'undolevels' option value. 2578 const char *did_set_buflocal_undolevels(buf_T *buf, OptInt value, OptInt old_value) 2579 { 2580 // use the old value, otherwise u_sync() may not work properly 2581 buf->b_p_ul = old_value; 2582 u_sync(true); 2583 buf->b_p_ul = value; 2584 return NULL; 2585 } 2586 2587 /// Process the new 'undolevels' option value. 2588 static const char *did_set_undolevels(optset_T *args) 2589 { 2590 buf_T *buf = (buf_T *)args->os_buf; 2591 OptInt *pp = (OptInt *)args->os_varp; 2592 2593 if (pp == &p_ul) { // global 'undolevels' 2594 did_set_global_undolevels(args->os_newval.number, args->os_oldval.number); 2595 } else if (pp == &buf->b_p_ul) { // buffer local 'undolevels' 2596 did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number); 2597 } 2598 2599 return NULL; 2600 } 2601 2602 /// Process the new 'updatecount' option value. 2603 static const char *did_set_updatecount(optset_T *args) 2604 { 2605 OptInt old_value = args->os_oldval.number; 2606 2607 // when 'updatecount' changes from zero to non-zero, open swap files 2608 if (p_uc && !old_value) { 2609 ml_open_files(); 2610 } 2611 2612 return NULL; 2613 } 2614 2615 /// Process the new 'wildchar' / 'wildcharm' option value. 2616 static const char *did_set_wildchar(optset_T *args) 2617 { 2618 OptInt c = *(OptInt *)args->os_varp; 2619 2620 // Don't allow key values that wouldn't work as wildchar. 2621 if (c == Ctrl_C || c == '\n' || c == '\r' || c == K_KENTER) { 2622 return e_invarg; 2623 } 2624 2625 return NULL; 2626 } 2627 2628 /// Process the new 'winblend' option value. 2629 static const char *did_set_winblend(optset_T *args) 2630 { 2631 win_T *win = (win_T *)args->os_win; 2632 OptInt old_value = args->os_oldval.number; 2633 OptInt value = args->os_newval.number; 2634 2635 if (value != old_value) { 2636 win->w_p_winbl = MAX(MIN(win->w_p_winbl, 100), 0); 2637 win->w_hl_needs_update = true; 2638 check_blending(win); 2639 } 2640 2641 return NULL; 2642 } 2643 2644 /// Process the new 'window' option value. 2645 static const char *did_set_window(optset_T *args FUNC_ATTR_UNUSED) 2646 { 2647 if (p_window < 1) { 2648 p_window = Rows - 1; 2649 } else if (p_window >= Rows) { 2650 p_window = Rows - 1; 2651 } 2652 return NULL; 2653 } 2654 2655 /// Process the new 'winheight' value. 2656 static const char *did_set_winheight(optset_T *args) 2657 { 2658 // Change window height NOW 2659 if (!ONE_WINDOW) { 2660 if (curwin->w_height < p_wh) { 2661 win_setheight((int)p_wh); 2662 } 2663 } 2664 2665 return NULL; 2666 } 2667 2668 /// Process the new 'winwidth' option value. 2669 static const char *did_set_winwidth(optset_T *args) 2670 { 2671 if (!ONE_WINDOW && curwin->w_width < p_wiw) { 2672 win_setwidth((int)p_wiw); 2673 } 2674 return NULL; 2675 } 2676 2677 /// Process the updated 'wrap' option value. 2678 static const char *did_set_wrap(optset_T *args) 2679 { 2680 win_T *win = (win_T *)args->os_win; 2681 // Set w_leftcol or w_skipcol to zero. 2682 if (win->w_p_wrap) { 2683 win->w_leftcol = 0; 2684 } else { 2685 win->w_skipcol = 0; 2686 } 2687 2688 return NULL; 2689 } 2690 2691 /// Process the new 'chistory' or 'lhistory' option value. 'chistory' will 2692 /// be used if args->os_varp is the same as p_chi, else 'lhistory'. 2693 static const char *did_set_xhistory(optset_T *args) 2694 { 2695 win_T *win = (win_T *)args->os_win; 2696 bool is_p_chi = (OptInt *)args->os_varp == &p_chi; 2697 OptInt *arg = is_p_chi ? &p_chi : (OptInt *)args->os_varp; 2698 2699 if (is_p_chi) { 2700 qf_resize_stack((int)(*arg)); 2701 } else { 2702 ll_resize_stack(win, (int)(*arg)); 2703 } 2704 2705 return NULL; 2706 } 2707 2708 // When 'syntax' is set, load the syntax of that name 2709 static void do_syntax_autocmd(buf_T *buf, bool value_changed) 2710 { 2711 static int syn_recursive = 0; 2712 2713 syn_recursive++; 2714 buf->b_flags |= BF_SYN_SET; 2715 // Only pass true for "force" when the value changed or not used 2716 // recursively, to avoid endless recurrence. 2717 apply_autocmds(EVENT_SYNTAX, buf->b_p_syn, buf->b_fname, 2718 value_changed || syn_recursive == 1, buf); 2719 syn_recursive--; 2720 } 2721 2722 static void do_spelllang_source(win_T *win) 2723 { 2724 char fname[200]; 2725 char *q = win->w_s->b_p_spl; 2726 2727 // Skip the first name if it is "cjk". 2728 if (strncmp(q, "cjk,", 4) == 0) { 2729 q += 4; 2730 } 2731 2732 // Source the spell/LANG.{vim,lua} in 'runtimepath'. 2733 // They could set 'spellcapcheck' depending on the language. 2734 // Use the first name in 'spelllang' up to '_region' or 2735 // '.encoding'. 2736 char *p; 2737 for (p = q; *p != NUL; p++) { 2738 if (!ASCII_ISALNUM(*p) && *p != '-') { 2739 break; 2740 } 2741 } 2742 if (p > q) { 2743 vim_snprintf(fname, sizeof(fname), "spell/%.*s.*", (int)(p - q), q); 2744 source_runtime_vim_lua(fname, DIP_ALL); 2745 } 2746 } 2747 2748 /// Check the bounds of numeric options. 2749 /// 2750 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 2751 /// @param[in,out] newval Pointer to new option value. Will be set to bound checked value. 2752 /// @param[out] errbuf Buffer for error message. Cannot be NULL. 2753 /// @param errbuflen Length of error buffer. 2754 /// 2755 /// @return Error message, if any. 2756 static const char *check_num_option_bounds(OptIndex opt_idx, OptInt *newval, char *errbuf, 2757 size_t errbuflen) 2758 FUNC_ATTR_NONNULL_ARG(3) 2759 { 2760 const char *errmsg = NULL; 2761 2762 switch (opt_idx) { 2763 case kOptLines: 2764 if (*newval < min_rows_for_all_tabpages() && full_screen) { 2765 vim_snprintf(errbuf, errbuflen, _("E593: Need at least %d lines"), 2766 min_rows_for_all_tabpages()); 2767 errmsg = errbuf; 2768 *newval = min_rows_for_all_tabpages(); 2769 } 2770 // True max size is defined by check_screensize(). 2771 *newval = MIN(*newval, INT_MAX); 2772 break; 2773 case kOptColumns: 2774 if (*newval < MIN_COLUMNS && full_screen) { 2775 vim_snprintf(errbuf, errbuflen, _("E594: Need at least %d columns"), MIN_COLUMNS); 2776 errmsg = errbuf; 2777 *newval = MIN_COLUMNS; 2778 } 2779 // True max size is defined by check_screensize(). 2780 *newval = MIN(*newval, INT_MAX); 2781 break; 2782 case kOptPumblend: 2783 *newval = MAX(MIN(*newval, 100), 0); 2784 break; 2785 case kOptScrolljump: 2786 if ((*newval < -100 || *newval >= Rows) && full_screen) { 2787 errmsg = e_scroll; 2788 *newval = 1; 2789 } 2790 break; 2791 case kOptScroll: 2792 if ((*newval <= 0 || (*newval > curwin->w_view_height && curwin->w_view_height > 0)) 2793 && full_screen) { 2794 if (*newval != 0) { 2795 errmsg = e_scroll; 2796 } 2797 *newval = win_default_scroll(curwin); 2798 } 2799 break; 2800 default: 2801 break; 2802 } 2803 2804 return errmsg; 2805 } 2806 2807 /// Validate and bound check option value. 2808 /// 2809 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 2810 /// @param[in,out] newval Pointer to new option value. Will be set to bound checked value. 2811 /// @param[out] errbuf Buffer for error message. Cannot be NULL. 2812 /// @param errbuflen Length of error buffer. 2813 /// 2814 /// @return Error message, if any. 2815 static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *errbuf, 2816 size_t errbuflen) 2817 { 2818 OptInt value = *newval; 2819 2820 // Many number options assume their value is in the signed int range. 2821 if (value < INT_MIN || value > INT_MAX) { 2822 return e_invarg; 2823 } 2824 2825 // if you increase this, also increase SEARCH_STAT_BUF_LEN in search.c 2826 enum { MAX_SEARCH_COUNT = 9999, }; 2827 2828 switch (opt_idx) { 2829 case kOptHelpheight: 2830 case kOptTitlelen: 2831 case kOptUpdatecount: 2832 case kOptReport: 2833 case kOptUpdatetime: 2834 case kOptSidescroll: 2835 case kOptFoldlevel: 2836 case kOptShiftwidth: 2837 case kOptTextwidth: 2838 case kOptWritedelay: 2839 case kOptTimeoutlen: 2840 if (value < 0) { 2841 return e_positive; 2842 } 2843 break; 2844 case kOptWinheight: 2845 if (value < 1) { 2846 return e_positive; 2847 } else if (p_wmh > value) { 2848 return e_winheight; 2849 } 2850 break; 2851 case kOptWinminheight: 2852 if (value < 0) { 2853 return e_positive; 2854 } else if (value > p_wh) { 2855 return e_winheight; 2856 } 2857 break; 2858 case kOptWinwidth: 2859 if (value < 1) { 2860 return e_positive; 2861 } else if (p_wmw > value) { 2862 return e_winwidth; 2863 } 2864 break; 2865 case kOptWinminwidth: 2866 if (value < 0) { 2867 return e_positive; 2868 } else if (value > p_wiw) { 2869 return e_winwidth; 2870 } 2871 break; 2872 case kOptMaxcombine: 2873 *newval = MAX_MCO; 2874 break; 2875 case kOptCmdheight: 2876 if (value < 0) { 2877 return e_positive; 2878 } 2879 break; 2880 case kOptHistory: 2881 if (value < 0) { 2882 return e_positive; 2883 } else if (value > 10000) { 2884 return e_invarg; 2885 } 2886 break; 2887 case kOptPyxversion: 2888 if (value == 0) { 2889 *newval = 3; 2890 } else if (value != 3) { 2891 return e_invarg; 2892 } 2893 break; 2894 case kOptRegexpengine: 2895 if (value < 0 || value > 2) { 2896 return e_invarg; 2897 } 2898 break; 2899 case kOptScrolloff: 2900 if (value < 0 && full_screen) { 2901 return e_positive; 2902 } 2903 break; 2904 case kOptSidescrolloff: 2905 if (value < 0 && full_screen) { 2906 return e_positive; 2907 } 2908 break; 2909 case kOptCmdwinheight: 2910 if (value < 1) { 2911 return e_positive; 2912 } 2913 break; 2914 case kOptConceallevel: 2915 if (value < 0) { 2916 return e_positive; 2917 } else if (value > 3) { 2918 return e_invarg; 2919 } 2920 break; 2921 case kOptNumberwidth: 2922 if (value < 1) { 2923 return e_positive; 2924 } else if (value > MAX_NUMBERWIDTH) { 2925 return e_invarg; 2926 } 2927 break; 2928 case kOptIminsert: 2929 if (value < 0 || value > B_IMODE_LAST) { 2930 return e_invarg; 2931 } 2932 break; 2933 case kOptImsearch: 2934 if (value < -1 || value > B_IMODE_LAST) { 2935 return e_invarg; 2936 } 2937 break; 2938 case kOptChannel: 2939 return e_invarg; 2940 case kOptScrollback: 2941 if (value < -1 || value > SB_MAX) { 2942 return e_invarg; 2943 } 2944 break; 2945 case kOptTabstop: 2946 if (value < 1) { 2947 return e_positive; 2948 } else if (value > TABSTOP_MAX) { 2949 return e_invarg; 2950 } 2951 break; 2952 case kOptChistory: 2953 case kOptLhistory: 2954 if (value < 1) { 2955 return e_cannot_have_negative_or_zero_number_of_quickfix; 2956 } else if (value > 100) { 2957 return e_cannot_have_more_than_hundred_quickfix; 2958 } 2959 break; 2960 case kOptMaxsearchcount: 2961 if (value <= 0) { 2962 return e_positive; 2963 } else if (value > MAX_SEARCH_COUNT) { 2964 return e_invarg; 2965 } 2966 break; 2967 default: 2968 break; 2969 } 2970 2971 return check_num_option_bounds(opt_idx, newval, errbuf, errbuflen); 2972 } 2973 2974 /// Called after an option changed: check if something needs to be redrawn. 2975 void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags) 2976 { 2977 // Careful: kOptFlagRedrAll is a combination of other redraw flags 2978 bool all = (flags & kOptFlagRedrAll) == kOptFlagRedrAll; 2979 2980 if ((flags & kOptFlagRedrStat) || all) { // mark all status lines and window bars dirty 2981 status_redraw_all(); 2982 } 2983 2984 if ((flags & kOptFlagRedrTabl) || all) { // mark tablines dirty 2985 redraw_tabline = true; 2986 } 2987 2988 if ((flags & kOptFlagRedrBuf) || (flags & kOptFlagRedrWin) || all) { 2989 if (flags & kOptFlagHLOnly) { 2990 redraw_later(win, UPD_NOT_VALID); 2991 } else { 2992 changed_window_setting(win); 2993 } 2994 } 2995 if (flags & kOptFlagRedrBuf) { 2996 redraw_buf_later(buf, UPD_NOT_VALID); 2997 } 2998 if (all) { 2999 redraw_all_later(UPD_NOT_VALID); 3000 } 3001 } 3002 3003 void check_redraw(uint32_t flags) 3004 { 3005 check_redraw_for(curbuf, curwin, flags); 3006 } 3007 3008 bool is_tty_option(const char *name) 3009 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3010 { 3011 return find_tty_option_end(name) != NULL; 3012 } 3013 3014 /// Get value of TTY option. 3015 /// 3016 /// @param name Name of TTY option. 3017 /// 3018 /// @return [allocated] TTY option value. Returns NIL_OPTVAL if option isn't a TTY option. 3019 OptVal get_tty_option(const char *name) 3020 { 3021 char *value = NULL; 3022 3023 if (strequal(name, "t_Co")) { 3024 if (t_colors <= 1) { 3025 value = xstrdup(""); 3026 } else { 3027 value = xmalloc(NUMBUFLEN); 3028 snprintf(value, NUMBUFLEN, "%d", t_colors); 3029 } 3030 } else if (strequal(name, "term")) { 3031 value = p_term ? xstrdup(p_term) : xstrdup("nvim"); 3032 } else if (strequal(name, "ttytype")) { 3033 value = p_ttytype ? xstrdup(p_ttytype) : xstrdup("nvim"); 3034 } else if (is_tty_option(name)) { 3035 // XXX: All other t_* options were removed in 3baba1e7. 3036 value = xstrdup(""); 3037 } 3038 3039 return value == NULL ? NIL_OPTVAL : CSTR_AS_OPTVAL(value); 3040 } 3041 3042 bool set_tty_option(const char *name, char *value) 3043 { 3044 if (strequal(name, "term")) { 3045 if (p_term) { 3046 xfree(p_term); 3047 } 3048 p_term = value; 3049 return true; 3050 } 3051 3052 if (strequal(name, "ttytype")) { 3053 if (p_ttytype) { 3054 xfree(p_ttytype); 3055 } 3056 p_ttytype = value; 3057 return true; 3058 } 3059 3060 return false; 3061 } 3062 3063 /// Find index for an option. Don't go beyond `len` length. 3064 /// 3065 /// @param[in] name Option name. 3066 /// @param len Option name length. 3067 /// 3068 /// @return Option index or kOptInvalid if option was not found. 3069 OptIndex find_option_len(const char *const name, size_t len) 3070 FUNC_ATTR_NONNULL_ALL 3071 { 3072 int index = find_option_hash(name, len); 3073 return index >= 0 ? option_hash_elems[index].opt_idx : kOptInvalid; 3074 } 3075 3076 /// Find index for an option. 3077 /// 3078 /// @param[in] name Option name. 3079 /// 3080 /// @return Option index or kOptInvalid if option was not found. 3081 OptIndex find_option(const char *const name) 3082 FUNC_ATTR_NONNULL_ALL 3083 { 3084 return find_option_len(name, strlen(name)); 3085 } 3086 3087 /// Free an allocated OptVal. 3088 void optval_free(OptVal o) 3089 { 3090 switch (o.type) { 3091 case kOptValTypeNil: 3092 case kOptValTypeBoolean: 3093 case kOptValTypeNumber: 3094 break; 3095 case kOptValTypeString: 3096 // Don't free empty string option 3097 if (o.data.string.data != empty_string_option) { 3098 api_free_string(o.data.string); 3099 } 3100 break; 3101 } 3102 } 3103 3104 /// Copy an OptVal. 3105 OptVal optval_copy(OptVal o) 3106 { 3107 switch (o.type) { 3108 case kOptValTypeNil: 3109 case kOptValTypeBoolean: 3110 case kOptValTypeNumber: 3111 return o; 3112 case kOptValTypeString: 3113 return STRING_OPTVAL(copy_string(o.data.string, NULL)); 3114 } 3115 UNREACHABLE; 3116 } 3117 3118 /// Check if two option values are equal. 3119 bool optval_equal(OptVal o1, OptVal o2) 3120 { 3121 if (o1.type != o2.type) { 3122 return false; 3123 } 3124 3125 switch (o1.type) { 3126 case kOptValTypeNil: 3127 return true; 3128 case kOptValTypeBoolean: 3129 return o1.data.boolean == o2.data.boolean; 3130 case kOptValTypeNumber: 3131 return o1.data.number == o2.data.number; 3132 case kOptValTypeString: 3133 return o1.data.string.size == o2.data.string.size 3134 && (o1.data.string.data == o2.data.string.data 3135 || strnequal(o1.data.string.data, o2.data.string.data, o1.data.string.size)); 3136 } 3137 UNREACHABLE; 3138 } 3139 3140 /// Get type of option. 3141 static OptValType option_get_type(const OptIndex opt_idx) 3142 { 3143 return options[opt_idx].type; 3144 } 3145 3146 /// Create OptVal from var pointer. 3147 /// 3148 /// @param opt_idx Option index in options[] table. 3149 /// @param[out] varp Pointer to option variable. 3150 /// 3151 /// @return Option value stored in varp. 3152 OptVal optval_from_varp(OptIndex opt_idx, void *varp) 3153 FUNC_ATTR_NONNULL_ARG(2) 3154 { 3155 // Special case: 'modified' is b_changed, but we also want to consider it set when 'ff' or 'fenc' 3156 // changed. 3157 if ((int *)varp == &curbuf->b_changed) { 3158 return BOOLEAN_OPTVAL(curbufIsChanged()); 3159 } 3160 3161 OptValType type = option_get_type(opt_idx); 3162 3163 switch (type) { 3164 case kOptValTypeNil: 3165 return NIL_OPTVAL; 3166 case kOptValTypeBoolean: 3167 return BOOLEAN_OPTVAL(TRISTATE_FROM_INT(*(int *)varp)); 3168 case kOptValTypeNumber: 3169 return NUMBER_OPTVAL(*(OptInt *)varp); 3170 case kOptValTypeString: 3171 return STRING_OPTVAL(cstr_as_string(*(char **)varp)); 3172 } 3173 UNREACHABLE; 3174 } 3175 3176 /// Set option var pointer value from OptVal. 3177 /// 3178 /// @param opt_idx Option index in options[] table. 3179 /// @param[out] varp Pointer to option variable. 3180 /// @param[in] value New option value. 3181 /// @param free_oldval Free old value. 3182 static void set_option_varp(OptIndex opt_idx, void *varp, OptVal value, bool free_oldval) 3183 FUNC_ATTR_NONNULL_ARG(2) 3184 { 3185 assert(option_has_type(opt_idx, value.type)); 3186 3187 if (free_oldval) { 3188 optval_free(optval_from_varp(opt_idx, varp)); 3189 } 3190 3191 switch (value.type) { 3192 case kOptValTypeNil: 3193 abort(); 3194 case kOptValTypeBoolean: 3195 *(int *)varp = value.data.boolean; 3196 return; 3197 case kOptValTypeNumber: 3198 *(OptInt *)varp = value.data.number; 3199 return; 3200 case kOptValTypeString: 3201 *(char **)varp = value.data.string.data; 3202 return; 3203 } 3204 UNREACHABLE; 3205 } 3206 3207 /// Return C-string representation of OptVal. Caller must free the returned C-string. 3208 static char *optval_to_cstr(OptVal o) 3209 { 3210 switch (o.type) { 3211 case kOptValTypeNil: 3212 return xstrdup(""); 3213 case kOptValTypeBoolean: 3214 return xstrdup(o.data.boolean ? "true" : "false"); 3215 case kOptValTypeNumber: { 3216 char *buf = xmalloc(NUMBUFLEN); 3217 snprintf(buf, NUMBUFLEN, "%" PRId64, o.data.number); 3218 return buf; 3219 } 3220 case kOptValTypeString: { 3221 char *buf = xmalloc(o.data.string.size + 3); 3222 snprintf(buf, o.data.string.size + 3, "\"%s\"", o.data.string.data); 3223 return buf; 3224 } 3225 } 3226 UNREACHABLE; 3227 } 3228 3229 /// Convert an OptVal to an API Object. 3230 Object optval_as_object(OptVal o) 3231 { 3232 switch (o.type) { 3233 case kOptValTypeNil: 3234 return NIL; 3235 case kOptValTypeBoolean: 3236 switch (o.data.boolean) { 3237 case kFalse: 3238 case kTrue: 3239 return BOOLEAN_OBJ(o.data.boolean); 3240 case kNone: 3241 return NIL; 3242 } 3243 UNREACHABLE; 3244 case kOptValTypeNumber: 3245 return INTEGER_OBJ(o.data.number); 3246 case kOptValTypeString: 3247 return STRING_OBJ(o.data.string); 3248 } 3249 UNREACHABLE; 3250 } 3251 3252 /// Convert an API Object to an OptVal. 3253 OptVal object_as_optval(Object o, bool *error) 3254 { 3255 switch (o.type) { 3256 case kObjectTypeNil: 3257 return NIL_OPTVAL; 3258 case kObjectTypeBoolean: 3259 return BOOLEAN_OPTVAL(o.data.boolean); 3260 case kObjectTypeInteger: 3261 return NUMBER_OPTVAL((OptInt)o.data.integer); 3262 case kObjectTypeString: 3263 return STRING_OPTVAL(o.data.string); 3264 default: 3265 *error = true; 3266 return NIL_OPTVAL; 3267 } 3268 UNREACHABLE; 3269 } 3270 3271 /// Check if option is hidden. 3272 /// 3273 /// @param opt_idx Option index in options[] table. 3274 /// 3275 /// @return True if option is hidden, false otherwise. Returns false if option name is invalid. 3276 bool is_option_hidden(OptIndex opt_idx) 3277 { 3278 // Hidden options are always immutable and point to their default value 3279 return opt_idx != kOptInvalid && options[opt_idx].immutable 3280 && options[opt_idx].var == &options[opt_idx].def_val.data; 3281 } 3282 3283 /// Check if option supports a specific type. 3284 bool option_has_type(OptIndex opt_idx, OptValType type) 3285 { 3286 return opt_idx != kOptInvalid && options[opt_idx].type == type; 3287 } 3288 3289 /// Check if option supports a specific scope. 3290 bool option_has_scope(OptIndex opt_idx, OptScope scope) 3291 { 3292 // Ensure that scope flags variable can hold all scopes. 3293 STATIC_ASSERT(kOptScopeSize <= sizeof(OptScopeFlags) * 8, 3294 "Option scope_flags cannot fit all option scopes"); 3295 // Ensure that the scope is valid before accessing scope_flags. 3296 assert(scope >= kOptScopeGlobal && scope < kOptScopeSize); 3297 // Bitshift 1 by the value of scope to get the scope's corresponding flag, and check if it's set 3298 // in the scope_flags bit field. 3299 return get_option(opt_idx)->scope_flags & (1 << scope); 3300 } 3301 3302 /// Check if option is global-local. 3303 static inline bool option_is_global_local(OptIndex opt_idx) 3304 { 3305 // Global-local options have at least two types, so their type flag cannot be a power of two. 3306 return opt_idx != kOptInvalid && !is_power_of_two(options[opt_idx].scope_flags); 3307 } 3308 3309 /// Check if option only supports global scope. 3310 static inline bool option_is_global_only(OptIndex opt_idx) 3311 { 3312 // For an option to be global-only, it has to only have a single scope, which means the scope 3313 // flags must be a power of two, and it must have the global scope. 3314 return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags) 3315 && option_has_scope(opt_idx, kOptScopeGlobal); 3316 } 3317 3318 /// Check if option only supports window scope. 3319 static inline bool option_is_window_local(OptIndex opt_idx) 3320 { 3321 // For an option to be window-local it has to only have a single scope, which means the scope 3322 // flags must be a power of two, and it must have the window scope. 3323 return opt_idx != kOptInvalid && is_power_of_two(options[opt_idx].scope_flags) 3324 && option_has_scope(opt_idx, kOptScopeWin); 3325 } 3326 3327 /// Get option index for scope. 3328 ssize_t option_scope_idx(OptIndex opt_idx, OptScope scope) 3329 { 3330 return options[opt_idx].scope_idx[scope]; 3331 } 3332 3333 /// Get option flags. 3334 /// 3335 /// @param opt_idx Option index in options[] table. 3336 /// 3337 /// @return Option flags. Returns 0 for invalid option name. 3338 uint32_t get_option_flags(OptIndex opt_idx) 3339 { 3340 return opt_idx == kOptInvalid ? 0 : options[opt_idx].flags; 3341 } 3342 3343 /// Gets the value for an option. 3344 /// 3345 /// @param opt_idx Option index in options[] table. 3346 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3347 /// 3348 /// @return [allocated] Option value. Returns NIL_OPTVAL for invalid option index. 3349 OptVal get_option_value(OptIndex opt_idx, int opt_flags) 3350 { 3351 if (opt_idx == kOptInvalid) { // option not in the options[] table. 3352 return NIL_OPTVAL; 3353 } 3354 3355 vimoption_T *opt = &options[opt_idx]; 3356 void *varp = get_varp_scope(opt, opt_flags); 3357 3358 return optval_copy(optval_from_varp(opt_idx, varp)); 3359 } 3360 3361 /// Return information for option at 'opt_idx' 3362 vimoption_T *get_option(OptIndex opt_idx) 3363 { 3364 assert(opt_idx != kOptInvalid); 3365 return &options[opt_idx]; 3366 } 3367 3368 /// Get option value that represents an unset local value for an option. 3369 /// TODO(famiu): Remove this once we have a dedicated OptVal type for unset local options. 3370 /// 3371 /// @param opt_idx Option index in options[] table. 3372 /// @param[in] varp Pointer to option variable. 3373 /// 3374 /// @return Option value equal to the unset value for the option. 3375 static OptVal get_option_unset_value(OptIndex opt_idx) 3376 { 3377 assert(opt_idx != kOptInvalid); 3378 vimoption_T *opt = &options[opt_idx]; 3379 3380 // For global-local options, use the unset value of the local value. 3381 if (option_is_global_local(opt_idx)) { 3382 // String global-local options always use an empty string for the unset value. 3383 if (option_has_type(opt_idx, kOptValTypeString)) { 3384 return STATIC_CSTR_AS_OPTVAL(""); 3385 } 3386 3387 switch (opt_idx) { 3388 case kOptAutocomplete: 3389 case kOptAutoread: 3390 case kOptFsync: 3391 return BOOLEAN_OPTVAL(kNone); 3392 case kOptScrolloff: 3393 case kOptSidescrolloff: 3394 return NUMBER_OPTVAL(-1); 3395 case kOptUndolevels: 3396 return NUMBER_OPTVAL(NO_LOCAL_UNDOLEVEL); 3397 default: 3398 abort(); 3399 } 3400 } 3401 3402 // For options that aren't global-local, use the global value to represent an unset local value. 3403 return optval_from_varp(opt_idx, get_varp_scope(opt, OPT_GLOBAL)); 3404 } 3405 3406 /// Check if local value of global-local option is unset for current buffer / window. 3407 /// Always returns false for options that aren't global-local. 3408 /// 3409 /// TODO(famiu): Remove this once we have an OptVal type to indicate an unset local value. 3410 static bool is_option_local_value_unset(OptIndex opt_idx) 3411 { 3412 vimoption_T *opt = get_option(opt_idx); 3413 3414 // Local value of option that isn't global-local is always considered set. 3415 if (!option_is_global_local(opt_idx)) { 3416 return false; 3417 } 3418 3419 void *varp_local = get_varp_scope(opt, OPT_LOCAL); 3420 OptVal local_value = optval_from_varp(opt_idx, varp_local); 3421 OptVal unset_local_value = get_option_unset_value(opt_idx); 3422 3423 return optval_equal(local_value, unset_local_value); 3424 } 3425 3426 /// Handle side-effects of setting an option. 3427 /// 3428 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 3429 /// @param[in] varp Option variable pointer, cannot be NULL. 3430 /// @param old_value Old option value. 3431 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3432 /// @param set_sid Script ID. Special values: 3433 /// 0: Use current script ID. 3434 /// SID_NONE: Don't set script ID. 3435 /// @param direct Don't process side-effects. 3436 /// @param value_replaced Value was replaced completely. 3437 /// @param[out] errbuf Buffer for error message. 3438 /// @param errbuflen Length of error buffer. 3439 /// 3440 /// @return NULL on success, an untranslated error message on error. 3441 static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value, OptVal new_value, 3442 int opt_flags, scid_T set_sid, const bool direct, 3443 const bool value_replaced, char *errbuf, size_t errbuflen) 3444 { 3445 vimoption_T *opt = &options[opt_idx]; 3446 const char *errmsg = NULL; 3447 bool restore_chartab = false; 3448 bool value_changed = false; 3449 bool value_checked = false; 3450 3451 optset_T did_set_cb_args = { 3452 .os_varp = varp, 3453 .os_idx = opt_idx, 3454 .os_flags = opt_flags, 3455 .os_oldval = old_value.data, 3456 .os_newval = new_value.data, 3457 .os_value_checked = false, 3458 .os_value_changed = false, 3459 .os_restore_chartab = false, 3460 .os_errbuf = errbuf, 3461 .os_errbuflen = errbuflen, 3462 .os_buf = curbuf, 3463 .os_win = curwin, 3464 }; 3465 3466 if (direct) { 3467 // Don't do any extra processing if setting directly. 3468 } 3469 // Disallow changing immutable options. 3470 else if (opt->immutable && !optval_equal(old_value, new_value)) { 3471 errmsg = e_unsupportedoption; 3472 } 3473 // Disallow changing some options from secure mode. 3474 else if ((secure || sandbox != 0) && (opt->flags & kOptFlagSecure)) { 3475 errmsg = e_secure; 3476 } 3477 // Check for a "normal" directory or file name in some string options. 3478 else if (new_value.type == kOptValTypeString 3479 && check_illegal_path_names(*(char **)varp, opt->flags)) { 3480 errmsg = e_invarg; 3481 } else if (opt->opt_did_set_cb != NULL) { 3482 // Invoke the option specific callback function to validate and apply the new value. 3483 errmsg = opt->opt_did_set_cb(&did_set_cb_args); 3484 // The 'filetype' and 'syntax' option callback functions may change the os_value_changed field. 3485 value_changed = did_set_cb_args.os_value_changed; 3486 // The 'keymap', 'filetype' and 'syntax' option callback functions may change the 3487 // os_value_checked field. 3488 value_checked = did_set_cb_args.os_value_checked; 3489 // The 'isident', 'iskeyword', 'isprint' and 'isfname' options may change the character table. 3490 // On failure, this needs to be restored. 3491 restore_chartab = did_set_cb_args.os_restore_chartab; 3492 } 3493 3494 // If option is hidden or if an error is detected, restore the previous value and don't do any 3495 // further processing. 3496 if (errmsg != NULL) { 3497 set_option_varp(opt_idx, varp, old_value, true); 3498 // When resetting some values, need to act on it. 3499 if (restore_chartab) { 3500 buf_init_chartab(curbuf, true); 3501 } 3502 3503 return errmsg; 3504 } 3505 3506 // Re-assign the new value as its value may get freed or modified by the option callback. 3507 new_value = optval_from_varp(opt_idx, varp); 3508 3509 if (set_sid != SID_NONE) { 3510 sctx_T script_ctx = set_sid == 0 ? current_sctx : (sctx_T){ .sc_sid = set_sid }; 3511 // Remember where the option was set. 3512 set_option_sctx(opt_idx, opt_flags, script_ctx); 3513 } 3514 3515 optval_free(old_value); 3516 3517 const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; 3518 3519 if (scope_both) { 3520 if (option_is_global_local(opt_idx)) { 3521 // Global option with local value set to use global value. 3522 // Free the local value and clear it. 3523 void *varp_local = get_varp_scope(opt, OPT_LOCAL); 3524 OptVal local_unset_value = get_option_unset_value(opt_idx); 3525 set_option_varp(opt_idx, varp_local, optval_copy(local_unset_value), true); 3526 } else { 3527 // May set global value for local option. 3528 void *varp_global = get_varp_scope(opt, OPT_GLOBAL); 3529 set_option_varp(opt_idx, varp_global, optval_copy(new_value), true); 3530 } 3531 } 3532 3533 // Don't do anything else if setting the option directly. 3534 if (direct) { 3535 return errmsg; 3536 } 3537 3538 // Trigger the autocommand only after setting the flags. 3539 if (varp == &curbuf->b_p_syn) { 3540 do_syntax_autocmd(curbuf, value_changed); 3541 } else if (varp == &curbuf->b_p_ft) { 3542 // 'filetype' is set, trigger the FileType autocommand 3543 // Skip this when called from a modeline 3544 // Force autocmd when the filetype was changed 3545 if (!(opt_flags & OPT_MODELINE) || value_changed) { 3546 do_filetype_autocmd(curbuf, value_changed); 3547 } 3548 } else if (varp == &curwin->w_s->b_p_spl) { 3549 do_spelllang_source(curwin); 3550 } 3551 3552 // In case 'ruler' or 'showcmd' or 'columns' or 'ls' changed. 3553 comp_col(); 3554 3555 if (varp == &p_mouse) { 3556 setmouse(); // in case 'mouse' changed 3557 } else if ((varp == &p_flp || varp == &(curbuf->b_p_flp)) && curwin->w_briopt_list) { 3558 // Changing Formatlistpattern when briopt includes the list setting: 3559 // redraw 3560 redraw_all_later(UPD_NOT_VALID); 3561 } else if (varp == &p_wbr || varp == &(curwin->w_p_wbr)) { 3562 // add / remove window bars for 'winbar' 3563 set_winbar(true); 3564 } 3565 3566 if (curwin->w_curswant != MAXCOL 3567 && (opt->flags & (kOptFlagCurswant | kOptFlagRedrAll)) != 0 3568 && (opt->flags & kOptFlagHLOnly) == 0) { 3569 curwin->w_set_curswant = true; 3570 } 3571 3572 check_redraw(opt->flags); 3573 3574 if (errmsg == NULL) { 3575 opt->flags |= kOptFlagWasSet; 3576 3577 uint32_t *flagsp = insecure_flag(curwin, opt_idx, opt_flags); 3578 uint32_t *flagsp_local = scope_both ? insecure_flag(curwin, opt_idx, OPT_LOCAL) : NULL; 3579 // When an option is set in the sandbox, from a modeline or in secure mode set the 3580 // kOptFlagInsecure flag. Otherwise, if a new value is stored reset the flag. 3581 if (!value_checked && (secure || sandbox != 0 || (opt_flags & OPT_MODELINE))) { 3582 *flagsp |= kOptFlagInsecure; 3583 if (flagsp_local != NULL) { 3584 *flagsp_local |= kOptFlagInsecure; 3585 } 3586 } else if (value_replaced) { 3587 *flagsp &= ~(unsigned)kOptFlagInsecure; 3588 if (flagsp_local != NULL) { 3589 *flagsp_local &= ~(unsigned)kOptFlagInsecure; 3590 } 3591 } 3592 } 3593 3594 return errmsg; 3595 } 3596 3597 /// Validate the new value for an option. 3598 /// 3599 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 3600 /// @param newval[in,out] New option value. Might be modified. 3601 static const char *validate_option_value(const OptIndex opt_idx, OptVal *newval, int opt_flags, 3602 char *errbuf, size_t errbuflen) 3603 { 3604 const char *errmsg = NULL; 3605 vimoption_T *opt = &options[opt_idx]; 3606 3607 // Always allow unsetting local value of global-local option. 3608 if (option_is_global_local(opt_idx) && (opt_flags & OPT_LOCAL) 3609 && optval_equal(*newval, get_option_unset_value(opt_idx))) { 3610 return NULL; 3611 } 3612 3613 if (newval->type == kOptValTypeNil) { 3614 // Don't try to unset local value if scope is global. 3615 // TODO(famiu): Change this to forbid changing all non-local scopes when the API scope bug is 3616 // fixed. 3617 if (opt_flags == OPT_GLOBAL) { 3618 errmsg = _("Cannot unset global option value"); 3619 } else { 3620 *newval = optval_copy(get_option_unset_value(opt_idx)); 3621 } 3622 } else if (!option_has_type(opt_idx, newval->type)) { 3623 char *rep = optval_to_cstr(*newval); 3624 const char *type_str = optval_type_get_name(opt->type); 3625 snprintf(errbuf, IOSIZE, _("Invalid value for option '%s': expected %s, got %s %s"), 3626 opt->fullname, type_str, optval_type_get_name(newval->type), rep); 3627 xfree(rep); 3628 errmsg = errbuf; 3629 } else if (newval->type == kOptValTypeNumber) { 3630 // Validate and bound check num option values. 3631 errmsg = validate_num_option(opt_idx, &newval->data.number, errbuf, errbuflen); 3632 } 3633 3634 return errmsg; 3635 } 3636 3637 /// Set the value of an option using an OptVal. 3638 /// 3639 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 3640 /// @param value New option value. Might get freed. 3641 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3642 /// @param set_sid Script ID. Special values: 3643 /// 0: Use current script ID. 3644 /// SID_NONE: Don't set script ID. 3645 /// @param direct Don't process side-effects. 3646 /// @param value_replaced Value was replaced completely. 3647 /// @param[out] errbuf Buffer for error message. 3648 /// @param errbuflen Length of error buffer. 3649 /// 3650 /// @return NULL on success, an untranslated error message on error. 3651 static const char *set_option(const OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, 3652 const bool direct, const bool value_replaced, char *errbuf, 3653 size_t errbuflen) 3654 { 3655 assert(opt_idx != kOptInvalid); 3656 3657 const char *errmsg = NULL; 3658 3659 if (!direct) { 3660 errmsg = validate_option_value(opt_idx, &value, opt_flags, errbuf, errbuflen); 3661 3662 if (errmsg != NULL) { 3663 optval_free(value); 3664 return errmsg; 3665 } 3666 } 3667 3668 vimoption_T *opt = &options[opt_idx]; 3669 const bool scope_local = opt_flags & OPT_LOCAL; 3670 const bool scope_global = opt_flags & OPT_GLOBAL; 3671 const bool scope_both = !scope_local && !scope_global; 3672 // Whether local value of global-local option is unset. 3673 // NOTE: When this is true, it also implies that the option is global-local. 3674 const bool is_opt_local_unset = is_option_local_value_unset(opt_idx); 3675 3676 // When using ":set opt=val" for a global option with a local value the local value will be reset, 3677 // use the global value in that case. 3678 void *varp 3679 = scope_both && option_is_global_local(opt_idx) ? opt->var : get_varp_scope(opt, opt_flags); 3680 void *varp_local = get_varp_scope(opt, OPT_LOCAL); 3681 void *varp_global = get_varp_scope(opt, OPT_GLOBAL); 3682 3683 OptVal old_value = optval_from_varp(opt_idx, varp); 3684 OptVal old_global_value = optval_from_varp(opt_idx, varp_global); 3685 // If local value of global-local option is unset, use global value as local value. 3686 OptVal old_local_value = is_opt_local_unset 3687 ? old_global_value 3688 : optval_from_varp(opt_idx, varp_local); 3689 // Value that's actually being used. 3690 // For local scope of a global-local option, it's equal to the global value if the local value is 3691 // unset. In every other case, it is the same as old_value. 3692 // This value is used instead of old_value when triggering the OptionSet autocommand. 3693 OptVal used_old_value = (scope_local && is_opt_local_unset) 3694 ? optval_from_varp(opt_idx, get_varp(opt)) 3695 : old_value; 3696 3697 // Save the old values and the new value in case they get changed. 3698 OptVal saved_used_value = optval_copy(used_old_value); 3699 OptVal saved_old_global_value = optval_copy(old_global_value); 3700 OptVal saved_old_local_value = optval_copy(old_local_value); 3701 // New value (and varp) may become invalid if the buffer is closed by autocommands. 3702 OptVal saved_new_value = optval_copy(value); 3703 3704 uint32_t *p = insecure_flag(curwin, opt_idx, opt_flags); 3705 const int secure_saved = secure; 3706 3707 // When an option is set in the sandbox, from a modeline or in secure mode, then deal with side 3708 // effects in secure mode. Also when the value was set with the kOptFlagInsecure flag and is not 3709 // completely replaced. 3710 if ((opt_flags & OPT_MODELINE) || sandbox != 0 || (!value_replaced && (*p & kOptFlagInsecure))) { 3711 secure = 1; 3712 } 3713 3714 // Set option through its variable pointer. 3715 set_option_varp(opt_idx, varp, value, false); 3716 // Process any side effects. 3717 errmsg = did_set_option(opt_idx, varp, old_value, value, opt_flags, set_sid, direct, 3718 value_replaced, errbuf, errbuflen); 3719 3720 secure = secure_saved; 3721 3722 if (errmsg == NULL && !direct) { 3723 if (!starting) { 3724 apply_optionset_autocmd(opt_idx, opt_flags, saved_used_value, saved_old_global_value, 3725 saved_old_local_value, saved_new_value, errmsg); 3726 } 3727 if (opt->flags & kOptFlagUIOption) { 3728 ui_call_option_set(cstr_as_string(opt->fullname), optval_as_object(saved_new_value)); 3729 } 3730 } 3731 3732 // Free copied values as they are not needed anymore 3733 optval_free(saved_used_value); 3734 optval_free(saved_old_local_value); 3735 optval_free(saved_old_global_value); 3736 optval_free(saved_new_value); 3737 3738 return errmsg; 3739 } 3740 3741 /// Set option value directly, without processing any side effects. 3742 /// 3743 /// @param opt_idx Option index in options[] table. 3744 /// @param value Option value. 3745 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3746 /// @param set_sid Script ID. Special values: 3747 /// 0: Use current script ID. 3748 /// SID_NONE: Don't set script ID. 3749 void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid) 3750 { 3751 static char errbuf[IOSIZE]; 3752 3753 if (is_option_hidden(opt_idx)) { 3754 return; 3755 } 3756 3757 const char *errmsg = set_option(opt_idx, optval_copy(value), opt_flags, set_sid, true, true, 3758 errbuf, sizeof(errbuf)); 3759 assert(errmsg == NULL); 3760 (void)errmsg; // ignore unused warning 3761 } 3762 3763 /// Set option value directly for buffer / window, without processing any side effects. 3764 /// 3765 /// @param opt_idx Option index in options[] table. 3766 /// @param value Option value. 3767 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3768 /// @param set_sid Script ID. Special values: 3769 /// 0: Use current script ID. 3770 /// SID_NONE: Don't set script ID. 3771 /// @param scope Option scope. See OptScope in option.h. 3772 /// @param[in] from Target buffer/window. 3773 void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, 3774 OptScope scope, void *const from) 3775 { 3776 buf_T *save_curbuf = curbuf; 3777 win_T *save_curwin = curwin; 3778 3779 // Don't use switch_option_context(), as that calls aucmd_prepbuf(), which may have unintended 3780 // side-effects when setting an option directly. Just change the values of curbuf and curwin if 3781 // needed, no need to properly switch the window / buffer. 3782 switch (scope) { 3783 case kOptScopeGlobal: 3784 break; 3785 case kOptScopeWin: 3786 curwin = (win_T *)from; 3787 curbuf = curwin->w_buffer; 3788 break; 3789 case kOptScopeBuf: 3790 curbuf = (buf_T *)from; 3791 break; 3792 } 3793 3794 set_option_direct(opt_idx, value, opt_flags, set_sid); 3795 3796 curwin = save_curwin; 3797 curbuf = save_curbuf; 3798 } 3799 3800 /// Set the value of an option. 3801 /// 3802 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 3803 /// @param[in] value Option value. If NIL_OPTVAL, the option value is cleared. 3804 /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). 3805 /// 3806 /// @return NULL on success, an untranslated error message on error. 3807 const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt_flags) 3808 { 3809 assert(opt_idx != kOptInvalid); 3810 3811 static char errbuf[IOSIZE]; 3812 uint32_t flags = options[opt_idx].flags; 3813 3814 // Disallow changing some options in the sandbox 3815 if (sandbox > 0 && (flags & kOptFlagSecure)) { 3816 return _(e_sandbox); 3817 } 3818 3819 return set_option(opt_idx, optval_copy(value), opt_flags, 0, false, true, errbuf, sizeof(errbuf)); 3820 } 3821 3822 /// Unset the local value of a global-local option. 3823 /// 3824 /// @param opt_idx Index in options[] table. Must not be kOptInvalid. 3825 /// 3826 /// @return NULL on success, an untranslated error message on error. 3827 static inline const char *unset_option_local_value(const OptIndex opt_idx) 3828 { 3829 assert(option_is_global_local(opt_idx)); 3830 return set_option_value(opt_idx, get_option_unset_value(opt_idx), OPT_LOCAL); 3831 } 3832 3833 /// Set the value of an option. Supports TTY options, unlike set_option_value(). 3834 /// 3835 /// @param name Option name. Used for error messages and for setting TTY options. 3836 /// @param opt_idx Option indx in options[] table. If kOptInvalid, `name` is used to 3837 /// check if the option is a TTY option, and an error is shown if it's not. 3838 /// If the option is a TTY option, the function fails silently. 3839 /// @param value Option value. If NIL_OPTVAL, the option value is cleared. 3840 /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). 3841 /// 3842 /// @return NULL on success, an untranslated error message on error. 3843 const char *set_option_value_handle_tty(const char *name, OptIndex opt_idx, const OptVal value, 3844 int opt_flags) 3845 FUNC_ATTR_NONNULL_ARG(1) 3846 { 3847 static char errbuf[IOSIZE]; 3848 3849 if (opt_idx == kOptInvalid) { 3850 if (is_tty_option(name)) { 3851 return NULL; // Fail silently; many old vimrcs set t_xx options. 3852 } 3853 3854 snprintf(errbuf, sizeof(errbuf), _(e_unknown_option2), name); 3855 return errbuf; 3856 } 3857 3858 return set_option_value(opt_idx, value, opt_flags); 3859 } 3860 3861 /// Call set_option_value() and when an error is returned, report it. 3862 /// 3863 /// @param opt_idx Option index in options[] table. 3864 /// @param value Option value. If NIL_OPTVAL, the option value is cleared. 3865 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3866 void set_option_value_give_err(const OptIndex opt_idx, OptVal value, int opt_flags) 3867 { 3868 const char *errmsg = set_option_value(opt_idx, value, opt_flags); 3869 3870 if (errmsg != NULL) { 3871 emsg(_(errmsg)); 3872 } 3873 } 3874 3875 /// Switch current context to get/set option value for window/buffer. 3876 /// 3877 /// @param[out] ctx Current context. switchwin_T for window and aco_save_T for buffer. 3878 /// @param scope Option scope. See OptScope in option.h. 3879 /// @param[in] from Target buffer/window. 3880 /// @param[out] err Error message, if any. 3881 /// 3882 /// @return true if context was switched, false otherwise. 3883 static bool switch_option_context(void *const ctx, OptScope scope, void *const from, Error *err) 3884 { 3885 switch (scope) { 3886 case kOptScopeGlobal: 3887 return false; 3888 case kOptScopeWin: { 3889 win_T *const win = (win_T *)from; 3890 switchwin_T *const switchwin = (switchwin_T *)ctx; 3891 3892 if (win == curwin) { 3893 return false; 3894 } 3895 3896 if (switch_win_noblock(switchwin, win, win_find_tabpage(win), true) 3897 == FAIL) { 3898 restore_win_noblock(switchwin, true); 3899 3900 if (ERROR_SET(err)) { 3901 return false; 3902 } 3903 api_set_error(err, kErrorTypeException, "Problem while switching windows"); 3904 return false; 3905 } 3906 return true; 3907 } 3908 case kOptScopeBuf: { 3909 buf_T *const buf = (buf_T *)from; 3910 aco_save_T *const aco = (aco_save_T *)ctx; 3911 3912 if (buf == curbuf) { 3913 return false; 3914 } 3915 aucmd_prepbuf(aco, buf); 3916 return true; 3917 } 3918 } 3919 UNREACHABLE; 3920 } 3921 3922 /// Restore context after getting/setting option for window/buffer. See switch_option_context() for 3923 /// params. 3924 static void restore_option_context(void *const ctx, OptScope scope) 3925 { 3926 switch (scope) { 3927 case kOptScopeGlobal: 3928 break; 3929 case kOptScopeWin: 3930 restore_win_noblock((switchwin_T *)ctx, true); 3931 break; 3932 case kOptScopeBuf: 3933 aucmd_restbuf((aco_save_T *)ctx); 3934 break; 3935 } 3936 } 3937 3938 /// Get option value for buffer / window. 3939 /// 3940 /// @param opt_idx Option index in options[] table. 3941 /// @param[out] flagsp Set to the option flags (see OptFlags) (if not NULL). 3942 /// @param[in] scope Option scope (can be OPT_LOCAL, OPT_GLOBAL or a combination). 3943 /// @param[out] hidden Whether option is hidden. 3944 /// @param scope Option scope. See OptScope in option.h. 3945 /// @param[in] from Target buffer/window. 3946 /// @param[out] err Error message, if any. 3947 /// 3948 /// @return Option value. Must be freed by caller. 3949 OptVal get_option_value_for(OptIndex opt_idx, int opt_flags, const OptScope scope, void *const from, 3950 Error *err) 3951 { 3952 switchwin_T switchwin; 3953 aco_save_T aco; 3954 void *ctx = scope == kOptScopeWin ? (void *)&switchwin 3955 : (scope == kOptScopeBuf ? (void *)&aco : NULL); 3956 3957 bool switched = switch_option_context(ctx, scope, from, err); 3958 if (ERROR_SET(err)) { 3959 return NIL_OPTVAL; 3960 } 3961 3962 OptVal retv = get_option_value(opt_idx, opt_flags); 3963 3964 if (switched) { 3965 restore_option_context(ctx, scope); 3966 } 3967 3968 return retv; 3969 } 3970 3971 /// Set option value for buffer / window. 3972 /// 3973 /// @param name Option name. 3974 /// @param opt_idx Option index in options[] table. 3975 /// @param[in] value Option value. 3976 /// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both). 3977 /// @param scope Option scope. See OptScope in option.h. 3978 /// @param[in] from Target buffer/window. 3979 /// @param[out] err Error message, if any. 3980 void set_option_value_for(const char *name, OptIndex opt_idx, OptVal value, const int opt_flags, 3981 const OptScope scope, void *const from, Error *err) 3982 FUNC_ATTR_NONNULL_ARG(1) 3983 { 3984 switchwin_T switchwin; 3985 aco_save_T aco; 3986 void *ctx = scope == kOptScopeWin ? (void *)&switchwin 3987 : (scope == kOptScopeBuf ? (void *)&aco : NULL); 3988 3989 bool switched = switch_option_context(ctx, scope, from, err); 3990 if (ERROR_SET(err)) { 3991 return; 3992 } 3993 3994 const char *const errmsg = set_option_value_handle_tty(name, opt_idx, value, opt_flags); 3995 if (errmsg) { 3996 api_set_error(err, kErrorTypeException, "%s", errmsg); 3997 } 3998 3999 if (switched) { 4000 restore_option_context(ctx, scope); 4001 } 4002 } 4003 4004 /// if 'all' == false: show changed options 4005 /// if 'all' == true: show all normal options 4006 /// 4007 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 4008 static void showoptions(bool all, int opt_flags) 4009 { 4010 #define INC 20 4011 #define GAP 3 4012 4013 vimoption_T **items = xmalloc(sizeof(vimoption_T *) * OPTION_COUNT); 4014 4015 msg_ext_set_kind("list_cmd"); 4016 // Highlight title 4017 if (opt_flags & OPT_GLOBAL) { 4018 msg_puts_title(_("\n--- Global option values ---")); 4019 } else if (opt_flags & OPT_LOCAL) { 4020 msg_puts_title(_("\n--- Local option values ---")); 4021 } else { 4022 msg_puts_title(_("\n--- Options ---")); 4023 } 4024 4025 // Do the loop two times: 4026 // 1. display the short items 4027 // 2. display the long items (only strings and numbers) 4028 // When "opt_flags" has OPT_ONECOLUMN do everything in run 2. 4029 for (int run = 1; run <= 2 && !got_int; run++) { 4030 // collect the items in items[] 4031 int item_count = 0; 4032 vimoption_T *opt; 4033 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 4034 opt = &options[opt_idx]; 4035 // apply :filter /pat/ 4036 if (message_filtered(opt->fullname)) { 4037 continue; 4038 } 4039 4040 void *varp = NULL; 4041 if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) != 0) { 4042 if (!option_is_global_only(opt_idx)) { 4043 varp = get_varp_scope(opt, opt_flags); 4044 } 4045 } else { 4046 varp = get_varp(opt); 4047 } 4048 if (varp != NULL && (all || !optval_default(opt_idx, varp))) { 4049 int len; 4050 if (opt_flags & OPT_ONECOLUMN) { 4051 len = Columns; 4052 } else if (option_has_type(opt_idx, kOptValTypeBoolean)) { 4053 len = 1; // a toggle option fits always 4054 } else { 4055 option_value2string(opt, opt_flags); 4056 len = (int)strlen(opt->fullname) + vim_strsize(NameBuff) + 1; 4057 } 4058 if ((len <= INC - GAP && run == 1) 4059 || (len > INC - GAP && run == 2)) { 4060 items[item_count++] = opt; 4061 } 4062 } 4063 } 4064 4065 int rows; 4066 4067 // display the items 4068 if (run == 1) { 4069 assert(Columns <= INT_MAX - GAP 4070 && Columns + GAP >= INT_MIN + 3 4071 && (Columns + GAP - 3) / INC >= INT_MIN 4072 && (Columns + GAP - 3) / INC <= INT_MAX); 4073 int cols = (Columns + GAP - 3) / INC; 4074 if (cols == 0) { 4075 cols = 1; 4076 } 4077 rows = (item_count + cols - 1) / cols; 4078 } else { // run == 2 4079 rows = item_count; 4080 } 4081 for (int row = 0; row < rows && !got_int; row++) { 4082 msg_putchar('\n'); // go to next line 4083 if (got_int) { // 'q' typed in more 4084 break; 4085 } 4086 int col = 0; 4087 for (int i = row; i < item_count; i += rows) { 4088 msg_advance(col); // make columns 4089 showoneopt(items[i], opt_flags); 4090 col += INC; 4091 } 4092 os_breakcheck(); 4093 } 4094 } 4095 xfree(items); 4096 } 4097 4098 /// Return true if option "p" has its default value. 4099 static int optval_default(OptIndex opt_idx, void *varp) 4100 { 4101 vimoption_T *opt = &options[opt_idx]; 4102 4103 // Hidden options always use their default value. 4104 if (is_option_hidden(opt_idx)) { 4105 return true; 4106 } 4107 4108 OptVal current_val = optval_from_varp(opt_idx, varp); 4109 OptVal default_val = opt->def_val; 4110 4111 return optval_equal(current_val, default_val); 4112 } 4113 4114 /// Send update to UIs with values of UI relevant options 4115 void ui_refresh_options(void) 4116 { 4117 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 4118 uint32_t flags = options[opt_idx].flags; 4119 if (!(flags & kOptFlagUIOption)) { 4120 continue; 4121 } 4122 String name = cstr_as_string(options[opt_idx].fullname); 4123 Object value = optval_as_object(optval_from_varp(opt_idx, options[opt_idx].var)); 4124 ui_call_option_set(name, value); 4125 } 4126 if (p_mouse != NULL) { 4127 setmouse(); 4128 } 4129 } 4130 4131 /// showoneopt: show the value of one option 4132 /// must not be called with a hidden option! 4133 /// 4134 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 4135 static void showoneopt(vimoption_T *opt, int opt_flags) 4136 { 4137 int save_silent = silent_mode; 4138 4139 silent_mode = false; 4140 info_message = true; // use stdout, not stderr 4141 4142 OptIndex opt_idx = get_opt_idx(opt); 4143 void *varp = get_varp_scope(opt, opt_flags); 4144 4145 // for 'modified' we also need to check if 'ff' or 'fenc' changed. 4146 if (option_has_type(opt_idx, kOptValTypeBoolean) 4147 && ((int *)varp == &curbuf->b_changed ? !curbufIsChanged() : !*(int *)varp)) { 4148 msg_puts("no"); 4149 } else if (option_has_type(opt_idx, kOptValTypeBoolean) && *(int *)varp < 0) { 4150 msg_puts("--"); 4151 } else { 4152 msg_puts(" "); 4153 } 4154 msg_puts(opt->fullname); 4155 if (!(option_has_type(opt_idx, kOptValTypeBoolean))) { 4156 msg_putchar('='); 4157 // put value string in NameBuff 4158 option_value2string(opt, opt_flags); 4159 if (*NameBuff != NUL) { 4160 msg_outtrans(NameBuff, 0, false); 4161 } 4162 } 4163 4164 silent_mode = save_silent; 4165 info_message = false; 4166 } 4167 4168 /// Write modified options as ":set" commands to a file. 4169 /// 4170 /// There are three values for "opt_flags": 4171 /// OPT_GLOBAL: Write global option values and fresh values of 4172 /// buffer-local options (used for start of a session 4173 /// file). 4174 /// OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for 4175 /// curwin (used for a vimrc file). 4176 /// OPT_LOCAL: Write buffer-local option values for curbuf, fresh 4177 /// and local values for window-local options of 4178 /// curwin. Local values are also written when at the 4179 /// default value, because a modeline or autocommand 4180 /// may have set them when doing ":edit file" and the 4181 /// user has set them back at the default or fresh 4182 /// value. 4183 /// When "local_only" is true, don't write fresh 4184 /// values, only local values (for ":mkview"). 4185 /// (fresh value = value used for a new buffer or window for a local option). 4186 /// 4187 /// Return FAIL on error, OK otherwise. 4188 int makeset(FILE *fd, int opt_flags, int local_only) 4189 { 4190 // Some options are never written: 4191 // - Options that don't have a default (terminal name, columns, lines). 4192 // - Terminal options. 4193 // - Hidden options. 4194 // 4195 // Do the loop over "options[]" twice: once for options with the 4196 // kOptFlagPriMkrc flag and once without. 4197 for (int pri = 1; pri >= 0; pri--) { 4198 vimoption_T *opt; 4199 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 4200 opt = &options[opt_idx]; 4201 4202 if (!(opt->flags & kOptFlagNoMkrc) 4203 && ((pri == 1) == ((opt->flags & kOptFlagPriMkrc) != 0))) { 4204 // skip global option when only doing locals 4205 if (option_is_global_only(opt_idx) && !(opt_flags & OPT_GLOBAL)) { 4206 continue; 4207 } 4208 4209 // Do not store options like 'bufhidden' and 'syntax' in a vimrc 4210 // file, they are always buffer-specific. 4211 if ((opt_flags & OPT_GLOBAL) && (opt->flags & kOptFlagNoGlob)) { 4212 continue; 4213 } 4214 4215 void *varp = get_varp_scope(opt, opt_flags); // currently used value 4216 // Hidden options are never written. 4217 if (!varp) { 4218 continue; 4219 } 4220 // Global values are only written when not at the default value. 4221 if ((opt_flags & OPT_GLOBAL) && optval_default(opt_idx, varp)) { 4222 continue; 4223 } 4224 4225 if ((opt_flags & OPT_SKIPRTP) 4226 && (opt->var == &p_rtp || opt->var == &p_pp)) { 4227 continue; 4228 } 4229 4230 int round = 2; 4231 void *varp_local = NULL; // fresh value 4232 if (option_is_window_local(opt_idx)) { 4233 // skip window-local option when only doing globals 4234 if (!(opt_flags & OPT_LOCAL)) { 4235 continue; 4236 } 4237 // When fresh value of window-local option is not at the 4238 // default, need to write it too. 4239 if (!(opt_flags & OPT_GLOBAL) && !local_only) { 4240 void *varp_fresh = get_varp_scope(opt, OPT_GLOBAL); // local value 4241 if (!optval_default(opt_idx, varp_fresh)) { 4242 round = 1; 4243 varp_local = varp; 4244 varp = varp_fresh; 4245 } 4246 } 4247 } 4248 4249 // Round 1: fresh value for window-local options. 4250 // Round 2: other values 4251 for (; round <= 2; varp = varp_local, round++) { 4252 char *cmd; 4253 if (round == 1 || (opt_flags & OPT_GLOBAL)) { 4254 cmd = "set"; 4255 } else { 4256 cmd = "setlocal"; 4257 } 4258 4259 bool do_endif = false; 4260 // Don't set 'syntax' and 'filetype' again if the value is already right, avoids reloading 4261 // the syntax file. 4262 if (opt_idx == kOptSyntax || opt_idx == kOptFiletype) { 4263 if (fprintf(fd, "if &%s != '%s'", opt->fullname, 4264 *(char **)(varp)) < 0 4265 || put_eol(fd) < 0) { 4266 return FAIL; 4267 } 4268 do_endif = true; 4269 } 4270 if (put_set(fd, cmd, opt_idx, varp) == FAIL) { 4271 return FAIL; 4272 } 4273 if (do_endif) { 4274 if (put_line(fd, "endif") == FAIL) { 4275 return FAIL; 4276 } 4277 } 4278 } 4279 } 4280 } 4281 } 4282 return OK; 4283 } 4284 4285 /// Generate set commands for the local fold options only. Used when 4286 /// 'sessionoptions' or 'viewoptions' contains "folds" but not "options". 4287 int makefoldset(FILE *fd) 4288 { 4289 if (put_set(fd, "setlocal", kOptFoldmethod, &curwin->w_p_fdm) == FAIL 4290 || put_set(fd, "setlocal", kOptFoldexpr, &curwin->w_p_fde) == FAIL 4291 || put_set(fd, "setlocal", kOptFoldmarker, &curwin->w_p_fmr) == FAIL 4292 || put_set(fd, "setlocal", kOptFoldignore, &curwin->w_p_fdi) == FAIL 4293 || put_set(fd, "setlocal", kOptFoldlevel, &curwin->w_p_fdl) == FAIL 4294 || put_set(fd, "setlocal", kOptFoldminlines, &curwin->w_p_fml) == FAIL 4295 || put_set(fd, "setlocal", kOptFoldnestmax, &curwin->w_p_fdn) == FAIL 4296 || put_set(fd, "setlocal", kOptFoldenable, &curwin->w_p_fen) == FAIL) { 4297 return FAIL; 4298 } 4299 4300 return OK; 4301 } 4302 4303 /// Print the ":set" command to set a single option to file. 4304 /// 4305 /// @param fd File descriptor. 4306 /// @param cmd Command name. 4307 /// @param opt_idx Option index in options[] table. 4308 /// @param varp Pointer to option variable. 4309 /// 4310 /// @return FAIL on error, OK otherwise. 4311 static int put_set(FILE *fd, char *cmd, OptIndex opt_idx, void *varp) 4312 { 4313 OptVal value = optval_from_varp(opt_idx, varp); 4314 vimoption_T *opt = &options[opt_idx]; 4315 char *name = opt->fullname; 4316 uint64_t flags = opt->flags; 4317 4318 if (option_is_global_local(opt_idx) && varp != opt->var 4319 && optval_equal(value, get_option_unset_value(opt_idx))) { 4320 // Processing unset local value of global-local option. Do nothing. 4321 return OK; 4322 } 4323 4324 switch (value.type) { 4325 case kOptValTypeNil: 4326 abort(); 4327 case kOptValTypeBoolean: { 4328 assert(value.data.boolean != kNone); 4329 bool value_bool = TRISTATE_TO_BOOL(value.data.boolean, false); 4330 4331 if (fprintf(fd, "%s %s%s", cmd, value_bool ? "" : "no", name) < 0) { 4332 return FAIL; 4333 } 4334 break; 4335 } 4336 case kOptValTypeNumber: { 4337 if (fprintf(fd, "%s %s=", cmd, name) < 0) { 4338 return FAIL; 4339 } 4340 4341 OptInt value_num = value.data.number; 4342 4343 OptInt wc; 4344 if (wc_use_keyname(varp, &wc)) { 4345 // print 'wildchar' and 'wildcharm' as a key name 4346 if (fputs(get_special_key_name((int)wc, 0), fd) < 0) { 4347 return FAIL; 4348 } 4349 } else if (fprintf(fd, "%" PRId64, value_num) < 0) { 4350 return FAIL; 4351 } 4352 break; 4353 } 4354 case kOptValTypeString: { 4355 if (fprintf(fd, "%s %s=", cmd, name) < 0) { 4356 return FAIL; 4357 } 4358 4359 const char *value_str = value.data.string.data; 4360 char *buf = NULL; 4361 char *part = NULL; 4362 4363 if (value_str != NULL) { 4364 if ((flags & kOptFlagExpand) != 0) { 4365 size_t size = (size_t)strlen(value_str) + 1; 4366 4367 // replace home directory in the whole option value into "buf" 4368 buf = xmalloc(size); 4369 home_replace(NULL, value_str, buf, size, false); 4370 4371 // If the option value is longer than MAXPATHL, we need to append 4372 // each comma separated part of the option separately, so that it 4373 // can be expanded when read back. 4374 if (size >= MAXPATHL && (flags & kOptFlagComma) != 0 4375 && vim_strchr(value_str, ',') != NULL) { 4376 part = xmalloc(size); 4377 4378 // write line break to clear the option, e.g. ':set rtp=' 4379 if (put_eol(fd) == FAIL) { 4380 goto fail; 4381 } 4382 char *p = buf; 4383 while (*p != NUL) { 4384 // for each comma separated option part, append value to 4385 // the option, :set rtp+=value 4386 if (fprintf(fd, "%s %s+=", cmd, name) < 0) { 4387 goto fail; 4388 } 4389 copy_option_part(&p, part, size, ","); 4390 if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) { 4391 goto fail; 4392 } 4393 } 4394 xfree(buf); 4395 xfree(part); 4396 return OK; 4397 } 4398 if (put_escstr(fd, buf, 2) == FAIL) { 4399 xfree(buf); 4400 return FAIL; 4401 } 4402 xfree(buf); 4403 } else if (put_escstr(fd, value_str, 2) == FAIL) { 4404 return FAIL; 4405 } 4406 } 4407 break; 4408 fail: 4409 xfree(buf); 4410 xfree(part); 4411 return FAIL; 4412 } 4413 } 4414 4415 if (put_eol(fd) < 0) { 4416 return FAIL; 4417 } 4418 return OK; 4419 } 4420 4421 void *get_varp_scope_from(vimoption_T *p, int opt_flags, buf_T *buf, win_T *win) 4422 { 4423 OptIndex opt_idx = get_opt_idx(p); 4424 4425 if ((opt_flags & OPT_GLOBAL) && !option_is_global_only(opt_idx)) { 4426 if (option_is_window_local(opt_idx)) { 4427 return GLOBAL_WO(get_varp_from(p, buf, win)); 4428 } 4429 return p->var; 4430 } 4431 4432 if ((opt_flags & OPT_LOCAL) && option_is_global_local(opt_idx)) { 4433 switch (opt_idx) { 4434 case kOptFormatprg: 4435 return &(buf->b_p_fp); 4436 case kOptFsync: 4437 return &(buf->b_p_fs); 4438 case kOptFindfunc: 4439 return &(buf->b_p_ffu); 4440 case kOptErrorformat: 4441 return &(buf->b_p_efm); 4442 case kOptGrepformat: 4443 return &(buf->b_p_gefm); 4444 case kOptGrepprg: 4445 return &(buf->b_p_gp); 4446 case kOptMakeprg: 4447 return &(buf->b_p_mp); 4448 case kOptEqualprg: 4449 return &(buf->b_p_ep); 4450 case kOptKeywordprg: 4451 return &(buf->b_p_kp); 4452 case kOptPath: 4453 return &(buf->b_p_path); 4454 case kOptAutocomplete: 4455 return &(buf->b_p_ac); 4456 case kOptAutoread: 4457 return &(buf->b_p_ar); 4458 case kOptTags: 4459 return &(buf->b_p_tags); 4460 case kOptTagcase: 4461 return &(buf->b_p_tc); 4462 case kOptSidescrolloff: 4463 return &(win->w_p_siso); 4464 case kOptScrolloff: 4465 return &(win->w_p_so); 4466 case kOptDefine: 4467 return &(buf->b_p_def); 4468 case kOptInclude: 4469 return &(buf->b_p_inc); 4470 case kOptCompleteopt: 4471 return &(buf->b_p_cot); 4472 case kOptDictionary: 4473 return &(buf->b_p_dict); 4474 case kOptDiffanchors: 4475 return &(buf->b_p_dia); 4476 case kOptThesaurus: 4477 return &(buf->b_p_tsr); 4478 case kOptThesaurusfunc: 4479 return &(buf->b_p_tsrfu); 4480 case kOptTagfunc: 4481 return &(buf->b_p_tfu); 4482 case kOptShowbreak: 4483 return &(win->w_p_sbr); 4484 case kOptStatusline: 4485 return &(win->w_p_stl); 4486 case kOptWinbar: 4487 return &(win->w_p_wbr); 4488 case kOptUndolevels: 4489 return &(buf->b_p_ul); 4490 case kOptLispwords: 4491 return &(buf->b_p_lw); 4492 case kOptBackupcopy: 4493 return &(buf->b_p_bkc); 4494 case kOptMakeencoding: 4495 return &(buf->b_p_menc); 4496 case kOptFillchars: 4497 return &(win->w_p_fcs); 4498 case kOptListchars: 4499 return &(win->w_p_lcs); 4500 case kOptVirtualedit: 4501 return &(win->w_p_ve); 4502 default: 4503 abort(); 4504 } 4505 } 4506 return get_varp_from(p, buf, win); 4507 } 4508 4509 /// Get pointer to option variable, depending on local or global scope. 4510 /// 4511 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 4512 void *get_varp_scope(vimoption_T *p, int opt_flags) 4513 { 4514 return get_varp_scope_from(p, opt_flags, curbuf, curwin); 4515 } 4516 4517 /// Get pointer to option variable at 'opt_idx', depending on local or global 4518 /// scope. 4519 void *get_option_varp_scope_from(OptIndex opt_idx, int opt_flags, buf_T *buf, win_T *win) 4520 { 4521 return get_varp_scope_from(&(options[opt_idx]), opt_flags, buf, win); 4522 } 4523 4524 void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) 4525 { 4526 OptIndex opt_idx = get_opt_idx(p); 4527 4528 // Hidden options and global-only options always use the same var pointer 4529 if (is_option_hidden(opt_idx) || option_is_global_only(opt_idx)) { 4530 return p->var; 4531 } 4532 4533 switch (opt_idx) { 4534 // global option with local value: use local value if it's been set 4535 case kOptEqualprg: 4536 return *buf->b_p_ep != NUL ? &buf->b_p_ep : p->var; 4537 case kOptKeywordprg: 4538 return *buf->b_p_kp != NUL ? &buf->b_p_kp : p->var; 4539 case kOptPath: 4540 return *buf->b_p_path != NUL ? &(buf->b_p_path) : p->var; 4541 case kOptAutocomplete: 4542 return buf->b_p_ac >= 0 ? &(buf->b_p_ac) : p->var; 4543 case kOptAutoread: 4544 return buf->b_p_ar >= 0 ? &(buf->b_p_ar) : p->var; 4545 case kOptTags: 4546 return *buf->b_p_tags != NUL ? &(buf->b_p_tags) : p->var; 4547 case kOptTagcase: 4548 return *buf->b_p_tc != NUL ? &(buf->b_p_tc) : p->var; 4549 case kOptSidescrolloff: 4550 return win->w_p_siso >= 0 ? &(win->w_p_siso) : p->var; 4551 case kOptScrolloff: 4552 return win->w_p_so >= 0 ? &(win->w_p_so) : p->var; 4553 case kOptBackupcopy: 4554 return *buf->b_p_bkc != NUL ? &(buf->b_p_bkc) : p->var; 4555 case kOptDefine: 4556 return *buf->b_p_def != NUL ? &(buf->b_p_def) : p->var; 4557 case kOptInclude: 4558 return *buf->b_p_inc != NUL ? &(buf->b_p_inc) : p->var; 4559 case kOptCompleteopt: 4560 return *buf->b_p_cot != NUL ? &(buf->b_p_cot) : p->var; 4561 case kOptDictionary: 4562 return *buf->b_p_dict != NUL ? &(buf->b_p_dict) : p->var; 4563 case kOptDiffanchors: 4564 return *buf->b_p_dia != NUL ? &(buf->b_p_dia) : p->var; 4565 case kOptThesaurus: 4566 return *buf->b_p_tsr != NUL ? &(buf->b_p_tsr) : p->var; 4567 case kOptThesaurusfunc: 4568 return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var; 4569 case kOptFormatprg: 4570 return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var; 4571 case kOptFsync: 4572 return buf->b_p_fs >= 0 ? &(buf->b_p_fs) : p->var; 4573 case kOptFindfunc: 4574 return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var; 4575 case kOptErrorformat: 4576 return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var; 4577 case kOptGrepformat: 4578 return *buf->b_p_gefm != NUL ? &(buf->b_p_gefm) : p->var; 4579 case kOptGrepprg: 4580 return *buf->b_p_gp != NUL ? &(buf->b_p_gp) : p->var; 4581 case kOptMakeprg: 4582 return *buf->b_p_mp != NUL ? &(buf->b_p_mp) : p->var; 4583 case kOptShowbreak: 4584 return *win->w_p_sbr != NUL ? &(win->w_p_sbr) : p->var; 4585 case kOptStatusline: 4586 return *win->w_p_stl != NUL ? &(win->w_p_stl) : p->var; 4587 case kOptWinbar: 4588 return *win->w_p_wbr != NUL ? &(win->w_p_wbr) : p->var; 4589 case kOptUndolevels: 4590 return buf->b_p_ul != NO_LOCAL_UNDOLEVEL ? &(buf->b_p_ul) : p->var; 4591 case kOptLispwords: 4592 return *buf->b_p_lw != NUL ? &(buf->b_p_lw) : p->var; 4593 case kOptMakeencoding: 4594 return *buf->b_p_menc != NUL ? &(buf->b_p_menc) : p->var; 4595 case kOptFillchars: 4596 return *win->w_p_fcs != NUL ? &(win->w_p_fcs) : p->var; 4597 case kOptListchars: 4598 return *win->w_p_lcs != NUL ? &(win->w_p_lcs) : p->var; 4599 case kOptVirtualedit: 4600 return *win->w_p_ve != NUL ? &win->w_p_ve : p->var; 4601 4602 case kOptArabic: 4603 return &(win->w_p_arab); 4604 case kOptList: 4605 return &(win->w_p_list); 4606 case kOptSpell: 4607 return &(win->w_p_spell); 4608 case kOptCursorcolumn: 4609 return &(win->w_p_cuc); 4610 case kOptCursorline: 4611 return &(win->w_p_cul); 4612 case kOptCursorlineopt: 4613 return &(win->w_p_culopt); 4614 case kOptColorcolumn: 4615 return &(win->w_p_cc); 4616 case kOptDiff: 4617 return &(win->w_p_diff); 4618 case kOptEventignorewin: 4619 return &(win->w_p_eiw); 4620 case kOptFoldcolumn: 4621 return &(win->w_p_fdc); 4622 case kOptFoldenable: 4623 return &(win->w_p_fen); 4624 case kOptFoldignore: 4625 return &(win->w_p_fdi); 4626 case kOptFoldlevel: 4627 return &(win->w_p_fdl); 4628 case kOptFoldmethod: 4629 return &(win->w_p_fdm); 4630 case kOptFoldminlines: 4631 return &(win->w_p_fml); 4632 case kOptFoldnestmax: 4633 return &(win->w_p_fdn); 4634 case kOptFoldexpr: 4635 return &(win->w_p_fde); 4636 case kOptFoldtext: 4637 return &(win->w_p_fdt); 4638 case kOptFoldmarker: 4639 return &(win->w_p_fmr); 4640 case kOptNumber: 4641 return &(win->w_p_nu); 4642 case kOptRelativenumber: 4643 return &(win->w_p_rnu); 4644 case kOptNumberwidth: 4645 return &(win->w_p_nuw); 4646 case kOptWinfixbuf: 4647 return &(win->w_p_wfb); 4648 case kOptWinfixheight: 4649 return &(win->w_p_wfh); 4650 case kOptWinfixwidth: 4651 return &(win->w_p_wfw); 4652 case kOptPreviewwindow: 4653 return &(win->w_p_pvw); 4654 case kOptLhistory: 4655 return &(win->w_p_lhi); 4656 case kOptRightleft: 4657 return &(win->w_p_rl); 4658 case kOptRightleftcmd: 4659 return &(win->w_p_rlc); 4660 case kOptScroll: 4661 return &(win->w_p_scr); 4662 case kOptSmoothscroll: 4663 return &(win->w_p_sms); 4664 case kOptWrap: 4665 return &(win->w_p_wrap); 4666 case kOptLinebreak: 4667 return &(win->w_p_lbr); 4668 case kOptBreakindent: 4669 return &(win->w_p_bri); 4670 case kOptBreakindentopt: 4671 return &(win->w_p_briopt); 4672 case kOptScrollbind: 4673 return &(win->w_p_scb); 4674 case kOptCursorbind: 4675 return &(win->w_p_crb); 4676 case kOptConcealcursor: 4677 return &(win->w_p_cocu); 4678 case kOptConceallevel: 4679 return &(win->w_p_cole); 4680 4681 case kOptAutoindent: 4682 return &(buf->b_p_ai); 4683 case kOptBinary: 4684 return &(buf->b_p_bin); 4685 case kOptBomb: 4686 return &(buf->b_p_bomb); 4687 case kOptBufhidden: 4688 return &(buf->b_p_bh); 4689 case kOptBuftype: 4690 return &(buf->b_p_bt); 4691 case kOptBuflisted: 4692 return &(buf->b_p_bl); 4693 case kOptBusy: 4694 return &(buf->b_p_busy); 4695 case kOptChannel: 4696 return &(buf->b_p_channel); 4697 case kOptCopyindent: 4698 return &(buf->b_p_ci); 4699 case kOptCindent: 4700 return &(buf->b_p_cin); 4701 case kOptCinkeys: 4702 return &(buf->b_p_cink); 4703 case kOptCinoptions: 4704 return &(buf->b_p_cino); 4705 case kOptCinscopedecls: 4706 return &(buf->b_p_cinsd); 4707 case kOptCinwords: 4708 return &(buf->b_p_cinw); 4709 case kOptComments: 4710 return &(buf->b_p_com); 4711 case kOptCommentstring: 4712 return &(buf->b_p_cms); 4713 case kOptComplete: 4714 return &(buf->b_p_cpt); 4715 #ifdef BACKSLASH_IN_FILENAME 4716 case kOptCompleteslash: 4717 return &(buf->b_p_csl); 4718 #endif 4719 case kOptCompletefunc: 4720 return &(buf->b_p_cfu); 4721 case kOptOmnifunc: 4722 return &(buf->b_p_ofu); 4723 case kOptEndoffile: 4724 return &(buf->b_p_eof); 4725 case kOptEndofline: 4726 return &(buf->b_p_eol); 4727 case kOptFixendofline: 4728 return &(buf->b_p_fixeol); 4729 case kOptExpandtab: 4730 return &(buf->b_p_et); 4731 case kOptFileencoding: 4732 return &(buf->b_p_fenc); 4733 case kOptFileformat: 4734 return &(buf->b_p_ff); 4735 case kOptFiletype: 4736 return &(buf->b_p_ft); 4737 case kOptFormatoptions: 4738 return &(buf->b_p_fo); 4739 case kOptFormatlistpat: 4740 return &(buf->b_p_flp); 4741 case kOptIminsert: 4742 return &(buf->b_p_iminsert); 4743 case kOptImsearch: 4744 return &(buf->b_p_imsearch); 4745 case kOptInfercase: 4746 return &(buf->b_p_inf); 4747 case kOptIskeyword: 4748 return &(buf->b_p_isk); 4749 case kOptIncludeexpr: 4750 return &(buf->b_p_inex); 4751 case kOptIndentexpr: 4752 return &(buf->b_p_inde); 4753 case kOptIndentkeys: 4754 return &(buf->b_p_indk); 4755 case kOptFormatexpr: 4756 return &(buf->b_p_fex); 4757 case kOptLisp: 4758 return &(buf->b_p_lisp); 4759 case kOptLispoptions: 4760 return &(buf->b_p_lop); 4761 case kOptModeline: 4762 return &(buf->b_p_ml); 4763 case kOptMatchpairs: 4764 return &(buf->b_p_mps); 4765 case kOptModifiable: 4766 return &(buf->b_p_ma); 4767 case kOptModified: 4768 return &(buf->b_changed); 4769 case kOptNrformats: 4770 return &(buf->b_p_nf); 4771 case kOptPreserveindent: 4772 return &(buf->b_p_pi); 4773 case kOptQuoteescape: 4774 return &(buf->b_p_qe); 4775 case kOptReadonly: 4776 return &(buf->b_p_ro); 4777 case kOptScrollback: 4778 return &(buf->b_p_scbk); 4779 case kOptSmartindent: 4780 return &(buf->b_p_si); 4781 case kOptSofttabstop: 4782 return &(buf->b_p_sts); 4783 case kOptSuffixesadd: 4784 return &(buf->b_p_sua); 4785 case kOptSwapfile: 4786 return &(buf->b_p_swf); 4787 case kOptSynmaxcol: 4788 return &(buf->b_p_smc); 4789 case kOptSyntax: 4790 return &(buf->b_p_syn); 4791 case kOptSpellcapcheck: 4792 return &(win->w_s->b_p_spc); 4793 case kOptSpellfile: 4794 return &(win->w_s->b_p_spf); 4795 case kOptSpelllang: 4796 return &(win->w_s->b_p_spl); 4797 case kOptSpelloptions: 4798 return &(win->w_s->b_p_spo); 4799 case kOptShiftwidth: 4800 return &(buf->b_p_sw); 4801 case kOptTagfunc: 4802 return &(buf->b_p_tfu); 4803 case kOptTabstop: 4804 return &(buf->b_p_ts); 4805 case kOptTextwidth: 4806 return &(buf->b_p_tw); 4807 case kOptUndofile: 4808 return &(buf->b_p_udf); 4809 case kOptWrapmargin: 4810 return &(buf->b_p_wm); 4811 case kOptVarsofttabstop: 4812 return &(buf->b_p_vsts); 4813 case kOptVartabstop: 4814 return &(buf->b_p_vts); 4815 case kOptKeymap: 4816 return &(buf->b_p_keymap); 4817 case kOptSigncolumn: 4818 return &(win->w_p_scl); 4819 case kOptWinhighlight: 4820 return &(win->w_p_winhl); 4821 case kOptWinblend: 4822 return &(win->w_p_winbl); 4823 case kOptStatuscolumn: 4824 return &(win->w_p_stc); 4825 default: 4826 iemsg(_("E356: get_varp ERROR")); 4827 } 4828 // always return a valid pointer to avoid a crash! 4829 return &(buf->b_p_wm); 4830 } 4831 4832 /// Get option index from option pointer 4833 static inline OptIndex get_opt_idx(vimoption_T *opt) 4834 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 4835 { 4836 return (OptIndex)(opt - options); 4837 } 4838 4839 /// Get pointer to option variable. 4840 static inline void *get_varp(vimoption_T *p) 4841 { 4842 return get_varp_from(p, curbuf, curwin); 4843 } 4844 4845 /// Get the value of 'equalprg', either the buffer-local one or the global one. 4846 char *get_equalprg(void) 4847 { 4848 if (*curbuf->b_p_ep == NUL) { 4849 return p_ep; 4850 } 4851 return curbuf->b_p_ep; 4852 } 4853 4854 /// Get the value of 'findfunc', either the buffer-local one or the global one. 4855 char *get_findfunc(void) 4856 { 4857 if (*curbuf->b_p_ffu == NUL) { 4858 return p_ffu; 4859 } 4860 return curbuf->b_p_ffu; 4861 } 4862 4863 /// Copy options from one window to another. 4864 /// Used when splitting a window. 4865 void win_copy_options(win_T *wp_from, win_T *wp_to) 4866 { 4867 copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt); 4868 copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt); 4869 didset_window_options(wp_to, true); 4870 } 4871 4872 static char *copy_option_val(const char *val) 4873 { 4874 if (val == empty_string_option) { 4875 return empty_string_option; // no need to allocate memory 4876 } 4877 return xstrdup(val); 4878 } 4879 4880 /// Copy the options from one winopt_T to another. 4881 /// Doesn't free the old option values in "to", use clear_winopt() for that. 4882 /// The 'scroll' option is not copied, because it depends on the window height. 4883 /// The 'previewwindow' option is reset, there can be only one preview window. 4884 void copy_winopt(winopt_T *from, winopt_T *to) 4885 { 4886 to->wo_arab = from->wo_arab; 4887 to->wo_list = from->wo_list; 4888 to->wo_lcs = copy_option_val(from->wo_lcs); 4889 to->wo_fcs = copy_option_val(from->wo_fcs); 4890 to->wo_nu = from->wo_nu; 4891 to->wo_rnu = from->wo_rnu; 4892 to->wo_ve = copy_option_val(from->wo_ve); 4893 to->wo_ve_flags = from->wo_ve_flags; 4894 to->wo_nuw = from->wo_nuw; 4895 to->wo_rl = from->wo_rl; 4896 to->wo_rlc = copy_option_val(from->wo_rlc); 4897 to->wo_sbr = copy_option_val(from->wo_sbr); 4898 to->wo_stl = copy_option_val(from->wo_stl); 4899 to->wo_wbr = copy_option_val(from->wo_wbr); 4900 to->wo_wrap = from->wo_wrap; 4901 to->wo_wrap_save = from->wo_wrap_save; 4902 to->wo_lbr = from->wo_lbr; 4903 to->wo_bri = from->wo_bri; 4904 to->wo_briopt = copy_option_val(from->wo_briopt); 4905 to->wo_scb = from->wo_scb; 4906 to->wo_scb_save = from->wo_scb_save; 4907 to->wo_sms = from->wo_sms; 4908 to->wo_crb = from->wo_crb; 4909 to->wo_crb_save = from->wo_crb_save; 4910 to->wo_siso = from->wo_siso; 4911 to->wo_so = from->wo_so; 4912 to->wo_spell = from->wo_spell; 4913 to->wo_cuc = from->wo_cuc; 4914 to->wo_cul = from->wo_cul; 4915 to->wo_culopt = copy_option_val(from->wo_culopt); 4916 to->wo_cc = copy_option_val(from->wo_cc); 4917 to->wo_diff = from->wo_diff; 4918 to->wo_diff_saved = from->wo_diff_saved; 4919 to->wo_eiw = copy_option_val(from->wo_eiw); 4920 to->wo_cocu = copy_option_val(from->wo_cocu); 4921 to->wo_cole = from->wo_cole; 4922 to->wo_fdc = copy_option_val(from->wo_fdc); 4923 to->wo_fdc_save = from->wo_diff_saved ? xstrdup(from->wo_fdc_save) : empty_string_option; 4924 to->wo_fen = from->wo_fen; 4925 to->wo_fen_save = from->wo_fen_save; 4926 to->wo_fdi = copy_option_val(from->wo_fdi); 4927 to->wo_fml = from->wo_fml; 4928 to->wo_fdl = from->wo_fdl; 4929 to->wo_fdl_save = from->wo_fdl_save; 4930 to->wo_fdm = copy_option_val(from->wo_fdm); 4931 to->wo_fdm_save = from->wo_diff_saved ? xstrdup(from->wo_fdm_save) : empty_string_option; 4932 to->wo_fdn = from->wo_fdn; 4933 to->wo_fde = copy_option_val(from->wo_fde); 4934 to->wo_fdt = copy_option_val(from->wo_fdt); 4935 to->wo_fmr = copy_option_val(from->wo_fmr); 4936 to->wo_scl = copy_option_val(from->wo_scl); 4937 to->wo_lhi = from->wo_lhi; 4938 to->wo_winhl = copy_option_val(from->wo_winhl); 4939 to->wo_winbl = from->wo_winbl; 4940 to->wo_stc = copy_option_val(from->wo_stc); 4941 4942 to->wo_wrap_flags = from->wo_wrap_flags; 4943 to->wo_stl_flags = from->wo_stl_flags; 4944 to->wo_wbr_flags = from->wo_wbr_flags; 4945 to->wo_fde_flags = from->wo_fde_flags; 4946 to->wo_fdt_flags = from->wo_fdt_flags; 4947 4948 // Copy the script context so that we know were the value was last set. 4949 memmove(to->wo_script_ctx, from->wo_script_ctx, sizeof(to->wo_script_ctx)); 4950 check_winopt(to); // don't want NULL pointers 4951 } 4952 4953 /// Check string options in a window for a NULL value. 4954 static void check_win_options(win_T *win) 4955 { 4956 check_winopt(&win->w_onebuf_opt); 4957 check_winopt(&win->w_allbuf_opt); 4958 } 4959 4960 /// Check for NULL pointers in a winopt_T and replace them with empty_string_option. 4961 static void check_winopt(winopt_T *wop) 4962 { 4963 check_string_option(&wop->wo_fdc); 4964 check_string_option(&wop->wo_fdc_save); 4965 check_string_option(&wop->wo_fdi); 4966 check_string_option(&wop->wo_fdm); 4967 check_string_option(&wop->wo_fdm_save); 4968 check_string_option(&wop->wo_fde); 4969 check_string_option(&wop->wo_fdt); 4970 check_string_option(&wop->wo_fmr); 4971 check_string_option(&wop->wo_eiw); 4972 check_string_option(&wop->wo_scl); 4973 check_string_option(&wop->wo_rlc); 4974 check_string_option(&wop->wo_sbr); 4975 check_string_option(&wop->wo_stl); 4976 check_string_option(&wop->wo_culopt); 4977 check_string_option(&wop->wo_cc); 4978 check_string_option(&wop->wo_cocu); 4979 check_string_option(&wop->wo_briopt); 4980 check_string_option(&wop->wo_winhl); 4981 check_string_option(&wop->wo_lcs); 4982 check_string_option(&wop->wo_fcs); 4983 check_string_option(&wop->wo_ve); 4984 check_string_option(&wop->wo_wbr); 4985 check_string_option(&wop->wo_stc); 4986 } 4987 4988 /// Free the allocated memory inside a winopt_T. 4989 void clear_winopt(winopt_T *wop) 4990 { 4991 clear_string_option(&wop->wo_fdc); 4992 clear_string_option(&wop->wo_fdc_save); 4993 clear_string_option(&wop->wo_fdi); 4994 clear_string_option(&wop->wo_fdm); 4995 clear_string_option(&wop->wo_fdm_save); 4996 clear_string_option(&wop->wo_fde); 4997 clear_string_option(&wop->wo_fdt); 4998 clear_string_option(&wop->wo_fmr); 4999 clear_string_option(&wop->wo_eiw); 5000 clear_string_option(&wop->wo_scl); 5001 clear_string_option(&wop->wo_rlc); 5002 clear_string_option(&wop->wo_sbr); 5003 clear_string_option(&wop->wo_stl); 5004 clear_string_option(&wop->wo_culopt); 5005 clear_string_option(&wop->wo_cc); 5006 clear_string_option(&wop->wo_cocu); 5007 clear_string_option(&wop->wo_briopt); 5008 clear_string_option(&wop->wo_winhl); 5009 clear_string_option(&wop->wo_lcs); 5010 clear_string_option(&wop->wo_fcs); 5011 clear_string_option(&wop->wo_ve); 5012 clear_string_option(&wop->wo_wbr); 5013 clear_string_option(&wop->wo_stc); 5014 } 5015 5016 void didset_window_options(win_T *wp, bool valid_cursor) 5017 { 5018 // Set w_leftcol or w_skipcol to zero. 5019 if (wp->w_p_wrap) { 5020 wp->w_leftcol = 0; 5021 } else { 5022 wp->w_skipcol = 0; 5023 } 5024 check_colorcolumn(NULL, wp); 5025 briopt_check(NULL, wp); 5026 fill_culopt_flags(NULL, wp); 5027 set_chars_option(wp, wp->w_p_fcs, kFillchars, true, NULL, 0); 5028 set_chars_option(wp, wp->w_p_lcs, kListchars, true, NULL, 0); 5029 parse_winhl_opt(NULL, wp); // sets w_hl_needs_update also for w_p_winbl 5030 check_blending(wp); 5031 set_winbar_win(wp, false, valid_cursor); 5032 check_signcolumn(NULL, wp); 5033 wp->w_grid_alloc.blending = wp->w_p_winbl > 0; 5034 } 5035 5036 #define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].script_ctx 5037 5038 /// Copy global option values to local options for one buffer. 5039 /// Used when creating a new buffer and sometimes when entering a buffer. 5040 /// flags: 5041 /// BCO_ENTER We will enter the buffer "buf". 5042 /// BCO_ALWAYS Always copy the options, but only set b_p_initialized when 5043 /// appropriate. 5044 /// BCO_NOHELP Don't copy the values to a help buffer. 5045 void buf_copy_options(buf_T *buf, int flags) 5046 { 5047 bool should_copy = true; 5048 char *save_p_isk = NULL; // init for GCC 5049 bool did_isk = false; 5050 5051 // Skip this when the option defaults have not been set yet. Happens when 5052 // main() allocates the first buffer. 5053 if (p_cpo != NULL) { 5054 // 5055 // Always copy when entering and 'cpo' contains 'S'. 5056 // Don't copy when already initialized. 5057 // Don't copy when 'cpo' contains 's' and not entering. 5058 // 'S' BCO_ENTER initialized 's' should_copy 5059 // yes yes X X true 5060 // yes no yes X false 5061 // no X yes X false 5062 // X no no yes false 5063 // X no no no true 5064 // no yes no X true 5065 /// 5066 if ((vim_strchr(p_cpo, CPO_BUFOPTGLOB) == NULL || !(flags & BCO_ENTER)) 5067 && (buf->b_p_initialized 5068 || (!(flags & BCO_ENTER) 5069 && vim_strchr(p_cpo, CPO_BUFOPT) != NULL))) { 5070 should_copy = false; 5071 } 5072 5073 if (should_copy || (flags & BCO_ALWAYS)) { 5074 CLEAR_FIELD(buf->b_p_script_ctx); 5075 // Don't copy the options specific to a help buffer when 5076 // BCO_NOHELP is given or the options were initialized already 5077 // (jumping back to a help file with CTRL-T or CTRL-O) 5078 bool dont_do_help = ((flags & BCO_NOHELP) && buf->b_help) || buf->b_p_initialized; 5079 if (dont_do_help) { // don't free b_p_isk 5080 save_p_isk = buf->b_p_isk; 5081 buf->b_p_isk = NULL; 5082 } 5083 // Always free the allocated strings. If not already initialized, 5084 // reset 'readonly' and copy 'fileformat'. 5085 if (!buf->b_p_initialized) { 5086 free_buf_options(buf, true); 5087 buf->b_p_ro = false; // don't copy readonly 5088 buf->b_p_fenc = xstrdup(p_fenc); 5089 switch (*p_ffs) { 5090 case 'm': 5091 buf->b_p_ff = xstrdup("mac"); 5092 break; 5093 case 'd': 5094 buf->b_p_ff = xstrdup("dos"); 5095 break; 5096 case 'u': 5097 buf->b_p_ff = xstrdup("unix"); 5098 break; 5099 default: 5100 buf->b_p_ff = xstrdup(p_ff); 5101 break; 5102 } 5103 buf->b_p_bh = empty_string_option; 5104 buf->b_p_bt = empty_string_option; 5105 } else { 5106 free_buf_options(buf, false); 5107 } 5108 5109 buf->b_p_ai = p_ai; 5110 COPY_OPT_SCTX(buf, kBufOptAutoindent); 5111 buf->b_p_ai_nopaste = p_ai_nopaste; 5112 buf->b_p_sw = p_sw; 5113 COPY_OPT_SCTX(buf, kBufOptShiftwidth); 5114 buf->b_p_scbk = p_scbk; 5115 COPY_OPT_SCTX(buf, kBufOptScrollback); 5116 buf->b_p_tw = p_tw; 5117 COPY_OPT_SCTX(buf, kBufOptTextwidth); 5118 buf->b_p_tw_nopaste = p_tw_nopaste; 5119 buf->b_p_tw_nobin = p_tw_nobin; 5120 buf->b_p_wm = p_wm; 5121 COPY_OPT_SCTX(buf, kBufOptWrapmargin); 5122 buf->b_p_wm_nopaste = p_wm_nopaste; 5123 buf->b_p_wm_nobin = p_wm_nobin; 5124 buf->b_p_bin = p_bin; 5125 COPY_OPT_SCTX(buf, kBufOptBinary); 5126 buf->b_p_bomb = p_bomb; 5127 COPY_OPT_SCTX(buf, kBufOptBomb); 5128 buf->b_p_et = p_et; 5129 COPY_OPT_SCTX(buf, kBufOptExpandtab); 5130 buf->b_p_fixeol = p_fixeol; 5131 COPY_OPT_SCTX(buf, kBufOptFixendofline); 5132 buf->b_p_et_nobin = p_et_nobin; 5133 buf->b_p_et_nopaste = p_et_nopaste; 5134 buf->b_p_ml = p_ml; 5135 COPY_OPT_SCTX(buf, kBufOptModeline); 5136 buf->b_p_ml_nobin = p_ml_nobin; 5137 buf->b_p_inf = p_inf; 5138 COPY_OPT_SCTX(buf, kBufOptInfercase); 5139 if (cmdmod.cmod_flags & CMOD_NOSWAPFILE) { 5140 buf->b_p_swf = false; 5141 } else { 5142 buf->b_p_swf = p_swf; 5143 COPY_OPT_SCTX(buf, kBufOptSwapfile); 5144 } 5145 buf->b_p_cpt = xstrdup(p_cpt); 5146 COPY_OPT_SCTX(buf, kBufOptComplete); 5147 set_buflocal_cpt_callbacks(buf); 5148 #ifdef BACKSLASH_IN_FILENAME 5149 buf->b_p_csl = xstrdup(p_csl); 5150 COPY_OPT_SCTX(buf, kBufOptCompleteslash); 5151 #endif 5152 buf->b_p_cfu = xstrdup(p_cfu); 5153 COPY_OPT_SCTX(buf, kBufOptCompletefunc); 5154 set_buflocal_cfu_callback(buf); 5155 buf->b_p_ofu = xstrdup(p_ofu); 5156 COPY_OPT_SCTX(buf, kBufOptOmnifunc); 5157 set_buflocal_ofu_callback(buf); 5158 buf->b_p_tfu = xstrdup(p_tfu); 5159 COPY_OPT_SCTX(buf, kBufOptTagfunc); 5160 set_buflocal_tfu_callback(buf); 5161 buf->b_p_sts = p_sts; 5162 COPY_OPT_SCTX(buf, kBufOptSofttabstop); 5163 buf->b_p_sts_nopaste = p_sts_nopaste; 5164 buf->b_p_vsts = xstrdup(p_vsts); 5165 COPY_OPT_SCTX(buf, kBufOptVarsofttabstop); 5166 if (p_vsts && p_vsts != empty_string_option) { 5167 tabstop_set(p_vsts, &buf->b_p_vsts_array); 5168 } else { 5169 buf->b_p_vsts_array = NULL; 5170 } 5171 buf->b_p_vsts_nopaste = p_vsts_nopaste ? xstrdup(p_vsts_nopaste) : NULL; 5172 buf->b_p_com = xstrdup(p_com); 5173 COPY_OPT_SCTX(buf, kBufOptComments); 5174 buf->b_p_cms = xstrdup(p_cms); 5175 COPY_OPT_SCTX(buf, kBufOptCommentstring); 5176 buf->b_p_fo = xstrdup(p_fo); 5177 COPY_OPT_SCTX(buf, kBufOptFormatoptions); 5178 buf->b_p_flp = xstrdup(p_flp); 5179 COPY_OPT_SCTX(buf, kBufOptFormatlistpat); 5180 buf->b_p_nf = xstrdup(p_nf); 5181 COPY_OPT_SCTX(buf, kBufOptNrformats); 5182 buf->b_p_mps = xstrdup(p_mps); 5183 COPY_OPT_SCTX(buf, kBufOptMatchpairs); 5184 buf->b_p_si = p_si; 5185 COPY_OPT_SCTX(buf, kBufOptSmartindent); 5186 buf->b_p_channel = 0; 5187 buf->b_p_ci = p_ci; 5188 5189 COPY_OPT_SCTX(buf, kBufOptCopyindent); 5190 buf->b_p_cin = p_cin; 5191 COPY_OPT_SCTX(buf, kBufOptCindent); 5192 buf->b_p_cink = xstrdup(p_cink); 5193 COPY_OPT_SCTX(buf, kBufOptCinkeys); 5194 buf->b_p_cino = xstrdup(p_cino); 5195 COPY_OPT_SCTX(buf, kBufOptCinoptions); 5196 buf->b_p_cinsd = xstrdup(p_cinsd); 5197 COPY_OPT_SCTX(buf, kBufOptCinscopedecls); 5198 buf->b_p_lop = xstrdup(p_lop); 5199 COPY_OPT_SCTX(buf, kBufOptLispoptions); 5200 5201 // Don't copy 'filetype', it must be detected 5202 buf->b_p_ft = empty_string_option; 5203 buf->b_p_pi = p_pi; 5204 COPY_OPT_SCTX(buf, kBufOptPreserveindent); 5205 buf->b_p_cinw = xstrdup(p_cinw); 5206 COPY_OPT_SCTX(buf, kBufOptCinwords); 5207 buf->b_p_lisp = p_lisp; 5208 COPY_OPT_SCTX(buf, kBufOptLisp); 5209 // Don't copy 'syntax', it must be set 5210 buf->b_p_syn = empty_string_option; 5211 buf->b_p_smc = p_smc; 5212 COPY_OPT_SCTX(buf, kBufOptSynmaxcol); 5213 buf->b_s.b_syn_isk = empty_string_option; 5214 buf->b_s.b_p_spc = xstrdup(p_spc); 5215 COPY_OPT_SCTX(buf, kBufOptSpellcapcheck); 5216 compile_cap_prog(&buf->b_s); 5217 buf->b_s.b_p_spf = xstrdup(p_spf); 5218 COPY_OPT_SCTX(buf, kBufOptSpellfile); 5219 buf->b_s.b_p_spl = xstrdup(p_spl); 5220 COPY_OPT_SCTX(buf, kBufOptSpelllang); 5221 buf->b_s.b_p_spo = xstrdup(p_spo); 5222 COPY_OPT_SCTX(buf, kBufOptSpelloptions); 5223 buf->b_s.b_p_spo_flags = spo_flags; 5224 buf->b_p_inde = xstrdup(p_inde); 5225 COPY_OPT_SCTX(buf, kBufOptIndentexpr); 5226 buf->b_p_indk = xstrdup(p_indk); 5227 COPY_OPT_SCTX(buf, kBufOptIndentkeys); 5228 buf->b_p_fp = empty_string_option; 5229 buf->b_p_fex = xstrdup(p_fex); 5230 COPY_OPT_SCTX(buf, kBufOptFormatexpr); 5231 buf->b_p_sua = xstrdup(p_sua); 5232 COPY_OPT_SCTX(buf, kBufOptSuffixesadd); 5233 buf->b_p_keymap = xstrdup(p_keymap); 5234 COPY_OPT_SCTX(buf, kBufOptKeymap); 5235 buf->b_kmap_state |= KEYMAP_INIT; 5236 // This isn't really an option, but copying the langmap and IME 5237 // state from the current buffer is better than resetting it. 5238 buf->b_p_iminsert = p_iminsert; 5239 COPY_OPT_SCTX(buf, kBufOptIminsert); 5240 buf->b_p_imsearch = p_imsearch; 5241 COPY_OPT_SCTX(buf, kBufOptImsearch); 5242 5243 // options that are normally global but also have a local value 5244 // are not copied, start using the global value 5245 buf->b_p_ac = -1; 5246 buf->b_p_ar = -1; 5247 buf->b_p_fs = -1; 5248 buf->b_p_ul = NO_LOCAL_UNDOLEVEL; 5249 buf->b_p_bkc = empty_string_option; 5250 buf->b_bkc_flags = 0; 5251 buf->b_p_gefm = empty_string_option; 5252 buf->b_p_gp = empty_string_option; 5253 buf->b_p_mp = empty_string_option; 5254 buf->b_p_efm = empty_string_option; 5255 buf->b_p_ep = empty_string_option; 5256 buf->b_p_ffu = empty_string_option; 5257 buf->b_p_kp = empty_string_option; 5258 buf->b_p_path = empty_string_option; 5259 buf->b_p_tags = empty_string_option; 5260 buf->b_p_tc = empty_string_option; 5261 buf->b_tc_flags = 0; 5262 buf->b_p_def = empty_string_option; 5263 buf->b_p_inc = empty_string_option; 5264 buf->b_p_inex = xstrdup(p_inex); 5265 COPY_OPT_SCTX(buf, kBufOptIncludeexpr); 5266 buf->b_p_cot = empty_string_option; 5267 buf->b_cot_flags = 0; 5268 buf->b_p_dict = empty_string_option; 5269 buf->b_p_dia = empty_string_option; 5270 buf->b_p_tsr = empty_string_option; 5271 buf->b_p_tsrfu = empty_string_option; 5272 buf->b_p_qe = xstrdup(p_qe); 5273 COPY_OPT_SCTX(buf, kBufOptQuoteescape); 5274 buf->b_p_udf = p_udf; 5275 COPY_OPT_SCTX(buf, kBufOptUndofile); 5276 buf->b_p_lw = empty_string_option; 5277 buf->b_p_menc = empty_string_option; 5278 5279 // Don't copy the options set by ex_help(), use the saved values, 5280 // when going from a help buffer to a non-help buffer. 5281 // Don't touch these at all when BCO_NOHELP is used and going from 5282 // or to a help buffer. 5283 if (dont_do_help) { 5284 buf->b_p_isk = save_p_isk; 5285 if (p_vts && *p_vts != NUL && !buf->b_p_vts_array) { 5286 tabstop_set(p_vts, &buf->b_p_vts_array); 5287 } else { 5288 buf->b_p_vts_array = NULL; 5289 } 5290 } else { 5291 buf->b_p_isk = xstrdup(p_isk); 5292 COPY_OPT_SCTX(buf, kBufOptIskeyword); 5293 did_isk = true; 5294 buf->b_p_ts = p_ts; 5295 COPY_OPT_SCTX(buf, kBufOptTabstop); 5296 buf->b_p_vts = xstrdup(p_vts); 5297 COPY_OPT_SCTX(buf, kBufOptVartabstop); 5298 if (p_vts && *p_vts != NUL && !buf->b_p_vts_array) { 5299 tabstop_set(p_vts, &buf->b_p_vts_array); 5300 } else { 5301 buf->b_p_vts_array = NULL; 5302 } 5303 buf->b_help = false; 5304 if (buf->b_p_bt[0] == 'h') { 5305 clear_string_option(&buf->b_p_bt); 5306 } 5307 buf->b_p_ma = p_ma; 5308 COPY_OPT_SCTX(buf, kBufOptModifiable); 5309 } 5310 } 5311 5312 // When the options should be copied (ignoring BCO_ALWAYS), set the 5313 // flag that indicates that the options have been initialized. 5314 if (should_copy) { 5315 buf->b_p_initialized = true; 5316 } 5317 } 5318 5319 check_buf_options(buf); // make sure we don't have NULLs 5320 if (did_isk) { 5321 buf_init_chartab(buf, false); 5322 } 5323 } 5324 5325 /// Reset the 'modifiable' option and its default value. 5326 void reset_modifiable(void) 5327 { 5328 curbuf->b_p_ma = false; 5329 p_ma = false; 5330 change_option_default(kOptModifiable, BOOLEAN_OPTVAL(false)); 5331 } 5332 5333 /// Set the global value for 'iminsert' to the local value. 5334 void set_iminsert_global(buf_T *buf) 5335 { 5336 p_iminsert = buf->b_p_iminsert; 5337 } 5338 5339 /// Set the global value for 'imsearch' to the local value. 5340 void set_imsearch_global(buf_T *buf) 5341 { 5342 p_imsearch = buf->b_p_imsearch; 5343 } 5344 5345 static OptIndex expand_option_idx = kOptInvalid; 5346 static int expand_option_start_col = 0; 5347 static char expand_option_name[5] = { 't', '_', NUL, NUL, NUL }; 5348 static int expand_option_flags = 0; 5349 static bool expand_option_append = false; 5350 5351 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 5352 void set_context_in_set_cmd(expand_T *xp, char *arg, int opt_flags) 5353 { 5354 expand_option_flags = opt_flags; 5355 5356 xp->xp_context = EXPAND_SETTINGS; 5357 if (*arg == NUL) { 5358 xp->xp_pattern = arg; 5359 return; 5360 } 5361 char *const argend = arg + strlen(arg); 5362 char *p = argend - 1; 5363 if (*p == ' ' && *(p - 1) != '\\') { 5364 xp->xp_pattern = p + 1; 5365 return; 5366 } 5367 while (p > arg) { 5368 char *s = p; 5369 // count number of backslashes before ' ' or ',' 5370 if (*p == ' ' || *p == ',') { 5371 while (s > arg && *(s - 1) == '\\') { 5372 s--; 5373 } 5374 } 5375 // break at a space with an even number of backslashes 5376 if (*p == ' ' && ((p - s) & 1) == 0) { 5377 p++; 5378 break; 5379 } 5380 p--; 5381 } 5382 if (strncmp(p, "no", 2) == 0) { 5383 xp->xp_context = EXPAND_BOOL_SETTINGS; 5384 xp->xp_prefix = XP_PREFIX_NO; 5385 p += 2; 5386 } else if (strncmp(p, "inv", 3) == 0) { 5387 xp->xp_context = EXPAND_BOOL_SETTINGS; 5388 xp->xp_prefix = XP_PREFIX_INV; 5389 p += 3; 5390 } 5391 xp->xp_pattern = p; 5392 arg = p; 5393 5394 char nextchar; 5395 uint32_t flags = 0; 5396 OptIndex opt_idx = 0; 5397 bool is_term_option = false; 5398 5399 if (*arg == '<') { 5400 while (*p != '>') { 5401 if (*p++ == NUL) { // expand terminal option name 5402 return; 5403 } 5404 } 5405 int key = get_special_key_code(arg + 1); 5406 if (key == 0) { // unknown name 5407 xp->xp_context = EXPAND_NOTHING; 5408 return; 5409 } 5410 nextchar = *++p; 5411 is_term_option = true; 5412 expand_option_name[2] = (char)(uint8_t)KEY2TERMCAP0(key); 5413 expand_option_name[3] = (char)(uint8_t)KEY2TERMCAP1(key); 5414 } else { 5415 if (p[0] == 't' && p[1] == '_') { 5416 p += 2; 5417 if (*p != NUL) { 5418 p++; 5419 } 5420 if (*p == NUL) { 5421 return; // expand option name 5422 } 5423 nextchar = *++p; 5424 is_term_option = true; 5425 expand_option_name[2] = p[-2]; 5426 expand_option_name[3] = p[-1]; 5427 } else { 5428 // Allow * wildcard. 5429 while (ASCII_ISALNUM(*p) || *p == '_' || *p == '*') { 5430 p++; 5431 } 5432 if (*p == NUL) { 5433 return; 5434 } 5435 nextchar = *p; 5436 opt_idx = find_option_len(arg, (size_t)(p - arg)); 5437 if (opt_idx == kOptInvalid || is_option_hidden(opt_idx)) { 5438 xp->xp_context = EXPAND_NOTHING; 5439 return; 5440 } 5441 flags = options[opt_idx].flags; 5442 if (option_has_type(opt_idx, kOptValTypeBoolean)) { 5443 xp->xp_context = EXPAND_NOTHING; 5444 return; 5445 } 5446 } 5447 } 5448 // handle "-=" and "+=" 5449 expand_option_append = false; 5450 bool expand_option_subtract = false; 5451 if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=') { 5452 if (nextchar == '-') { 5453 expand_option_subtract = true; 5454 } 5455 if (nextchar == '+' || nextchar == '^') { 5456 expand_option_append = true; 5457 } 5458 p++; 5459 nextchar = '='; 5460 } 5461 if ((nextchar != '=' && nextchar != ':') 5462 || xp->xp_context == EXPAND_BOOL_SETTINGS) { 5463 xp->xp_context = EXPAND_UNSUCCESSFUL; 5464 return; 5465 } 5466 5467 // Below are for handling expanding a specific option's value after the '=' or ':' 5468 5469 if (is_term_option) { 5470 expand_option_idx = kOptInvalid; 5471 } else { 5472 expand_option_idx = opt_idx; 5473 } 5474 5475 xp->xp_pattern = p + 1; 5476 expand_option_start_col = (int)(p + 1 - xp->xp_line); 5477 5478 // Certain options currently have special case handling to reuse the 5479 // expansion logic with other commands. 5480 if (options[opt_idx].var == &p_syn) { 5481 xp->xp_context = EXPAND_OWNSYNTAX; 5482 return; 5483 } 5484 if (options[opt_idx].var == &p_ft) { 5485 xp->xp_context = EXPAND_FILETYPE; 5486 return; 5487 } 5488 if (options[opt_idx].var == &p_keymap) { 5489 xp->xp_context = EXPAND_KEYMAP; 5490 return; 5491 } 5492 5493 // Now pick. If the option has a custom expander, use that. Otherwise, just 5494 // fill with the existing option value. 5495 if (expand_option_subtract) { 5496 xp->xp_context = EXPAND_SETTING_SUBTRACT; 5497 return; 5498 } else if (expand_option_idx != kOptInvalid && options[expand_option_idx].opt_expand_cb != NULL) { 5499 xp->xp_context = EXPAND_STRING_SETTING; 5500 } else if (*xp->xp_pattern == NUL) { 5501 xp->xp_context = EXPAND_OLD_SETTING; 5502 return; 5503 } else { 5504 xp->xp_context = EXPAND_NOTHING; 5505 } 5506 5507 if (is_term_option || option_has_type(opt_idx, kOptValTypeNumber)) { 5508 return; 5509 } 5510 5511 // Only string options below 5512 5513 // Options that have kOptFlagExpand are considered to all use file/dir expansion. 5514 if (flags & kOptFlagExpand) { 5515 p = options[opt_idx].var; 5516 if (p == (char *)&p_bdir 5517 || p == (char *)&p_dir 5518 || p == (char *)&p_path 5519 || p == (char *)&p_pp 5520 || p == (char *)&p_rtp 5521 || p == (char *)&p_cdpath 5522 || p == (char *)&p_vdir) { 5523 xp->xp_context = EXPAND_DIRECTORIES; 5524 if (p == (char *)&p_path || p == (char *)&p_cdpath) { 5525 xp->xp_backslash = XP_BS_THREE; 5526 } else { 5527 xp->xp_backslash = XP_BS_ONE; 5528 } 5529 } else { 5530 xp->xp_context = EXPAND_FILES; 5531 // for 'tags' need three backslashes for a space 5532 if (p == (char *)&p_tags) { 5533 xp->xp_backslash = XP_BS_THREE; 5534 } else { 5535 xp->xp_backslash = XP_BS_ONE; 5536 } 5537 } 5538 if (flags & kOptFlagComma) { 5539 xp->xp_backslash |= XP_BS_COMMA; 5540 } 5541 } 5542 5543 // For an option that is a list of file names, or comma/colon-separated 5544 // values, split it by the delimiter and find the start of the current 5545 // pattern, while accounting for backslash-escaped space/commas/colons. 5546 // Triple-backslashed escaped file names (e.g. 'path') can also be 5547 // delimited by space. 5548 if ((flags & kOptFlagExpand) || (flags & kOptFlagComma) || (flags & kOptFlagColon)) { 5549 for (p = argend - 1; p > xp->xp_pattern; p--) { 5550 // count number of backslashes before ' ' or ',' 5551 if (*p == ' ' || *p == ',' || (*p == ':' && (flags & kOptFlagColon))) { 5552 char *s = p; 5553 while (s > xp->xp_pattern && *(s - 1) == '\\') { 5554 s--; 5555 } 5556 if ((*p == ' ' && ((xp->xp_backslash & XP_BS_THREE) && (p - s) < 3)) 5557 #if defined(BACKSLASH_IN_FILENAME) 5558 || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 1) 5559 #else 5560 || (*p == ',' && (flags & kOptFlagComma) && (p - s) < 2) 5561 #endif 5562 || (*p == ':' && (flags & kOptFlagColon))) { 5563 xp->xp_pattern = p + 1; 5564 break; 5565 } 5566 } 5567 } 5568 } 5569 5570 // An option that is a list of single-character flags should always start 5571 // at the end as we don't complete words. 5572 if (flags & kOptFlagFlagList) { 5573 xp->xp_pattern = argend; 5574 } 5575 5576 // Some options can either be using file/dir expansions, or custom value 5577 // expansion depending on what the user typed. Unfortunately we have to 5578 // manually handle it here to make sure we have the correct xp_context set. 5579 // for 'spellsuggest' start at "file:" 5580 if (options[opt_idx].var == &p_sps) { 5581 if (strncmp(xp->xp_pattern, "file:", 5) == 0) { 5582 xp->xp_pattern += 5; 5583 return; 5584 } else if (options[expand_option_idx].opt_expand_cb != NULL) { 5585 xp->xp_context = EXPAND_STRING_SETTING; 5586 } 5587 } 5588 } 5589 5590 /// Returns true if "str" either matches "regmatch" or fuzzy matches "pat". 5591 /// 5592 /// If "test_only" is true and "fuzzy" is false and if "str" matches the regular 5593 /// expression "regmatch", then returns true. Otherwise returns false. 5594 /// 5595 /// If "test_only" is false and "fuzzy" is false and if "str" matches the 5596 /// regular expression "regmatch", then stores the match in matches[idx] and 5597 /// returns true. 5598 /// 5599 /// If "test_only" is true and "fuzzy" is true and if "str" fuzzy matches 5600 /// "fuzzystr", then returns true. Otherwise returns false. 5601 /// 5602 /// If "test_only" is false and "fuzzy" is true and if "str" fuzzy matches 5603 /// "fuzzystr", then stores the match details in fuzmatch[idx] and returns true. 5604 static bool match_str(char *const str, regmatch_T *const regmatch, char **const matches, 5605 const int idx, const bool test_only, const bool fuzzy, 5606 const char *const fuzzystr, fuzmatch_str_T *const fuzmatch) 5607 { 5608 if (!fuzzy) { 5609 if (vim_regexec(regmatch, str, 0)) { 5610 if (!test_only) { 5611 matches[idx] = xstrdup(str); 5612 } 5613 return true; 5614 } 5615 } else { 5616 const int score = fuzzy_match_str(str, fuzzystr); 5617 if (score != FUZZY_SCORE_NONE) { 5618 if (!test_only) { 5619 fuzmatch[idx].idx = idx; 5620 fuzmatch[idx].str = xstrdup(str); 5621 fuzmatch[idx].score = score; 5622 } 5623 return true; 5624 } 5625 } 5626 return false; 5627 } 5628 5629 int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numMatches, 5630 char ***matches, const bool can_fuzzy) 5631 { 5632 int num_normal = 0; // Nr of matching non-term-code settings 5633 int count = 0; 5634 static char *(names[]) = { "all" }; 5635 int ic = regmatch->rm_ic; // remember the ignore-case flag 5636 5637 fuzmatch_str_T *fuzmatch = NULL; 5638 const bool fuzzy = can_fuzzy && cmdline_fuzzy_complete(fuzzystr); 5639 5640 // do this loop twice: 5641 // loop == 0: count the number of matching options 5642 // loop == 1: copy the matching options into allocated memory 5643 for (int loop = 0; loop <= 1; loop++) { 5644 regmatch->rm_ic = ic; 5645 if (xp->xp_context != EXPAND_BOOL_SETTINGS) { 5646 for (int match = 0; match < (int)ARRAY_SIZE(names); 5647 match++) { 5648 if (match_str(names[match], regmatch, *matches, 5649 count, (loop == 0), fuzzy, fuzzystr, fuzmatch)) { 5650 if (loop == 0) { 5651 num_normal++; 5652 } else { 5653 count++; 5654 } 5655 } 5656 } 5657 } 5658 char *str; 5659 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 5660 str = options[opt_idx].fullname; 5661 if (is_option_hidden(opt_idx)) { 5662 continue; 5663 } 5664 if (xp->xp_context == EXPAND_BOOL_SETTINGS 5665 && !(option_has_type(opt_idx, kOptValTypeBoolean))) { 5666 continue; 5667 } 5668 5669 if (match_str(str, regmatch, *matches, count, (loop == 0), 5670 fuzzy, fuzzystr, fuzmatch)) { 5671 if (loop == 0) { 5672 num_normal++; 5673 } else { 5674 count++; 5675 } 5676 } else if (!fuzzy && options[opt_idx].shortname != NULL 5677 && vim_regexec(regmatch, options[opt_idx].shortname, 0)) { 5678 // Compare against the abbreviated option name (for regular 5679 // expression match). Fuzzy matching (previous if) already 5680 // matches against both the expanded and abbreviated names. 5681 if (loop == 0) { 5682 num_normal++; 5683 } else { 5684 (*matches)[count++] = xstrdup(str); 5685 } 5686 } 5687 } 5688 5689 if (loop == 0) { 5690 if (num_normal > 0) { 5691 *numMatches = num_normal; 5692 } else { 5693 return OK; 5694 } 5695 if (!fuzzy) { 5696 *matches = xmalloc((size_t)(*numMatches) * sizeof(char *)); 5697 } else { 5698 fuzmatch = xmalloc((size_t)(*numMatches) * sizeof(fuzmatch_str_T)); 5699 } 5700 } 5701 } 5702 5703 if (fuzzy) { 5704 fuzzymatches_to_strmatches(fuzmatch, matches, count, false); 5705 } 5706 5707 return OK; 5708 } 5709 5710 /// Escape an option value that can be used on the command-line with :set. 5711 /// Caller needs to free the returned string, unless NULL is returned. 5712 static char *escape_option_str_cmdline(char *var) 5713 { 5714 // A backslash is required before some characters. This is the reverse of 5715 // what happens in do_set(). 5716 char *buf = vim_strsave_escaped(var, escape_chars); 5717 5718 #ifdef BACKSLASH_IN_FILENAME 5719 // For MS-Windows et al. we don't double backslashes at the start and 5720 // before a file name character. 5721 // The reverse is found at stropt_copy_value(). 5722 for (var = buf; *var != NUL; MB_PTR_ADV(var)) { 5723 if (var[0] == '\\' && var[1] == '\\' 5724 && expand_option_idx != kOptInvalid 5725 && (options[expand_option_idx].flags & kOptFlagExpand) 5726 && vim_isfilec((uint8_t)var[2]) 5727 && (var[2] != '\\' || (var == buf && var[4] != '\\'))) { 5728 STRMOVE(var, var + 1); 5729 } 5730 } 5731 #endif 5732 return buf; 5733 } 5734 5735 /// Expansion handler for :set= when we just want to fill in with the existing value. 5736 int ExpandOldSetting(int *numMatches, char ***matches) 5737 { 5738 char *var = NULL; 5739 5740 *numMatches = 0; 5741 *matches = xmalloc(sizeof(char *)); 5742 5743 // For a terminal key code expand_option_idx is kOptInvalid. 5744 if (expand_option_idx == kOptInvalid) { 5745 expand_option_idx = find_option(expand_option_name); 5746 } 5747 5748 if (expand_option_idx != kOptInvalid) { 5749 // Put string of option value in NameBuff. 5750 option_value2string(&options[expand_option_idx], expand_option_flags); 5751 var = NameBuff; 5752 } else { 5753 var = ""; 5754 } 5755 5756 char *buf = escape_option_str_cmdline(var); 5757 5758 (*matches)[0] = buf; 5759 *numMatches = 1; 5760 return OK; 5761 } 5762 5763 /// Expansion handler for :set=/:set+= when the option has a custom expansion handler. 5764 int ExpandStringSetting(expand_T *xp, regmatch_T *regmatch, int *numMatches, char ***matches) 5765 { 5766 if (expand_option_idx == kOptInvalid || options[expand_option_idx].opt_expand_cb == NULL) { 5767 // Not supposed to reach this. This function is only for options with 5768 // custom expansion callbacks. 5769 return FAIL; 5770 } 5771 5772 optexpand_T args = { 5773 .oe_varp = get_varp_scope(&options[expand_option_idx], expand_option_flags), 5774 .oe_idx = expand_option_idx, 5775 .oe_append = expand_option_append, 5776 .oe_regmatch = regmatch, 5777 .oe_xp = xp, 5778 .oe_set_arg = xp->xp_line + expand_option_start_col, 5779 }; 5780 args.oe_include_orig_val = !expand_option_append && (*args.oe_set_arg == NUL); 5781 5782 // Retrieve the existing value, but escape it as a reverse of setting it. 5783 // We technically only need to do this when oe_append or 5784 // oe_include_orig_val is true. 5785 option_value2string(&options[expand_option_idx], expand_option_flags); 5786 char *var = NameBuff; 5787 char *buf = escape_option_str_cmdline(var); 5788 args.oe_opt_value = buf; 5789 5790 int num_ret = options[expand_option_idx].opt_expand_cb(&args, numMatches, matches); 5791 5792 xfree(buf); 5793 return num_ret; 5794 } 5795 5796 /// Expansion handler for :set-= 5797 int ExpandSettingSubtract(expand_T *xp, regmatch_T *regmatch, int *numMatches, char ***matches) 5798 { 5799 if (expand_option_idx == kOptInvalid) { 5800 // term option 5801 return ExpandOldSetting(numMatches, matches); 5802 } 5803 5804 char *option_val = *(char **)get_option_varp_scope_from(expand_option_idx, 5805 expand_option_flags, 5806 curbuf, curwin); 5807 5808 uint32_t option_flags = options[expand_option_idx].flags; 5809 5810 if (option_has_type(expand_option_idx, kOptValTypeNumber)) { 5811 return ExpandOldSetting(numMatches, matches); 5812 } else if (option_flags & kOptFlagComma) { 5813 // Split the option by comma, then present each option to the user if 5814 // it matches the pattern. 5815 // This condition needs to go first, because 'whichwrap' has both 5816 // kOptFlagComma and kOptFlagFlagList. 5817 5818 if (*option_val == NUL) { 5819 return FAIL; 5820 } 5821 5822 // Make a copy as we need to inject null characters destructively. 5823 char *option_copy = xstrdup(option_val); 5824 char *next_val = option_copy; 5825 5826 garray_T ga; 5827 ga_init(&ga, sizeof(char *), 10); 5828 5829 do { 5830 char *item = next_val; 5831 char *comma = vim_strchr(next_val, ','); 5832 while (comma != NULL && comma != next_val && *(comma - 1) == '\\') { 5833 // "\," is interpreted as a literal comma rather than option 5834 // separator when reading options in copy_option_part(). Skip 5835 // it. 5836 comma = vim_strchr(comma + 1, ','); 5837 } 5838 if (comma != NULL) { 5839 *comma = NUL; // null-terminate this value, required by later functions 5840 next_val = comma + 1; 5841 } else { 5842 next_val = NULL; 5843 } 5844 5845 if (*item == NUL) { 5846 // empty value, don't add to list 5847 continue; 5848 } 5849 5850 if (!vim_regexec(regmatch, item, 0)) { 5851 continue; 5852 } 5853 5854 char *buf = escape_option_str_cmdline(item); 5855 GA_APPEND(char *, &ga, buf); 5856 } while (next_val != NULL); 5857 5858 xfree(option_copy); 5859 5860 *matches = ga.ga_data; 5861 *numMatches = ga.ga_len; 5862 return OK; 5863 } else if (option_flags & kOptFlagFlagList) { 5864 // Only present the flags that are set on the option as the other flags 5865 // are not meaningful to do set-= on. 5866 5867 if (*xp->xp_pattern != NUL) { 5868 // Don't suggest anything if cmdline is non-empty. Vim's set-= 5869 // behavior requires consecutive strings and it's usually 5870 // unintuitive to users if they try to subtract multiple flags at 5871 // once. 5872 return FAIL; 5873 } 5874 5875 size_t num_flags = strlen(option_val); 5876 if (num_flags == 0) { 5877 return FAIL; 5878 } 5879 5880 *matches = xmalloc(sizeof(char *) * (num_flags + 1)); 5881 5882 int count = 0; 5883 5884 (*matches)[count++] = xmemdupz(option_val, num_flags); 5885 5886 if (num_flags > 1) { 5887 // If more than one flags, split the flags up and expose each 5888 // character as individual choice. 5889 for (char *flag = option_val; *flag != NUL; flag++) { 5890 (*matches)[count++] = xmemdupz(flag, 1); 5891 } 5892 } 5893 5894 *numMatches = count; 5895 return OK; 5896 } 5897 5898 return ExpandOldSetting(numMatches, matches); 5899 } 5900 5901 /// Get the value for the numeric or string option///opp in a nice format into 5902 /// NameBuff[]. Must not be called with a hidden option! 5903 /// 5904 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 5905 /// 5906 /// TODO(famiu): Replace this with optval_to_cstr() if possible. 5907 static void option_value2string(vimoption_T *opt, int opt_flags) 5908 { 5909 void *varp = get_varp_scope(opt, opt_flags); 5910 assert(varp != NULL); 5911 5912 if (option_has_type(get_opt_idx(opt), kOptValTypeNumber)) { 5913 OptInt wc = 0; 5914 5915 if (wc_use_keyname(varp, &wc)) { 5916 xstrlcpy(NameBuff, get_special_key_name((int)wc, 0), sizeof(NameBuff)); 5917 } else if (wc != 0) { 5918 xstrlcpy(NameBuff, transchar((int)wc), sizeof(NameBuff)); 5919 } else { 5920 snprintf(NameBuff, 5921 sizeof(NameBuff), 5922 "%" PRId64, 5923 (int64_t)(*(OptInt *)varp)); 5924 } 5925 } else { // string 5926 varp = *(char **)(varp); 5927 5928 if (opt->flags & kOptFlagExpand) { 5929 home_replace(NULL, varp, NameBuff, MAXPATHL, false); 5930 } else { 5931 xstrlcpy(NameBuff, varp, MAXPATHL); 5932 } 5933 } 5934 } 5935 5936 /// Return true if "varp" points to 'wildchar' or 'wildcharm' and it can be 5937 /// printed as a keyname. 5938 /// "*wcp" is set to the value of the option if it's 'wildchar' or 'wildcharm'. 5939 static int wc_use_keyname(const void *varp, OptInt *wcp) 5940 { 5941 if (((OptInt *)varp == &p_wc) || ((OptInt *)varp == &p_wcm)) { 5942 *wcp = *(OptInt *)varp; 5943 if (IS_SPECIAL(*wcp) || find_special_key_in_table((int)(*wcp)) >= 0) { 5944 return true; 5945 } 5946 } 5947 return false; 5948 } 5949 5950 /// @returns true if "x" is present in 'shortmess' option, or 5951 /// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS. 5952 bool shortmess(int x) 5953 { 5954 return (p_shm != NULL 5955 && (vim_strchr(p_shm, x) != NULL 5956 || (vim_strchr(p_shm, 'a') != NULL 5957 && vim_strchr(SHM_ALL_ABBREVIATIONS, x) != NULL))); 5958 } 5959 5960 /// vimrc_found() - Called when a vimrc or "VIMINIT" has been found. 5961 /// 5962 /// Set the values for options that didn't get set yet to the defaults. 5963 /// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet. 5964 void vimrc_found(char *fname, char *envname) 5965 { 5966 if (fname != NULL && envname != NULL) { 5967 char *p = vim_getenv(envname); 5968 if (p == NULL) { 5969 // Set $MYVIMRC to the first vimrc file found. 5970 p = FullName_save(fname, false); 5971 if (p != NULL) { 5972 os_setenv(envname, p, 1); 5973 xfree(p); 5974 } 5975 } else { 5976 xfree(p); 5977 } 5978 } 5979 } 5980 5981 /// Check whether global option has been set. 5982 /// 5983 /// @param[in] name Option name. 5984 /// 5985 /// @return True if option was set. 5986 bool option_was_set(OptIndex opt_idx) 5987 { 5988 assert(opt_idx != kOptInvalid); 5989 return options[opt_idx].flags & kOptFlagWasSet; 5990 } 5991 5992 /// Reset the flag indicating option "name" was set. 5993 /// 5994 /// @param[in] name Option name. 5995 void reset_option_was_set(OptIndex opt_idx) 5996 { 5997 assert(opt_idx != kOptInvalid); 5998 options[opt_idx].flags &= ~(unsigned)kOptFlagWasSet; 5999 } 6000 6001 /// fill_culopt_flags() -- called when 'culopt' changes value 6002 int fill_culopt_flags(char *val, win_T *wp) 6003 { 6004 char *p; 6005 uint8_t culopt_flags_new = 0; 6006 6007 if (val == NULL) { 6008 p = wp->w_p_culopt; 6009 } else { 6010 p = val; 6011 } 6012 while (*p != NUL) { 6013 // Note: Keep this in sync with opt_culopt_values. 6014 if (strncmp(p, "line", 4) == 0) { 6015 p += 4; 6016 culopt_flags_new |= kOptCuloptFlagLine; 6017 } else if (strncmp(p, "both", 4) == 0) { 6018 p += 4; 6019 culopt_flags_new |= kOptCuloptFlagLine | kOptCuloptFlagNumber; 6020 } else if (strncmp(p, "number", 6) == 0) { 6021 p += 6; 6022 culopt_flags_new |= kOptCuloptFlagNumber; 6023 } else if (strncmp(p, "screenline", 10) == 0) { 6024 p += 10; 6025 culopt_flags_new |= kOptCuloptFlagScreenline; 6026 } 6027 6028 if (*p != ',' && *p != NUL) { 6029 return FAIL; 6030 } 6031 if (*p == ',') { 6032 p++; 6033 } 6034 } 6035 6036 // Can't have both "line" and "screenline". 6037 if ((culopt_flags_new & kOptCuloptFlagLine) && (culopt_flags_new & kOptCuloptFlagScreenline)) { 6038 return FAIL; 6039 } 6040 wp->w_p_culopt_flags = culopt_flags_new; 6041 6042 return OK; 6043 } 6044 6045 /// Get the value of 'magic' taking "magic_overruled" into account. 6046 bool magic_isset(void) 6047 { 6048 switch (magic_overruled) { 6049 case OPTION_MAGIC_ON: 6050 return true; 6051 case OPTION_MAGIC_OFF: 6052 return false; 6053 case OPTION_MAGIC_NOT_SET: 6054 break; 6055 } 6056 return p_magic; 6057 } 6058 6059 /// Set the callback function value for an option that accepts a function name, 6060 /// lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.) 6061 /// @return OK if the option is successfully set to a function, otherwise FAIL 6062 int option_set_callback_func(char *optval, Callback *optcb) 6063 { 6064 if (optval == NULL || *optval == NUL) { 6065 callback_free(optcb); 6066 return OK; 6067 } 6068 6069 typval_T *tv; 6070 if (*optval == '{' 6071 || (strncmp(optval, "function(", 9) == 0) 6072 || (strncmp(optval, "funcref(", 8) == 0)) { 6073 // Lambda expression or a funcref 6074 tv = eval_expr(optval, NULL); 6075 if (tv == NULL) { 6076 return FAIL; 6077 } 6078 } else { 6079 // treat everything else as a function name string 6080 tv = xcalloc(1, sizeof(*tv)); 6081 tv->v_type = VAR_STRING; 6082 tv->vval.v_string = xstrdup(optval); 6083 } 6084 6085 Callback cb; 6086 if (!callback_from_typval(&cb, tv) || cb.type == kCallbackNone) { 6087 tv_free(tv); 6088 return FAIL; 6089 } 6090 6091 callback_free(optcb); 6092 *optcb = cb; 6093 tv_free(tv); 6094 return OK; 6095 } 6096 6097 static void didset_options_sctx(int opt_flags, int *buf) 6098 { 6099 for (int i = 0;; i++) { 6100 if (buf[i] == kOptInvalid) { 6101 break; 6102 } 6103 6104 set_option_sctx(buf[i], opt_flags, current_sctx); 6105 } 6106 } 6107 6108 /// Check if backspacing over something is allowed. 6109 /// @param what BS_INDENT, BS_EOL, BS_START, or BS_NOSTOP 6110 bool can_bs(int what) 6111 { 6112 if (what == BS_START && bt_prompt(curbuf)) { 6113 return false; 6114 } 6115 6116 // support for number values was removed but we keep '2' since it is used in 6117 // legacy tests 6118 if (*p_bs == '2') { 6119 return what != BS_NOSTOP; 6120 } 6121 6122 return vim_strchr(p_bs, what) != NULL; 6123 } 6124 6125 /// Get the local or global value of 'backupcopy' flags. 6126 /// 6127 /// @param buf The buffer. 6128 unsigned get_bkc_flags(buf_T *buf) 6129 { 6130 return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags; 6131 } 6132 6133 /// Get the local or global value of 'formatlistpat'. 6134 /// 6135 /// @param buf The buffer. 6136 char *get_flp_value(buf_T *buf) 6137 { 6138 if (buf->b_p_flp == NULL || *buf->b_p_flp == NUL) { 6139 return p_flp; 6140 } 6141 return buf->b_p_flp; 6142 } 6143 6144 /// Get the local or global value of 'virtualedit' flags. 6145 unsigned get_ve_flags(win_T *wp) 6146 { 6147 return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) 6148 & ~(unsigned)(kOptVeFlagNone | kOptVeFlagNoneU); 6149 } 6150 6151 /// Get the local or global value of 'showbreak'. 6152 /// 6153 /// @param win If not NULL, the window to get the local option from; global 6154 /// otherwise. 6155 char *get_showbreak_value(win_T *const win) 6156 FUNC_ATTR_WARN_UNUSED_RESULT 6157 { 6158 if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) { 6159 return p_sbr; 6160 } 6161 if (strcmp(win->w_p_sbr, "NONE") == 0) { 6162 return empty_string_option; 6163 } 6164 return win->w_p_sbr; 6165 } 6166 6167 /// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC. 6168 int get_fileformat(const buf_T *buf) 6169 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 6170 { 6171 int c = (unsigned char)(*buf->b_p_ff); 6172 6173 if (buf->b_p_bin || c == 'u') { 6174 return EOL_UNIX; 6175 } 6176 if (c == 'm') { 6177 return EOL_MAC; 6178 } 6179 return EOL_DOS; 6180 } 6181 6182 /// Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val" 6183 /// argument. 6184 /// 6185 /// @param eap can be NULL! 6186 int get_fileformat_force(const buf_T *buf, const exarg_T *eap) 6187 FUNC_ATTR_NONNULL_ARG(1) 6188 { 6189 int c; 6190 6191 if (eap != NULL && eap->force_ff != 0) { 6192 c = eap->force_ff; 6193 } else { 6194 if ((eap != NULL && eap->force_bin != 0) 6195 ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { 6196 return EOL_UNIX; 6197 } 6198 c = (unsigned char)(*buf->b_p_ff); 6199 } 6200 if (c == 'u') { 6201 return EOL_UNIX; 6202 } 6203 if (c == 'm') { 6204 return EOL_MAC; 6205 } 6206 return EOL_DOS; 6207 } 6208 6209 /// Return the default fileformat from 'fileformats'. 6210 int default_fileformat(void) 6211 { 6212 switch (*p_ffs) { 6213 case 'm': 6214 return EOL_MAC; 6215 case 'd': 6216 return EOL_DOS; 6217 } 6218 return EOL_UNIX; 6219 } 6220 6221 /// Set the current end-of-line type to EOL_UNIX, EOL_MAC, or EOL_DOS. 6222 /// 6223 /// Sets 'fileformat'. 6224 /// 6225 /// @param eol_style End-of-line style. 6226 /// @param opt_flags Option flags (can be OPT_LOCAL, OPT_GLOBAL or a combination). 6227 void set_fileformat(int eol_style, int opt_flags) 6228 { 6229 char *p = NULL; 6230 6231 switch (eol_style) { 6232 case EOL_UNIX: 6233 p = "unix"; 6234 break; 6235 case EOL_MAC: 6236 p = "mac"; 6237 break; 6238 case EOL_DOS: 6239 p = "dos"; 6240 break; 6241 } 6242 6243 // p is NULL if "eol_style" is EOL_UNKNOWN. 6244 if (p != NULL) { 6245 set_option_direct(kOptFileformat, CSTR_AS_OPTVAL(p), opt_flags, 0); 6246 } 6247 6248 // This may cause the buffer to become (un)modified. 6249 redraw_buf_status_later(curbuf); 6250 redraw_tabline = true; 6251 need_maketitle = true; // Set window title later. 6252 } 6253 6254 /// Skip to next part of an option argument: skip space and comma 6255 char *skip_to_option_part(const char *p) 6256 { 6257 if (*p == ',') { 6258 p++; 6259 } 6260 while (*p == ' ') { 6261 p++; 6262 } 6263 return (char *)p; 6264 } 6265 6266 /// Isolate one part of a string option separated by `sep_chars`. 6267 /// 6268 /// @param[in,out] option advanced to the next part 6269 /// @param[in,out] buf copy of the isolated part 6270 /// @param[in] maxlen length of `buf` 6271 /// @param[in] sep_chars chars that separate the option parts 6272 /// 6273 /// @return length of `*option` 6274 size_t copy_option_part(char **option, char *buf, size_t maxlen, char *sep_chars) 6275 { 6276 size_t len = 0; 6277 char *p = *option; 6278 6279 // skip '.' at start of option part, for 'suffixes' 6280 if (*p == '.') { 6281 buf[len++] = *p++; 6282 } 6283 while (*p != NUL && vim_strchr(sep_chars, (uint8_t)(*p)) == NULL) { 6284 // Skip backslash before a separator character and space. 6285 if (p[0] == '\\' && vim_strchr(sep_chars, (uint8_t)p[1]) != NULL) { 6286 p++; 6287 } 6288 if (len < maxlen - 1) { 6289 buf[len++] = *p; 6290 } 6291 p++; 6292 } 6293 buf[len] = NUL; 6294 6295 if (*p != NUL && *p != ',') { // skip non-standard separator 6296 p++; 6297 } 6298 p = skip_to_option_part(p); // p points to next file name 6299 6300 *option = p; 6301 return len; 6302 } 6303 6304 /// Return true when 'shell' has "csh" in the tail. 6305 int csh_like_shell(void) 6306 { 6307 return strstr(path_tail(p_sh), "csh") != NULL; 6308 } 6309 6310 /// Return true when 'shell' has "fish" in the tail. 6311 bool fish_like_shell(void) 6312 { 6313 return strstr(path_tail(p_sh), "fish") != NULL; 6314 } 6315 6316 /// Get window or buffer local options 6317 dict_T *get_winbuf_options(const int bufopt) 6318 FUNC_ATTR_WARN_UNUSED_RESULT 6319 { 6320 dict_T *const d = tv_dict_alloc(); 6321 6322 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 6323 vimoption_T *opt = &options[opt_idx]; 6324 6325 if ((bufopt && (option_has_scope(opt_idx, kOptScopeBuf))) 6326 || (!bufopt && (option_has_scope(opt_idx, kOptScopeWin)))) { 6327 void *varp = get_varp(opt); 6328 6329 if (varp != NULL) { 6330 typval_T opt_tv = optval_as_tv(optval_from_varp(opt_idx, varp), true); 6331 tv_dict_add_tv(d, opt->fullname, strlen(opt->fullname), &opt_tv); 6332 } 6333 } 6334 } 6335 6336 return d; 6337 } 6338 6339 /// Return the effective 'scrolloff' value for the current window, using the 6340 /// global value when appropriate. 6341 int get_scrolloff_value(win_T *wp) 6342 { 6343 // Disallow scrolloff in terminal-mode. #11915 6344 // Still allow 'scrolloff' for non-terminal buffers. #34447 6345 if ((State & MODE_TERMINAL) && wp->w_buffer->terminal) { 6346 return 0; 6347 } 6348 return (int)(wp->w_p_so < 0 ? p_so : wp->w_p_so); 6349 } 6350 6351 /// Return the effective 'sidescrolloff' value for the current window, using the 6352 /// global value when appropriate. 6353 int get_sidescrolloff_value(win_T *wp) 6354 { 6355 return (int)(wp->w_p_siso < 0 ? p_siso : wp->w_p_siso); 6356 } 6357 6358 Dict get_vimoption(String name, int opt_flags, buf_T *buf, win_T *win, Arena *arena, Error *err) 6359 { 6360 OptIndex opt_idx = find_option_len(name.data, name.size); 6361 VALIDATE_S(opt_idx != kOptInvalid, "option (not found)", name.data, { 6362 return (Dict)ARRAY_DICT_INIT; 6363 }); 6364 6365 return vimoption2dict(&options[opt_idx], opt_flags, buf, win, arena); 6366 } 6367 6368 Dict get_all_vimoptions(Arena *arena) 6369 { 6370 Dict retval = arena_dict(arena, kOptCount); 6371 for (OptIndex opt_idx = 0; opt_idx < kOptCount; opt_idx++) { 6372 Dict opt_dict = vimoption2dict(&options[opt_idx], OPT_GLOBAL, curbuf, curwin, arena); 6373 PUT_C(retval, options[opt_idx].fullname, DICT_OBJ(opt_dict)); 6374 } 6375 return retval; 6376 } 6377 6378 static Dict vimoption2dict(vimoption_T *opt, int opt_flags, buf_T *buf, win_T *win, Arena *arena) 6379 { 6380 OptIndex opt_idx = get_opt_idx(opt); 6381 Dict dict = arena_dict(arena, 13); 6382 6383 PUT_C(dict, "name", CSTR_AS_OBJ(opt->fullname)); 6384 PUT_C(dict, "shortname", CSTR_AS_OBJ(opt->shortname)); 6385 6386 const char *scope; 6387 if (option_has_scope(opt_idx, kOptScopeBuf)) { 6388 scope = "buf"; 6389 } else if (option_has_scope(opt_idx, kOptScopeWin)) { 6390 scope = "win"; 6391 } else { 6392 scope = "global"; 6393 } 6394 6395 PUT_C(dict, "scope", CSTR_AS_OBJ(scope)); 6396 6397 // welcome to the jungle 6398 PUT_C(dict, "global_local", BOOLEAN_OBJ(option_is_global_local(opt_idx))); 6399 PUT_C(dict, "commalist", BOOLEAN_OBJ(opt->flags & kOptFlagComma)); 6400 PUT_C(dict, "flaglist", BOOLEAN_OBJ(opt->flags & kOptFlagFlagList)); 6401 6402 PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & kOptFlagWasSet)); 6403 6404 sctx_T script_ctx = { .sc_sid = 0 }; 6405 if (opt_flags == OPT_GLOBAL) { 6406 script_ctx = opt->script_ctx; 6407 } else { 6408 // Scope is either OPT_LOCAL or a fallback mode was requested. 6409 if (option_has_scope(opt_idx, kOptScopeBuf)) { 6410 script_ctx = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]]; 6411 } 6412 if (option_has_scope(opt_idx, kOptScopeWin)) { 6413 script_ctx = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]]; 6414 } 6415 if (opt_flags != OPT_LOCAL && script_ctx.sc_sid == 0) { 6416 script_ctx = opt->script_ctx; 6417 } 6418 } 6419 6420 PUT_C(dict, "last_set_sid", INTEGER_OBJ(script_ctx.sc_sid)); 6421 PUT_C(dict, "last_set_linenr", INTEGER_OBJ(script_ctx.sc_lnum)); 6422 PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)script_ctx.sc_chan)); 6423 6424 PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt))))); 6425 PUT_C(dict, "default", optval_as_object(opt->def_val)); 6426 PUT_C(dict, "allows_duplicates", BOOLEAN_OBJ(!(opt->flags & kOptFlagNoDup))); 6427 6428 return dict; 6429 }