runtime.c (96323B)
1 /// @file runtime.c 2 /// 3 /// Management of runtime files (including packages) 4 5 #include <assert.h> 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <inttypes.h> 9 #include <stdbool.h> 10 #include <stddef.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <uv.h> 14 15 #include "klib/kvec.h" 16 #include "nvim/api/private/defs.h" 17 #include "nvim/api/private/helpers.h" 18 #include "nvim/ascii_defs.h" 19 #include "nvim/autocmd.h" 20 #include "nvim/autocmd_defs.h" 21 #include "nvim/buffer_defs.h" 22 #include "nvim/charset.h" 23 #include "nvim/cmdexpand.h" 24 #include "nvim/debugger.h" 25 #include "nvim/errors.h" 26 #include "nvim/eval.h" 27 #include "nvim/eval/typval.h" 28 #include "nvim/eval/userfunc.h" 29 #include "nvim/eval/vars.h" 30 #include "nvim/ex_cmds_defs.h" 31 #include "nvim/ex_docmd.h" 32 #include "nvim/ex_eval.h" 33 #include "nvim/ex_eval_defs.h" 34 #include "nvim/garray.h" 35 #include "nvim/getchar.h" 36 #include "nvim/gettext_defs.h" 37 #include "nvim/globals.h" 38 #include "nvim/hashtab.h" 39 #include "nvim/hashtab_defs.h" 40 #include "nvim/lua/executor.h" 41 #include "nvim/macros_defs.h" 42 #include "nvim/map_defs.h" 43 #include "nvim/mbyte.h" 44 #include "nvim/mbyte_defs.h" 45 #include "nvim/memline.h" 46 #include "nvim/memory.h" 47 #include "nvim/memory_defs.h" 48 #include "nvim/message.h" 49 #include "nvim/option.h" 50 #include "nvim/option_defs.h" 51 #include "nvim/option_vars.h" 52 #include "nvim/os/fs.h" 53 #include "nvim/os/input.h" 54 #include "nvim/os/os.h" 55 #include "nvim/os/os_defs.h" 56 #include "nvim/os/stdpaths_defs.h" 57 #include "nvim/path.h" 58 #include "nvim/pos_defs.h" 59 #include "nvim/profile.h" 60 #include "nvim/regexp.h" 61 #include "nvim/regexp_defs.h" 62 #include "nvim/runtime.h" 63 #include "nvim/strings.h" 64 #include "nvim/types_defs.h" 65 #include "nvim/usercmd.h" 66 #include "nvim/vim_defs.h" 67 #ifdef USE_CRNL 68 # include "nvim/highlight.h" 69 #endif 70 71 /// Structure used to store info for each sourced file. 72 /// It is shared between do_source() and getsourceline(). 73 /// This is required, because it needs to be handed to do_cmdline() and 74 /// sourcing can be done recursively. 75 typedef struct { 76 FILE *fp; ///< opened file for sourcing 77 char *nextline; ///< if not NULL: line that was read ahead 78 linenr_T sourcing_lnum; ///< line number of the source file 79 bool finished; ///< ":finish" used 80 bool source_from_buf_or_str; ///< true if sourcing from a buffer or string 81 int buf_lnum; ///< line number in the buffer or string 82 garray_T buflines; ///< lines in the buffer or string 83 #ifdef USE_CRNL 84 int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS 85 bool error; ///< true if LF found after CR-LF 86 #endif 87 linenr_T breakpoint; ///< next line with breakpoint or zero 88 char *fname; ///< name of sourced file 89 int dbg_tick; ///< debug_tick when breakpoint was set 90 int level; ///< top nesting level of sourced file 91 vimconv_T conv; ///< type of conversion 92 } source_cookie_T; 93 94 typedef struct { 95 char *path; 96 bool after; 97 bool pack_inserted; 98 TriState has_lua; 99 size_t pos_in_rtp; 100 } SearchPathItem; 101 102 typedef kvec_t(SearchPathItem) RuntimeSearchPath; 103 typedef kvec_t(char *) CharVec; 104 105 #include "runtime.c.generated.h" 106 107 garray_T exestack = { 0, 0, sizeof(estack_T), 50, NULL }; 108 garray_T script_items = { 0, 0, sizeof(scriptitem_T *), 20, NULL }; 109 110 /// The names of packages that once were loaded are remembered. 111 static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL }; 112 113 /// last used sequence number for sourcing scripts (current_sctx.sc_seq) 114 static int last_current_SID_seq = 0; 115 116 /// Initialize the execution stack. 117 void estack_init(void) 118 { 119 ga_grow(&exestack, 10); 120 estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; 121 entry->es_type = ETYPE_TOP; 122 entry->es_name = NULL; 123 entry->es_lnum = 0; 124 entry->es_info.ufunc = NULL; 125 exestack.ga_len++; 126 } 127 128 /// Add an item to the execution stack. 129 /// @return the new entry 130 estack_T *estack_push(etype_T type, char *name, linenr_T lnum) 131 { 132 ga_grow(&exestack, 1); 133 estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; 134 entry->es_type = type; 135 entry->es_name = name; 136 entry->es_lnum = lnum; 137 entry->es_info.ufunc = NULL; 138 exestack.ga_len++; 139 return entry; 140 } 141 142 /// Add a user function to the execution stack. 143 void estack_push_ufunc(ufunc_T *ufunc, linenr_T lnum) 144 { 145 estack_T *entry = estack_push(ETYPE_UFUNC, 146 ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name, 147 lnum); 148 if (entry != NULL) { 149 entry->es_info.ufunc = ufunc; 150 } 151 } 152 153 /// Take an item off of the execution stack. 154 void estack_pop(void) 155 { 156 if (exestack.ga_len > 1) { 157 exestack.ga_len--; 158 } 159 } 160 161 /// Get the current value for <sfile> in allocated memory. 162 /// @param which ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or 163 /// ESTACK_SCRIPT for <script>. 164 char *estack_sfile(estack_arg_T which) 165 { 166 const estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; 167 if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC) { 168 return entry->es_name != NULL ? xstrdup(entry->es_name) : NULL; 169 } 170 171 // If evaluated in a function or autocommand, return the path of the script 172 // where it is defined, at script level the current script path is returned 173 // instead. 174 if (which == ESTACK_SCRIPT) { 175 // Walk the stack backwards, starting from the current frame. 176 for (int idx = exestack.ga_len - 1; idx >= 0; idx--, entry--) { 177 if (entry->es_type == ETYPE_UFUNC || entry->es_type == ETYPE_AUCMD) { 178 const sctx_T *const def_ctx = (entry->es_type == ETYPE_UFUNC 179 ? &entry->es_info.ufunc->uf_script_ctx 180 : &entry->es_info.aucmd->script_ctx); 181 return def_ctx->sc_sid > 0 182 ? xstrdup((SCRIPT_ITEM(def_ctx->sc_sid)->sn_name)) 183 : NULL; 184 } else if (entry->es_type == ETYPE_SCRIPT) { 185 return xstrdup(entry->es_name); 186 } 187 } 188 return NULL; 189 } 190 191 // Give information about each stack entry up to the root. 192 // For a function we compose the call stack, as it was done in the past: 193 // "function One[123]..Two[456]..Three" 194 garray_T ga; 195 ga_init(&ga, sizeof(char), 100); 196 etype_T last_type = ETYPE_SCRIPT; 197 for (int idx = 0; idx < exestack.ga_len; idx++) { 198 entry = ((estack_T *)exestack.ga_data) + idx; 199 if (entry->es_name != NULL) { 200 String type_name = STATIC_CSTR_AS_STRING(""); 201 String es_name = cstr_as_string(entry->es_name); 202 if (entry->es_type != last_type) { 203 switch (entry->es_type) { 204 case ETYPE_SCRIPT: 205 type_name = STATIC_CSTR_AS_STRING("script "); break; 206 case ETYPE_UFUNC: 207 type_name = STATIC_CSTR_AS_STRING("function "); break; 208 default: 209 break; 210 } 211 last_type = entry->es_type; 212 } 213 linenr_T lnum = idx == exestack.ga_len - 1 214 ? which == ESTACK_STACK ? SOURCING_LNUM : 0 215 : entry->es_lnum; 216 217 size_t len = es_name.size + type_name.size + 26; 218 ga_grow(&ga, (int)len); 219 ga_concat_len(&ga, type_name.data, type_name.size); 220 ga_concat_len(&ga, es_name.data, es_name.size); 221 // For the bottom entry of <sfile>: do not add the line number, it is used in 222 // <slnum>. Also leave it out when the number is not set. 223 if (lnum != 0) { 224 ga.ga_len += (int)vim_snprintf_safelen((char *)ga.ga_data + ga.ga_len, 225 len - (size_t)ga.ga_len, 226 "[%" PRIdLINENR "]", lnum); 227 } 228 if (idx != exestack.ga_len - 1) { 229 GA_CONCAT_LITERAL(&ga, ".."); 230 } 231 } 232 } 233 234 // Only NUL-terminate when not returning NULL. 235 if (ga.ga_data != NULL) { 236 ga_append(&ga, NUL); 237 } 238 return (char *)ga.ga_data; 239 } 240 241 static void stacktrace_push_item(list_T *const l, ufunc_T *const fp, const char *const event, 242 const linenr_T lnum, char *const filepath) 243 { 244 dict_T *const d = tv_dict_alloc_lock(VAR_FIXED); 245 typval_T tv = { 246 .v_type = VAR_DICT, 247 .v_lock = VAR_LOCKED, 248 .vval.v_dict = d, 249 }; 250 251 if (fp != NULL) { 252 tv_dict_add_func(d, S_LEN("funcref"), fp); 253 } 254 if (event != NULL) { 255 tv_dict_add_str(d, S_LEN("event"), event); 256 } 257 tv_dict_add_nr(d, S_LEN("lnum"), lnum); 258 tv_dict_add_str(d, S_LEN("filepath"), filepath); 259 260 tv_list_append_tv(l, &tv); 261 } 262 263 /// Create the stacktrace from exestack. 264 list_T *stacktrace_create(void) 265 { 266 list_T *const l = tv_list_alloc(exestack.ga_len); 267 268 for (int i = 0; i < exestack.ga_len; i++) { 269 estack_T *const entry = &((estack_T *)exestack.ga_data)[i]; 270 linenr_T lnum = entry->es_lnum; 271 272 if (entry->es_type == ETYPE_SCRIPT) { 273 stacktrace_push_item(l, NULL, NULL, lnum, entry->es_name); 274 } else if (entry->es_type == ETYPE_UFUNC) { 275 ufunc_T *const fp = entry->es_info.ufunc; 276 const sctx_T sctx = fp->uf_script_ctx; 277 char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, NULL) : ""; 278 lnum += sctx.sc_lnum; 279 stacktrace_push_item(l, fp, NULL, lnum, filepath); 280 } else if (entry->es_type == ETYPE_AUCMD) { 281 const sctx_T sctx = entry->es_info.aucmd->script_ctx; 282 char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, NULL) : ""; 283 lnum += sctx.sc_lnum; 284 stacktrace_push_item(l, NULL, entry->es_name, lnum, filepath); 285 } 286 } 287 return l; 288 } 289 290 /// getstacktrace() function 291 void f_getstacktrace(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 292 { 293 tv_list_set_ret(rettv, stacktrace_create()); 294 } 295 296 static bool runtime_search_path_valid = false; 297 static bool runtime_search_path_valid_thread = false; 298 static int *runtime_search_path_ref = NULL; 299 static RuntimeSearchPath runtime_search_path; 300 static RuntimeSearchPath runtime_search_path_thread; 301 static uv_mutex_t runtime_search_path_mutex; 302 303 void runtime_init(void) 304 { 305 uv_mutex_init(&runtime_search_path_mutex); 306 } 307 308 /// Get DIP_ flags from the [where] argument of a :runtime command. 309 /// "*argp" is advanced to after the [where] argument. 310 static int get_runtime_cmd_flags(char **argp, size_t where_len) 311 { 312 char *arg = *argp; 313 314 if (where_len == 0) { 315 return 0; 316 } 317 318 if (strncmp(arg, "START", where_len) == 0) { 319 *argp = skipwhite(arg + where_len); 320 return DIP_START + DIP_NORTP; 321 } 322 if (strncmp(arg, "OPT", where_len) == 0) { 323 *argp = skipwhite(arg + where_len); 324 return DIP_OPT + DIP_NORTP; 325 } 326 if (strncmp(arg, "PACK", where_len) == 0) { 327 *argp = skipwhite(arg + where_len); 328 return DIP_START + DIP_OPT + DIP_NORTP; 329 } 330 if (strncmp(arg, "ALL", where_len) == 0) { 331 *argp = skipwhite(arg + where_len); 332 return DIP_START + DIP_OPT; 333 } 334 335 return 0; 336 } 337 338 /// ":runtime [where] {name}" 339 void ex_runtime(exarg_T *eap) 340 { 341 char *arg = eap->arg; 342 int flags = eap->forceit ? DIP_ALL : 0; 343 char *p = skiptowhite(arg); 344 flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg)); 345 assert(arg != NULL); // suppress clang false positive 346 source_runtime(arg, flags); 347 } 348 349 static int runtime_expand_flags; 350 351 /// Set the completion context for the :runtime command. 352 void set_context_in_runtime_cmd(expand_T *xp, const char *arg) 353 { 354 char *p = skiptowhite(arg); 355 runtime_expand_flags 356 = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0; 357 // Skip to the last argument. 358 while (*(p = skiptowhite_esc(arg)) != NUL) { 359 if (runtime_expand_flags == 0) { 360 // When there are multiple arguments and [where] is not specified, 361 // use an unrelated non-zero flag to avoid expanding [where]. 362 runtime_expand_flags = DIP_ALL; 363 } 364 arg = skipwhite(p); 365 } 366 xp->xp_context = EXPAND_RUNTIME; 367 xp->xp_pattern = (char *)arg; 368 } 369 370 /// Source all .vim and .lua files in "fnames" with .vim files being sourced first. 371 static bool source_callback_vim_lua(int num_fnames, char **fnames, bool all, void *cookie) 372 { 373 bool did_one = false; 374 375 for (int i = 0; i < num_fnames; i++) { 376 if (path_with_extension(fnames[i], "vim")) { 377 do_source(fnames[i], false, DOSO_NONE, cookie); 378 did_one = true; 379 if (!all) { 380 return true; 381 } 382 } 383 } 384 385 for (int i = 0; i < num_fnames; i++) { 386 if (path_with_extension(fnames[i], "lua")) { 387 do_source(fnames[i], false, DOSO_NONE, cookie); 388 did_one = true; 389 if (!all) { 390 return true; 391 } 392 } 393 } 394 395 return did_one; 396 } 397 398 /// Source all files in "fnames" with .vim files sourced first, .lua files 399 /// sourced second, and any remaining files sourced last. 400 static bool source_callback(int num_fnames, char **fnames, bool all, void *cookie) 401 { 402 bool did_one = source_callback_vim_lua(num_fnames, fnames, all, cookie); 403 404 if (!all && did_one) { 405 return true; 406 } 407 408 for (int i = 0; i < num_fnames; i++) { 409 if (!path_with_extension(fnames[i], "vim") 410 && !path_with_extension(fnames[i], "lua")) { 411 do_source(fnames[i], false, DOSO_NONE, cookie); 412 did_one = true; 413 if (!all) { 414 return true; 415 } 416 } 417 } 418 419 return did_one; 420 } 421 422 /// Find the patterns in "name" in all directories in "path" and invoke 423 /// "callback(fname, cookie)". 424 /// "prefix" is prepended to each pattern in "name". 425 /// When "flags" has DIP_ALL: source all files, otherwise only the first one. 426 /// When "flags" has DIP_DIR: find directories instead of files. 427 /// When "flags" has DIP_ERR: give an error message if there is no match. 428 /// 429 /// Return FAIL when no file could be sourced, OK otherwise. 430 int do_in_path(const char *path, const char *prefix, char *name, int flags, 431 DoInRuntimepathCB callback, void *cookie) 432 FUNC_ATTR_NONNULL_ARG(1, 2) 433 { 434 bool did_one = false; 435 436 // Make a copy of 'runtimepath'. Invoking the callback may change the 437 // value. 438 char *rtp_copy = xstrdup(path); 439 char *buf = xmallocz(MAXPATHL); 440 { 441 char *tail; 442 if (p_verbose > 10 && name != NULL) { 443 verbose_enter(); 444 if (*prefix != NUL) { 445 smsg(0, _("Searching for \"%s\" under \"%s\" in \"%s\""), name, prefix, path); 446 } else { 447 smsg(0, _("Searching for \"%s\" in \"%s\""), name, path); 448 } 449 verbose_leave(); 450 } 451 452 bool do_all = (flags & DIP_ALL) != 0; 453 454 // Loop over all entries in 'runtimepath'. 455 char *rtp = rtp_copy; 456 while (*rtp != NUL && (do_all || !did_one)) { 457 // Copy the path from 'runtimepath' to buf[]. 458 copy_option_part(&rtp, buf, MAXPATHL, ","); 459 size_t buflen = strlen(buf); 460 461 // Skip after or non-after directories. 462 if (flags & (DIP_NOAFTER | DIP_AFTER)) { 463 bool is_after = path_is_after(buf, buflen); 464 465 if ((is_after && (flags & DIP_NOAFTER)) 466 || (!is_after && (flags & DIP_AFTER))) { 467 continue; 468 } 469 } 470 471 if (name == NULL) { 472 (*callback)(1, &buf, do_all, cookie); 473 did_one = true; 474 } else if (buflen + 2 + strlen(prefix) + strlen(name) < MAXPATHL) { 475 add_pathsep(buf); 476 strcat(buf, prefix); 477 tail = buf + strlen(buf); 478 479 // Loop over all patterns in "name" 480 char *np = name; 481 while (*np != NUL && (do_all || !did_one)) { 482 // Append the pattern from "name" to buf[]. 483 assert(MAXPATHL >= (tail - buf)); 484 copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); 485 486 if (p_verbose > 10) { 487 verbose_enter(); 488 smsg(0, _("Searching for \"%s\""), buf); 489 verbose_leave(); 490 } 491 492 int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE) 493 | ((flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0); 494 495 did_one |= gen_expand_wildcards_and_cb(1, &buf, ew_flags, do_all, callback, 496 cookie) == OK; 497 } 498 } 499 } 500 } 501 xfree(buf); 502 xfree(rtp_copy); 503 if (!did_one && name != NULL) { 504 char *basepath = path == p_rtp ? "runtimepath" : "packpath"; 505 506 if (flags & DIP_ERR) { 507 semsg(_(e_dirnotf), basepath, name); 508 } else if (p_verbose > 1) { 509 verbose_enter(); 510 smsg(0, _("not found in '%s': \"%s\""), basepath, name); 511 verbose_leave(); 512 } 513 } 514 515 return did_one ? OK : FAIL; 516 } 517 518 static RuntimeSearchPath runtime_search_path_get_cached(int *ref) 519 FUNC_ATTR_NONNULL_ALL 520 { 521 runtime_search_path_validate(); 522 523 *ref = 0; 524 if (runtime_search_path_ref == NULL) { 525 // cached path was unreferenced. keep a ref to 526 // prevent runtime_search_path() to freeing it too early 527 (*ref)++; 528 runtime_search_path_ref = ref; 529 } 530 return runtime_search_path; 531 } 532 533 static RuntimeSearchPath copy_runtime_search_path(const RuntimeSearchPath src) 534 { 535 RuntimeSearchPath dst = KV_INITIAL_VALUE; 536 for (size_t j = 0; j < kv_size(src); j++) { 537 SearchPathItem item = kv_A(src, j); 538 kv_push(dst, ((SearchPathItem){ xstrdup(item.path), item.after, item.pack_inserted, 539 item.has_lua, item.pos_in_rtp })); 540 } 541 542 return dst; 543 } 544 545 static void runtime_search_path_unref(RuntimeSearchPath path, const int *ref) 546 FUNC_ATTR_NONNULL_ALL 547 { 548 if (*ref) { 549 if (runtime_search_path_ref == ref) { 550 runtime_search_path_ref = NULL; 551 } else { 552 runtime_search_path_free(path); 553 } 554 } 555 } 556 557 /// Find the file "name" in all directories in "path" and invoke 558 /// "callback(fname, cookie)". 559 /// "name" can contain wildcards. 560 /// When "flags" has DIP_ALL: source all files, otherwise only the first one. 561 /// When "flags" has DIP_DIR: find directories instead of files. 562 /// When "flags" has DIP_ERR: give an error message if there is no match. 563 /// 564 /// return FAIL when no file could be sourced, OK otherwise. 565 static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback, void *cookie) 566 { 567 bool did_one = false; 568 569 char buf[MAXPATHL]; 570 571 if (p_verbose > 10 && name != NULL) { 572 verbose_enter(); 573 smsg(0, _("Searching for \"%s\" in runtime path"), name); 574 verbose_leave(); 575 } 576 577 int ref; 578 RuntimeSearchPath path = runtime_search_path_get_cached(&ref); 579 580 bool do_all = (flags & DIP_ALL) != 0; 581 582 // Loop over all entries in cached path 583 for (size_t j = 0; j < kv_size(path); j++) { 584 SearchPathItem item = kv_A(path, j); 585 size_t buflen = strlen(item.path); 586 587 // Skip after or non-after directories. 588 if (flags & (DIP_NOAFTER | DIP_AFTER)) { 589 if ((item.after && (flags & DIP_NOAFTER)) 590 || (!item.after && (flags & DIP_AFTER))) { 591 continue; 592 } 593 } 594 595 if (name == NULL) { 596 (*callback)(1, &item.path, do_all, cookie); 597 } else if (buflen + strlen(name) + 2 < MAXPATHL) { 598 STRCPY(buf, item.path); 599 add_pathsep(buf); 600 char *tail = buf + strlen(buf); 601 602 // Loop over all patterns in "name" 603 char *np = name; 604 605 while (*np != NUL && (do_all || !did_one)) { 606 // Append the pattern from "name" to buf[]. 607 assert(MAXPATHL >= (tail - buf)); 608 copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)), "\t "); 609 610 if (p_verbose > 10) { 611 verbose_enter(); 612 smsg(0, _("Searching for \"%s\""), buf); 613 verbose_leave(); 614 } 615 616 int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE) 617 | ((flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0) 618 | EW_NOBREAK; 619 620 // Expand wildcards, invoke the callback for each match. 621 char *(pat[]) = { buf }; 622 did_one |= gen_expand_wildcards_and_cb(1, pat, ew_flags, do_all, callback, cookie) == OK; 623 } 624 } 625 } 626 627 if (!did_one && name != NULL) { 628 if (flags & DIP_ERR) { 629 semsg(_(e_dirnotf), "runtime path", name); 630 } else if (p_verbose > 1) { 631 verbose_enter(); 632 smsg(0, _("not found in runtime path: \"%s\""), name); 633 verbose_leave(); 634 } 635 } 636 637 runtime_search_path_unref(path, &ref); 638 639 return did_one ? OK : FAIL; 640 } 641 642 Array runtime_inspect(Arena *arena) 643 { 644 RuntimeSearchPath path = runtime_search_path; 645 Array rv = arena_array(arena, kv_size(path)); 646 647 for (size_t i = 0; i < kv_size(path); i++) { 648 SearchPathItem *item = &kv_A(path, i); 649 Dict entry = arena_dict(arena, 5); 650 PUT_C(entry, "path", CSTR_AS_OBJ(item->path)); 651 if (item->after) { 652 PUT_C(entry, "after", BOOLEAN_OBJ(true)); 653 } 654 if (item->pack_inserted) { 655 PUT_C(entry, "pack_inserted", BOOLEAN_OBJ(true)); 656 } 657 if (item->has_lua != kNone) { 658 PUT_C(entry, "has_lua", BOOLEAN_OBJ(item->has_lua == kTrue)); 659 } 660 PUT_C(entry, "pos_in_rtp", INTEGER_OBJ((Integer)item->pos_in_rtp)); 661 662 ADD_C(rv, DICT_OBJ(entry)); 663 } 664 return rv; 665 } 666 667 ArrayOf(String) runtime_get_named(bool lua, Array pat, bool all, Arena *arena) 668 { 669 int ref; 670 RuntimeSearchPath path = runtime_search_path_get_cached(&ref); 671 static char buf[MAXPATHL]; 672 673 ArrayOf(String) rv = runtime_get_named_common(lua, pat, all, path, buf, sizeof buf, arena); 674 675 runtime_search_path_unref(path, &ref); 676 return rv; 677 } 678 679 ArrayOf(String) runtime_get_named_thread(bool lua, Array pat, bool all) 680 { 681 // TODO(bfredl): avoid contention between multiple worker threads? 682 uv_mutex_lock(&runtime_search_path_mutex); 683 static char buf[MAXPATHL]; 684 ArrayOf(String) rv = runtime_get_named_common(lua, pat, all, runtime_search_path_thread, 685 buf, sizeof buf, NULL); 686 uv_mutex_unlock(&runtime_search_path_mutex); 687 return rv; 688 } 689 690 static ArrayOf(String) runtime_get_named_common(bool lua, Array pat, bool all, 691 RuntimeSearchPath path, char *buf, size_t buf_len, 692 Arena *arena) 693 { 694 ArrayOf(String) rv = arena_array(arena, kv_size(path) * pat.size); 695 for (size_t i = 0; i < kv_size(path); i++) { 696 SearchPathItem *item = &kv_A(path, i); 697 if (lua) { 698 if (item->has_lua == kNone) { 699 size_t size = (size_t)snprintf(buf, buf_len, "%s/lua/", item->path); 700 item->has_lua = (size < buf_len && os_isdir(buf)); 701 } 702 if (item->has_lua == kFalse) { 703 continue; 704 } 705 } 706 707 for (size_t j = 0; j < pat.size; j++) { 708 Object pat_item = pat.items[j]; 709 if (pat_item.type == kObjectTypeString) { 710 size_t size = (size_t)snprintf(buf, buf_len, "%s/%s", 711 item->path, pat_item.data.string.data); 712 if (size < buf_len) { 713 if (os_file_is_readable(buf)) { 714 ADD_C(rv, CSTR_TO_ARENA_OBJ(arena, buf)); 715 if (!all) { 716 goto done; 717 } 718 } 719 } 720 } 721 } 722 } 723 done: 724 return rv; 725 } 726 727 /// Find "name" in "path". When found, invoke the callback function for 728 /// it: callback(fname, "cookie") 729 /// When "flags" has DIP_ALL repeat for all matches, otherwise only the first 730 /// one is used. 731 /// Returns OK when at least one match found, FAIL otherwise. 732 /// If "name" is NULL calls callback for each entry in "path". Cookie is 733 /// passed by reference in this case, setting it to NULL indicates that callback 734 /// has done its job. 735 int do_in_path_and_pp(char *path, char *name, int flags, DoInRuntimepathCB callback, void *cookie) 736 { 737 int done = FAIL; 738 739 if ((flags & DIP_NORTP) == 0) { 740 done |= do_in_path(path, "", (name && !*name) ? NULL : name, flags, callback, 741 cookie); 742 } 743 744 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) { 745 const char *prefix 746 = (flags & DIP_AFTER) ? "pack/*/start/*/after/" : "pack/*/start/*/"; // NOLINT 747 done |= do_in_path(p_pp, prefix, name, flags & ~DIP_AFTER, callback, cookie); 748 749 if (done == FAIL || (flags & DIP_ALL)) { 750 prefix = (flags & DIP_AFTER) ? "start/*/after/" : "start/*/"; // NOLINT 751 done |= do_in_path(p_pp, prefix, name, flags & ~DIP_AFTER, callback, cookie); 752 } 753 } 754 755 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT)) { 756 done |= do_in_path(p_pp, "pack/*/opt/*/", name, flags, callback, cookie); // NOLINT 757 758 if (done == FAIL || (flags & DIP_ALL)) { 759 done |= do_in_path(p_pp, "opt/*/", name, flags, callback, cookie); // NOLINT 760 } 761 } 762 763 return done; 764 } 765 766 static bool push_path(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry, 767 bool after, size_t pos_in_rtp) 768 { 769 String *key_alloc; 770 if (set_put_ref(String, rtp_used, cstr_as_string(entry), &key_alloc)) { 771 *key_alloc = cstr_to_string(entry); 772 kv_push(*search_path, ((SearchPathItem){ key_alloc->data, after, false, kNone, pos_in_rtp })); 773 return true; 774 } 775 return false; 776 } 777 778 static void expand_rtp_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used, char *entry, 779 bool after, size_t pos_in_rtp) 780 { 781 if (set_has(String, rtp_used, cstr_as_string(entry))) { 782 return; 783 } 784 785 if (!*entry) { 786 push_path(search_path, rtp_used, entry, after, pos_in_rtp); 787 } 788 789 int num_files; 790 char **files; 791 char *(pat[]) = { entry }; 792 if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR | EW_NOBREAK) == OK) { 793 for (int i = 0; i < num_files; i++) { 794 // reuses position but it is ok, we need to be monotonic but not strictly 795 push_path(search_path, rtp_used, files[i], after, pos_in_rtp); 796 } 797 FreeWild(num_files, files); 798 } 799 } 800 801 static void expand_pack_entry(RuntimeSearchPath *search_path, Set(String) *rtp_used, 802 CharVec *after_path, char *pack_entry, size_t pack_entry_len, 803 size_t pos_in_rtp) 804 { 805 static char buf[MAXPATHL]; 806 char *(start_pat[]) = { "/pack/*/start/*", "/start/*" }; // NOLINT 807 for (int i = 0; i < 2; i++) { 808 if (pack_entry_len + strlen(start_pat[i]) + 1 > sizeof buf) { 809 continue; 810 } 811 xstrlcpy(buf, pack_entry, sizeof buf); 812 xstrlcpy(buf + pack_entry_len, start_pat[i], sizeof buf - pack_entry_len); 813 expand_rtp_entry(search_path, rtp_used, buf, false, pos_in_rtp); 814 size_t after_size = strlen(buf) + 7; 815 char *after = xmallocz(after_size); 816 xstrlcpy(after, buf, after_size); 817 xstrlcat(after, "/after", after_size); 818 kv_push(*after_path, after); 819 } 820 } 821 822 static bool path_is_after(char *buf, size_t buflen) 823 { 824 // NOTE: we only consider dirs exactly matching "after" to be an AFTER dir. 825 // vim8 considers all dirs like "foo/bar_after", "Xafter" etc, as an 826 // "after" dir in SOME codepaths not not in ALL codepaths. 827 return buflen >= 5 828 && (!(buflen >= 6) || vim_ispathsep(buf[buflen - 6])) 829 && strcmp(buf + buflen - 5, "after") == 0; 830 } 831 832 static RuntimeSearchPath runtime_search_path_build(void) 833 { 834 kvec_t(String) pack_entries = KV_INITIAL_VALUE; 835 Map(String, int) pack_used = MAP_INIT; 836 Set(String) rtp_used = SET_INIT; 837 RuntimeSearchPath search_path = KV_INITIAL_VALUE; 838 CharVec after_path = KV_INITIAL_VALUE; 839 840 static char buf[MAXPATHL]; 841 for (char *entry = p_pp; *entry != NUL;) { 842 char *cur_entry = entry; 843 copy_option_part(&entry, buf, MAXPATHL, ","); 844 845 String the_entry = { .data = cur_entry, .size = strlen(buf) }; 846 847 kv_push(pack_entries, the_entry); 848 map_put(String, int)(&pack_used, the_entry, 0); 849 } 850 851 char *rtp_entry; 852 for (rtp_entry = p_rtp; *rtp_entry != NUL;) { 853 char *cur_entry = rtp_entry; 854 copy_option_part(&rtp_entry, buf, MAXPATHL, ","); 855 size_t buflen = strlen(buf); 856 857 if (path_is_after(buf, buflen)) { 858 rtp_entry = cur_entry; 859 break; 860 } 861 862 size_t pos_in_rtp = (size_t)(cur_entry - p_rtp); 863 864 // fact: &rtp entries can contain wild chars 865 expand_rtp_entry(&search_path, &rtp_used, buf, false, pos_in_rtp); 866 867 handle_T *h = map_ref(String, int)(&pack_used, cstr_as_string(buf), NULL); 868 if (h) { 869 (*h)++; 870 expand_pack_entry(&search_path, &rtp_used, &after_path, buf, buflen, pos_in_rtp); 871 } 872 } 873 874 // The following entries were not explicit in rtp. 875 // this is fine, but keep pos_in_rtp monotonic: 876 // use the comma between two entries as a sentinel 877 size_t sentinel_pos_in_rtp = (size_t)(rtp_entry - p_rtp); 878 sentinel_pos_in_rtp -= (sentinel_pos_in_rtp > 0) ? 1 : 0; 879 880 for (size_t i = 0; i < kv_size(pack_entries); i++) { 881 String item = kv_A(pack_entries, i); 882 handle_T h = map_get(String, int)(&pack_used, item); 883 if (h == 0) { 884 expand_pack_entry(&search_path, &rtp_used, &after_path, item.data, item.size, 885 sentinel_pos_in_rtp); 886 } 887 } 888 889 // "after" packages 890 for (size_t i = 0; i < kv_size(after_path); i++) { 891 expand_rtp_entry(&search_path, &rtp_used, kv_A(after_path, i), true, sentinel_pos_in_rtp); 892 xfree(kv_A(after_path, i)); 893 } 894 895 // "after" dirs in rtp 896 for (; *rtp_entry != NUL;) { 897 char *cur_entry = rtp_entry; 898 copy_option_part(&rtp_entry, buf, MAXPATHL, ","); 899 size_t pos_in_rtp = (size_t)(cur_entry - p_rtp); 900 expand_rtp_entry(&search_path, &rtp_used, buf, path_is_after(buf, strlen(buf)), pos_in_rtp); 901 } 902 903 // strings are not owned 904 kv_destroy(pack_entries); 905 kv_destroy(after_path); 906 map_destroy(String, &pack_used); 907 set_destroy(String, &rtp_used); 908 909 return search_path; 910 } 911 912 const char *did_set_runtimepackpath(optset_T *args) 913 { 914 runtime_search_path_valid = false; 915 return NULL; 916 } 917 918 static void runtime_search_path_free(RuntimeSearchPath path) 919 { 920 for (size_t j = 0; j < kv_size(path); j++) { 921 SearchPathItem item = kv_A(path, j); 922 xfree(item.path); 923 } 924 kv_destroy(path); 925 } 926 927 void runtime_search_path_validate(void) 928 { 929 if (!nlua_is_deferred_safe()) { 930 // Cannot rebuild search path in an async context. As a plugin will invoke 931 // itself asynchronously from sync code in the same plugin, the sought 932 // after lua/autoload module will most likely already be in the cached path. 933 // Thus prefer using the stale cache over erroring out in this situation. 934 return; 935 } 936 if (!runtime_search_path_valid) { 937 if (!runtime_search_path_ref) { 938 runtime_search_path_free(runtime_search_path); 939 } 940 runtime_search_path = runtime_search_path_build(); 941 runtime_search_path_valid = true; 942 runtime_search_path_ref = NULL; // initially unowned 943 update_runtime_search_path_thread(true); 944 } 945 } 946 947 void update_runtime_search_path_thread(bool force) 948 { 949 if (!force && !(runtime_search_path_valid && !runtime_search_path_valid_thread)) { 950 return; 951 } 952 953 uv_mutex_lock(&runtime_search_path_mutex); 954 runtime_search_path_free(runtime_search_path_thread); 955 runtime_search_path_thread = copy_runtime_search_path(runtime_search_path); 956 uv_mutex_unlock(&runtime_search_path_mutex); 957 runtime_search_path_valid_thread = true; 958 } 959 960 /// Just like do_in_path_and_pp(), using 'runtimepath' for "path". 961 int do_in_runtimepath(char *name, int flags, DoInRuntimepathCB callback, void *cookie) 962 { 963 int success = FAIL; 964 if (!(flags & DIP_NORTP)) { 965 success |= do_in_cached_path((name && !*name) ? NULL : name, flags, callback, cookie); 966 flags = (flags & ~DIP_START) | DIP_NORTP; 967 } 968 // TODO(bfredl): we could integrate disabled OPT dirs into the cached path 969 // which would effectivize ":packadd myoptpack" as well 970 if ((flags & (DIP_START|DIP_OPT)) && (success == FAIL || (flags & DIP_ALL))) { 971 success |= do_in_path_and_pp(p_rtp, name, flags, callback, cookie); 972 } 973 return success; 974 } 975 976 /// Source the file "name" from all directories in 'runtimepath'. 977 /// "name" can contain wildcards. 978 /// When "flags" has DIP_ALL: source all files, otherwise only the first one. 979 /// 980 /// return FAIL when no file could be sourced, OK otherwise. 981 int source_runtime(char *name, int flags) 982 { 983 return do_in_runtimepath(name, flags, source_callback, NULL); 984 } 985 986 /// Just like source_runtime(), but only source vim and lua files 987 int source_runtime_vim_lua(char *name, int flags) 988 { 989 return do_in_runtimepath(name, flags, source_callback_vim_lua, NULL); 990 } 991 992 /// Just like source_runtime(), but: 993 /// - use "path" instead of 'runtimepath'. 994 /// - only source .vim and .lua files 995 int source_in_path_vim_lua(char *path, char *name, int flags) 996 { 997 return do_in_path_and_pp(path, name, flags, source_callback_vim_lua, NULL); 998 } 999 1000 /// Expand wildcards in "pats" and invoke callback matches. 1001 /// 1002 /// @param num_pat is number of input patterns. 1003 /// @param patx is an array of pointers to input patterns. 1004 /// @param flags is a combination of EW_* flags used in 1005 /// expand_wildcards(). 1006 /// @param all invoke callback on all matches or just one 1007 /// @param callback called for each match. 1008 /// @param cookie context for callback 1009 /// 1010 /// @returns OK when some files were found, FAIL otherwise. 1011 static int gen_expand_wildcards_and_cb(int num_pat, char **pats, int flags, bool all, 1012 DoInRuntimepathCB callback, void *cookie) 1013 { 1014 int num_files; 1015 char **files; 1016 1017 if (gen_expand_wildcards(num_pat, pats, &num_files, &files, flags) != OK) { 1018 return FAIL; 1019 } 1020 1021 (*callback)(num_files, files, all, cookie); 1022 1023 FreeWild(num_files, files); 1024 1025 return OK; 1026 } 1027 1028 /// Add the package directory to 'runtimepath' 1029 /// 1030 /// @param fname the package path 1031 /// @param is_pack whether the added dir is a "pack/*/start/*/" style package 1032 static int add_pack_dir_to_rtp(char *fname, bool is_pack) 1033 { 1034 char *afterdir = NULL; 1035 int retval = FAIL; 1036 1037 char *p1 = get_past_head(fname); 1038 char *p2 = p1; 1039 char *p3 = p1; 1040 char *p4 = p1; 1041 for (char *p = p1; *p; MB_PTR_ADV(p)) { 1042 if (vim_ispathsep_nocolon(*p)) { 1043 p4 = p3; 1044 p3 = p2; 1045 p2 = p1; 1046 p1 = p; 1047 } 1048 } 1049 1050 // now we have: 1051 // rtp/pack/name/(start|opt)/name 1052 // p4 p3 p2 p1 1053 // 1054 // find the part up to "pack" in 'runtimepath' 1055 p4++; // append pathsep in order to expand symlink 1056 char c = *p4; 1057 *p4 = NUL; 1058 char *const ffname = fix_fname(fname); 1059 *p4 = c; 1060 1061 if (ffname == NULL) { 1062 return FAIL; 1063 } 1064 1065 // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences 1066 // Also stop at the first "after" directory 1067 size_t fname_len = strlen(ffname); 1068 char buf[MAXPATHL]; 1069 const char *insp = NULL; 1070 const char *after_insp = NULL; 1071 const char *entry = p_rtp; 1072 while (*entry != NUL) { 1073 const char *cur_entry = entry; 1074 copy_option_part((char **)&entry, buf, MAXPATHL, ","); 1075 1076 char *p = strstr(buf, "after"); 1077 bool is_after = p != NULL 1078 && p > buf 1079 && vim_ispathsep(p[-1]) 1080 && (vim_ispathsep(p[5]) || p[5] == NUL || p[5] == ','); 1081 1082 if (is_after) { 1083 if (insp == NULL) { 1084 // Did not find "ffname" before the first "after" directory, 1085 // insert it before this entry. 1086 insp = cur_entry; 1087 } 1088 after_insp = cur_entry; 1089 break; 1090 } 1091 1092 if (insp == NULL) { 1093 add_pathsep(buf); 1094 char *const rtp_ffname = fix_fname(buf); 1095 if (rtp_ffname == NULL) { 1096 goto theend; 1097 } 1098 if (path_fnamencmp(rtp_ffname, ffname, fname_len) == 0) { 1099 // Insert "ffname" after this entry (and comma). 1100 insp = entry; 1101 } 1102 xfree(rtp_ffname); 1103 } 1104 } 1105 1106 if (insp == NULL) { 1107 // Both "fname" and "after" not found, append at the end. 1108 insp = p_rtp + strlen(p_rtp); 1109 } 1110 1111 // check if rtp/pack/name/start/name/after exists 1112 afterdir = concat_fnames(fname, "after", true); 1113 size_t afterlen = 0; 1114 if (is_pack ? pack_has_entries(afterdir) : os_isdir(afterdir)) { 1115 afterlen = strlen(afterdir) + 1; // add one for comma 1116 } 1117 1118 const size_t oldlen = strlen(p_rtp); 1119 const size_t addlen = strlen(fname) + 1; // add one for comma 1120 const size_t new_rtp_capacity = oldlen + addlen + afterlen + 1; 1121 // add one for NUL ------------------------------------------^ 1122 char *const new_rtp = try_malloc(new_rtp_capacity); 1123 if (new_rtp == NULL) { 1124 goto theend; 1125 } 1126 1127 // We now have 'rtp' parts: {keep}{keep_after}{rest}. 1128 // Create new_rtp, first: {keep},{fname} 1129 size_t keep = (size_t)(insp - p_rtp); 1130 size_t first_pos = keep; 1131 memmove(new_rtp, p_rtp, keep); 1132 size_t new_rtp_len = keep; 1133 if (*insp == NUL) { 1134 new_rtp[new_rtp_len++] = ','; // add comma before 1135 first_pos++; 1136 } 1137 memmove(new_rtp + new_rtp_len, fname, addlen - 1); 1138 new_rtp_len += addlen - 1; 1139 if (*insp != NUL) { 1140 new_rtp[new_rtp_len++] = ','; // add comma after 1141 } 1142 1143 size_t after_pos = 0; 1144 1145 if (afterlen > 0 && after_insp != NULL) { 1146 size_t keep_after = (size_t)(after_insp - p_rtp); 1147 1148 // Add to new_rtp: {keep},{fname}{keep_after},{afterdir} 1149 memmove(new_rtp + new_rtp_len, p_rtp + keep, keep_after - keep); 1150 new_rtp_len += keep_after - keep; 1151 memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1); 1152 new_rtp_len += afterlen - 1; 1153 new_rtp[new_rtp_len++] = ','; 1154 keep = keep_after; 1155 after_pos = keep_after; 1156 } 1157 1158 if (p_rtp[keep] != NUL) { 1159 // Append rest: {keep},{fname}{keep_after},{afterdir}{rest} 1160 memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1); 1161 } else { 1162 new_rtp[new_rtp_len] = NUL; 1163 } 1164 1165 if (afterlen > 0 && after_insp == NULL) { 1166 // Append afterdir when "after" was not found: 1167 // {keep},{fname}{rest},{afterdir} 1168 after_pos = xstrlcat(new_rtp, ",", new_rtp_capacity); 1169 xstrlcat(new_rtp, afterdir, new_rtp_capacity); 1170 } 1171 1172 bool was_valid = runtime_search_path_valid; 1173 set_option_value_give_err(kOptRuntimepath, CSTR_AS_OPTVAL(new_rtp), 0); 1174 1175 assert(!runtime_search_path_valid); 1176 // If this is the result of "packadd opt_pack", rebuilding runtime_search_pat 1177 // from scratch is needlessly slow. splice in the package and its afterdir instead. 1178 // But don't do this for "pack/*/start/*" (is_pack=true): 1179 // we want properly expand wildcards in a "start" bundle. 1180 if (was_valid && !is_pack) { 1181 runtime_search_path_valid = true; 1182 runtime_search_path_valid_thread = false; 1183 kv_pushp(runtime_search_path); 1184 ssize_t i = (ssize_t)(kv_size(runtime_search_path)) - 1; 1185 1186 if (afterlen > 0) { 1187 kv_pushp(runtime_search_path); 1188 i += 1; 1189 for (; i >= 1; i--) { 1190 if (i > 1 && kv_A(runtime_search_path, i - 2).pos_in_rtp >= after_pos) { 1191 kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 2); 1192 kv_A(runtime_search_path, i).pos_in_rtp += addlen + afterlen; 1193 } else { 1194 kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(afterdir), true, true, kNone, 1195 after_pos + addlen }; 1196 i--; 1197 break; 1198 } 1199 } 1200 } 1201 1202 for (; i >= 0; i--) { 1203 if (i > 0 && kv_A(runtime_search_path, i - 1).pos_in_rtp >= first_pos) { 1204 kv_A(runtime_search_path, i) = kv_A(runtime_search_path, i - 1); 1205 kv_A(runtime_search_path, i).pos_in_rtp += addlen; 1206 } else { 1207 kv_A(runtime_search_path, i) = (SearchPathItem){ xstrdup(fname), false, true, kNone, 1208 first_pos }; 1209 break; 1210 } 1211 } 1212 } 1213 xfree(new_rtp); 1214 retval = OK; 1215 1216 theend: 1217 xfree(ffname); 1218 xfree(afterdir); 1219 return retval; 1220 } 1221 1222 /// Load scripts in "plugin" directory of the package. 1223 /// For opt packages, also load scripts in "ftdetect" (start packages already 1224 /// load these from filetype.lua) 1225 static int load_pack_plugin(bool opt, char *fname) 1226 { 1227 static const char plugpat[] = "%s/plugin/**/*"; // NOLINT 1228 static const char ftpat[] = "%s/ftdetect/*"; // NOLINT 1229 1230 char *const ffname = fix_fname(fname); 1231 size_t len = strlen(ffname) + sizeof(plugpat); 1232 char *pat = xmallocz(len); 1233 1234 vim_snprintf(pat, len, plugpat, ffname); 1235 gen_expand_wildcards_and_cb(1, &pat, EW_FILE, true, source_callback_vim_lua, NULL); 1236 1237 char *cmd = xstrdup("g:did_load_filetypes"); 1238 1239 // If runtime/filetype.lua wasn't loaded yet, the scripts will be 1240 // found when it loads. 1241 if (opt && eval_to_number(cmd, false) > 0) { 1242 do_cmdline_cmd("augroup filetypedetect"); 1243 vim_snprintf(pat, len, ftpat, ffname); 1244 gen_expand_wildcards_and_cb(1, &pat, EW_FILE, true, source_callback_vim_lua, NULL); 1245 do_cmdline_cmd("augroup END"); 1246 } 1247 xfree(cmd); 1248 xfree(pat); 1249 xfree(ffname); 1250 1251 return OK; 1252 } 1253 1254 // used for "cookie" of add_pack_plugin() 1255 static int APP_ADD_DIR; 1256 static int APP_LOAD; 1257 static int APP_BOTH; 1258 1259 static void add_pack_plugins(bool opt, int num_fnames, char **fnames, bool all, void *cookie) 1260 { 1261 bool did_one = false; 1262 1263 if (cookie != &APP_LOAD) { 1264 char buf[MAXPATHL]; 1265 for (int i = 0; i < num_fnames; i++) { 1266 bool found = false; 1267 1268 const char *p = p_rtp; 1269 while (*p != NUL) { 1270 copy_option_part((char **)&p, buf, MAXPATHL, ","); 1271 if (path_fnamecmp(buf, fnames[i]) == 0) { 1272 found = true; 1273 break; 1274 } 1275 } 1276 if (!found) { 1277 // directory is not yet in 'runtimepath', add it 1278 if (add_pack_dir_to_rtp(fnames[i], false) == FAIL) { 1279 return; 1280 } 1281 } 1282 did_one = true; 1283 if (!all) { 1284 break; 1285 } 1286 } 1287 } 1288 1289 if (!all && did_one) { 1290 return; 1291 } 1292 1293 if (cookie != &APP_ADD_DIR) { 1294 for (int i = 0; i < num_fnames; i++) { 1295 load_pack_plugin(opt, fnames[i]); 1296 if (!all) { 1297 break; 1298 } 1299 } 1300 } 1301 } 1302 1303 static bool add_start_pack_plugins(int num_fnames, char **fnames, bool all, void *cookie) 1304 { 1305 add_pack_plugins(false, num_fnames, fnames, all, cookie); 1306 return num_fnames > 0; 1307 } 1308 1309 static bool add_opt_pack_plugins(int num_fnames, char **fnames, bool all, void *cookie) 1310 { 1311 add_pack_plugins(true, num_fnames, fnames, all, cookie); 1312 return num_fnames > 0; 1313 } 1314 1315 /// Add all packages in the "start" directory to 'runtimepath'. 1316 void add_pack_start_dirs(void) 1317 { 1318 do_in_path(p_pp, "", NULL, DIP_ALL + DIP_DIR, add_pack_start_dir, NULL); 1319 } 1320 1321 static bool pack_has_entries(char *buf) 1322 { 1323 int num_files; 1324 char **files; 1325 char *(pat[]) = { buf }; 1326 if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) { 1327 FreeWild(num_files, files); 1328 } 1329 return num_files > 0; 1330 } 1331 1332 static bool add_pack_start_dir(int num_fnames, char **fnames, bool all, void *cookie) 1333 { 1334 static char buf[MAXPATHL]; 1335 for (int i = 0; i < num_fnames; i++) { 1336 char *(start_pat[]) = { "/start/*", "/pack/*/start/*" }; // NOLINT 1337 for (int j = 0; j < 2; j++) { 1338 if (strlen(fnames[i]) + strlen(start_pat[j]) + 1 > MAXPATHL) { 1339 continue; 1340 } 1341 xstrlcpy(buf, fnames[i], MAXPATHL); 1342 xstrlcat(buf, start_pat[j], sizeof buf); 1343 if (pack_has_entries(buf)) { 1344 add_pack_dir_to_rtp(buf, true); 1345 } 1346 } 1347 1348 if (!all) { 1349 break; 1350 } 1351 } 1352 1353 return num_fnames > 1; 1354 } 1355 1356 /// Load plugins from all packages in the "start" directory. 1357 void load_start_packages(void) 1358 { 1359 did_source_packages = true; 1360 do_in_path(p_pp, "", "pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT 1361 add_start_pack_plugins, &APP_LOAD); 1362 do_in_path(p_pp, "", "start/*", DIP_ALL + DIP_DIR, // NOLINT 1363 add_start_pack_plugins, &APP_LOAD); 1364 1365 update_runtime_search_path_thread(false); 1366 } 1367 1368 // ":packloadall" 1369 // Find plugins in the package directories and source them. 1370 void ex_packloadall(exarg_T *eap) 1371 { 1372 if (!did_source_packages || eap->forceit) { 1373 // First do a round to add all directories to 'runtimepath', then load 1374 // the plugins. This allows for plugins to use an autoload directory 1375 // of another plugin. 1376 add_pack_start_dirs(); 1377 load_start_packages(); 1378 } 1379 } 1380 1381 /// Read all the plugin files at startup 1382 void load_plugins(void) 1383 { 1384 if (p_lpl) { 1385 char *rtp_copy = p_rtp; 1386 char *const plugin_pattern = "plugin/**/*"; // NOLINT 1387 1388 if (!did_source_packages) { 1389 rtp_copy = xstrdup(p_rtp); 1390 add_pack_start_dirs(); 1391 } 1392 1393 // Don't use source_runtime_vim_lua() yet so we can check for :packloadall below. 1394 // NB: after calling this "rtp_copy" may have been freed if it wasn't copied. 1395 source_in_path_vim_lua(rtp_copy, plugin_pattern, DIP_ALL | DIP_NOAFTER); 1396 TIME_MSG("loading rtp plugins"); 1397 1398 // Only source "start" packages if not done already with a :packloadall 1399 // command. 1400 if (!did_source_packages) { 1401 xfree(rtp_copy); 1402 load_start_packages(); 1403 } 1404 TIME_MSG("loading packages"); 1405 1406 source_runtime_vim_lua(plugin_pattern, DIP_ALL | DIP_AFTER); 1407 TIME_MSG("loading after plugins"); 1408 } 1409 } 1410 1411 /// ":packadd[!] {name}" 1412 void ex_packadd(exarg_T *eap) 1413 { 1414 static const char plugpat[] = "pack/*/%s/%s"; // NOLINT 1415 int res = OK; 1416 1417 const size_t len = sizeof(plugpat) + strlen(eap->arg) + 5; 1418 char *pat = xmallocz(len); 1419 void *cookie = eap->forceit ? &APP_ADD_DIR : &APP_BOTH; 1420 1421 // Only look under "start" when loading packages wasn't done yet. 1422 if (!did_source_packages) { 1423 vim_snprintf(pat, len, plugpat, "start", eap->arg); 1424 res = do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR, 1425 add_start_pack_plugins, cookie); 1426 } 1427 1428 // Give a "not found" error if nothing was found in 'start' or 'opt'. 1429 vim_snprintf(pat, len, plugpat, "opt", eap->arg); 1430 do_in_path(p_pp, "", pat, DIP_ALL + DIP_DIR + (res == FAIL ? DIP_ERR : 0), 1431 add_opt_pack_plugins, cookie); 1432 1433 update_runtime_search_path_thread(false); 1434 1435 xfree(pat); 1436 } 1437 1438 static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap, 1439 char *dirnames[]) 1440 { 1441 // TODO(bfredl): this is bullshit, expandpath should not reinvent path logic. 1442 for (int i = 0; dirnames[i] != NULL; i++) { 1443 const size_t buf_len = strlen(dirnames[i]) + pat_len + 64; 1444 char *buf = xmalloc(buf_len); 1445 int glob_flags = 0; 1446 bool expand_dirs = false; 1447 // Build base pattern 1448 snprintf(buf, buf_len, "%s%s%s%s", *dirnames[i] ? dirnames[i] : "", *dirnames[i] ? "/" : "", 1449 pat, "*.{vim,lua}"); 1450 1451 expand: 1452 if ((flags & DIP_NORTP) == 0) { 1453 globpath(p_rtp, buf, gap, glob_flags, expand_dirs); 1454 } 1455 1456 if (flags & DIP_START) { 1457 // pack/*/start/*/ patterns 1458 snprintf(buf, buf_len, "pack/*/start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT 1459 *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); 1460 globpath(p_pp, buf, gap, glob_flags, expand_dirs); 1461 1462 // start/*/ patterns 1463 snprintf(buf, buf_len, "start/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT 1464 *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); 1465 globpath(p_pp, buf, gap, glob_flags, expand_dirs); 1466 } 1467 1468 if (flags & DIP_OPT) { 1469 // pack/*/opt/*/ patterns 1470 snprintf(buf, buf_len, "pack/*/opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT 1471 *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); 1472 globpath(p_pp, buf, gap, glob_flags, expand_dirs); 1473 1474 // opt/*/ patterns 1475 snprintf(buf, buf_len, "opt/*/%s%s%s%s", *dirnames[i] ? dirnames[i] : "", // NOLINT 1476 *dirnames[i] ? "/" : "", pat, expand_dirs ? "*" : "*.{vim,lua}"); 1477 globpath(p_pp, buf, gap, glob_flags, expand_dirs); 1478 } 1479 1480 // Second round for directories 1481 if (*dirnames[i] == NUL && !expand_dirs) { 1482 snprintf(buf, buf_len, "%s*", pat); 1483 glob_flags = WILD_ADD_SLASH; 1484 expand_dirs = true; 1485 goto expand; 1486 } 1487 1488 xfree(buf); 1489 } 1490 1491 int pat_pathsep_cnt = 0; 1492 for (size_t i = 0; i < pat_len; i++) { 1493 if (vim_ispathsep(pat[i])) { 1494 pat_pathsep_cnt++; 1495 } 1496 } 1497 1498 for (int i = 0; i < gap->ga_len; i++) { 1499 char *match = ((char **)gap->ga_data)[i]; 1500 char *s = match; 1501 char *e = s + strlen(s); 1502 if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0 1503 || STRNICMP(e - 4, ".lua", 4) == 0)) { 1504 e -= 4; 1505 *e = NUL; 1506 } 1507 1508 int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0; 1509 for (s = e; s > match; MB_PTR_BACK(match, s)) { 1510 if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) { 1511 break; 1512 } 1513 } 1514 s++; 1515 if (s != match) { 1516 assert((e - s) + 1 >= 0); 1517 memmove(match, s, (size_t)(e - s) + 1); 1518 } 1519 } 1520 1521 if (GA_EMPTY(gap)) { 1522 return; 1523 } 1524 1525 // Sort and remove duplicates which can happen when specifying multiple 1526 // directories in dirnames. 1527 ga_remove_duplicate_strings(gap); 1528 } 1529 1530 /// Expand color scheme, compiler or filetype names. 1531 /// Search from 'runtimepath': 1532 /// 'runtimepath'/{dirnames}/{pat}.{vim,lua} 1533 /// When "flags" has DIP_START: search also from "start" of 'packpath': 1534 /// 'packpath'/pack/*/start/*/{dirnames}/{pat}.{vim,lua} 1535 /// When "flags" has DIP_OPT: search also from "opt" of 'packpath': 1536 /// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.{vim,lua} 1537 /// "dirnames" is an array with one or more directory names. 1538 int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[]) 1539 { 1540 *num_file = 0; 1541 *file = NULL; 1542 1543 garray_T ga; 1544 ga_init(&ga, (int)sizeof(char *), 10); 1545 1546 ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames); 1547 1548 if (GA_EMPTY(&ga)) { 1549 return FAIL; 1550 } 1551 1552 *file = ga.ga_data; 1553 *num_file = ga.ga_len; 1554 return OK; 1555 } 1556 1557 /// Handle command line completion for :runtime command. 1558 int expand_runtime_cmd(char *pat, int *numMatches, char ***matches) 1559 { 1560 *numMatches = 0; 1561 *matches = NULL; 1562 1563 garray_T ga; 1564 ga_init(&ga, sizeof(char *), 10); 1565 1566 const size_t pat_len = strlen(pat); 1567 char *dirnames[] = { "", NULL }; 1568 ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames); 1569 1570 // Try to complete values for [where] argument when none was found. 1571 if (runtime_expand_flags == 0) { 1572 char *where_values[] = { "START", "OPT", "PACK", "ALL" }; 1573 for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) { 1574 if (strncmp(pat, where_values[i], pat_len) == 0) { 1575 GA_APPEND(char *, &ga, xstrdup(where_values[i])); 1576 } 1577 } 1578 } 1579 1580 if (GA_EMPTY(&ga)) { 1581 return FAIL; 1582 } 1583 1584 *matches = ga.ga_data; 1585 *numMatches = ga.ga_len; 1586 return OK; 1587 } 1588 1589 /// Expand loadplugin names: 1590 /// 'packpath'/pack/*/opt/{pat} 1591 int ExpandPackAddDir(char *pat, int *num_file, char ***file) 1592 { 1593 garray_T ga; 1594 1595 *num_file = 0; 1596 *file = NULL; 1597 size_t pat_len = strlen(pat); 1598 ga_init(&ga, (int)sizeof(char *), 10); 1599 1600 size_t buflen = pat_len + 26; 1601 char *s = xmalloc(buflen); 1602 snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT 1603 globpath(p_pp, s, &ga, 0, true); 1604 snprintf(s, buflen, "opt/%s*", pat); // NOLINT 1605 globpath(p_pp, s, &ga, 0, true); 1606 xfree(s); 1607 1608 for (int i = 0; i < ga.ga_len; i++) { 1609 char *match = ((char **)ga.ga_data)[i]; 1610 s = path_tail(match); 1611 memmove(match, s, strlen(s) + 1); 1612 } 1613 1614 if (GA_EMPTY(&ga)) { 1615 return FAIL; 1616 } 1617 1618 // Sort and remove duplicates which can happen when specifying multiple 1619 // directories in dirnames. 1620 ga_remove_duplicate_strings(&ga); 1621 1622 *file = ga.ga_data; 1623 *num_file = ga.ga_len; 1624 return OK; 1625 } 1626 1627 /// Append string with escaped commas 1628 static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len) 1629 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT 1630 { 1631 size_t shift = 0; 1632 for (size_t i = 0; i < len; i++) { 1633 if (src[i] == ',') { 1634 dest[i + shift++] = '\\'; 1635 } 1636 dest[i + shift] = src[i]; 1637 } 1638 return &dest[len + shift]; 1639 } 1640 1641 /// Compute length of a ENV_SEPCHAR-separated value, doubled and with some 1642 /// suffixes 1643 /// 1644 /// @param[in] val ENV_SEPCHAR-separated array value. 1645 /// @param[in] common_suf_len Length of the common suffix which is appended to 1646 /// each item in the array, twice. 1647 /// @param[in] single_suf_len Length of the suffix which is appended to each 1648 /// item in the array once. 1649 /// 1650 /// @return Length of the ENV_SEPCHAR-separated string array that contains each 1651 /// item in the original array twice with suffixes with given length 1652 /// (common_suf is present after each new item, single_suf is present 1653 /// after half of the new items) and with commas after each item, commas 1654 /// inside the values are escaped. 1655 static inline size_t compute_double_env_sep_len(const char *const val, const size_t common_suf_len, 1656 const size_t single_suf_len) 1657 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE 1658 { 1659 if (val == NULL || *val == NUL) { 1660 return 0; 1661 } 1662 size_t ret = 0; 1663 const void *iter = NULL; 1664 do { 1665 size_t dir_len; 1666 const char *dir; 1667 iter = vim_env_iter(ENV_SEPCHAR, val, iter, &dir, &dir_len); 1668 if (dir != NULL && dir_len > 0) { 1669 ret += ((dir_len + memcnt(dir, ',', dir_len) + common_suf_len 1670 + !after_pathsep(dir, dir + dir_len)) * 2 1671 + single_suf_len); 1672 } 1673 } while (iter != NULL); 1674 return ret; 1675 } 1676 1677 /// Add directories to a ENV_SEPCHAR-separated array from a colon-separated one 1678 /// 1679 /// Commas are escaped in process. To each item PATHSEP "nvim" is appended in 1680 /// addition to suf1 and suf2. 1681 /// 1682 /// @param[in,out] dest Destination comma-separated array. 1683 /// @param[in] val Source ENV_SEPCHAR-separated array. 1684 /// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it 1685 /// directory separator is appended. Suffix must not contain 1686 /// commas. 1687 /// @param[in] len1 Length of the suf1. 1688 /// @param[in] suf2 If not NULL, another suffix appended to destination. Again 1689 /// with directory separator behind. Suffix must not contain 1690 /// commas. 1691 /// @param[in] len2 Length of the suf2. 1692 /// @param[in] forward If true, iterate over val in forward direction. 1693 /// Otherwise in reverse. 1694 /// 1695 /// @return (dest + appended_characters_length) 1696 static inline char *add_env_sep_dirs(char *dest, const char *const val, const char *const suf1, 1697 const size_t len1, const char *const suf2, const size_t len2, 1698 const bool forward) 1699 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) 1700 { 1701 if (val == NULL || *val == NUL) { 1702 return dest; 1703 } 1704 const void *iter = NULL; 1705 const char *appname = get_appname(false); 1706 const size_t appname_len = strlen(appname); 1707 do { 1708 size_t dir_len; 1709 const char *dir; 1710 iter = (forward ? vim_env_iter : vim_env_iter_rev)(ENV_SEPCHAR, val, iter, 1711 &dir, &dir_len); 1712 if (dir != NULL && dir_len > 0) { 1713 dest = strcpy_comma_escaped(dest, dir, dir_len); 1714 if (!after_pathsep(dest - 1, dest)) { 1715 *dest++ = PATHSEP; 1716 } 1717 memmove(dest, appname, appname_len); 1718 dest += appname_len; 1719 if (suf1 != NULL) { 1720 *dest++ = PATHSEP; 1721 memmove(dest, suf1, len1); 1722 dest += len1; 1723 if (suf2 != NULL) { 1724 *dest++ = PATHSEP; 1725 memmove(dest, suf2, len2); 1726 dest += len2; 1727 } 1728 } 1729 *dest++ = ','; 1730 } 1731 } while (iter != NULL); 1732 return dest; 1733 } 1734 1735 /// Adds directory `dest` to a comma-separated list of directories. 1736 /// 1737 /// Commas in the added directory are escaped. 1738 /// 1739 /// Windows: Appends "nvim-data" instead of "nvim" if `type` is kXDGDataHome. 1740 /// 1741 /// @see get_xdg_home 1742 /// 1743 /// @param[in,out] dest Destination comma-separated array. 1744 /// @param[in] dir Directory to append. 1745 /// @param[in] type Decides whether to append "nvim" (Win: or "nvim-data"). 1746 /// @param[in] suf1 If not NULL, suffix appended to destination. Prior to it 1747 /// directory separator is appended. Suffix must not contain 1748 /// commas. 1749 /// @param[in] len1 Length of the suf1. 1750 /// @param[in] suf2 If not NULL, another suffix appended to destination. Again 1751 /// with directory separator behind. Suffix must not contain 1752 /// commas. 1753 /// @param[in] len2 Length of the suf2. 1754 /// @param[in] forward If true, iterate over val in forward direction. 1755 /// Otherwise in reverse. 1756 /// 1757 /// @return (dest + appended_characters_length) 1758 static inline char *add_dir(char *dest, const char *const dir, const size_t dir_len, 1759 const XDGVarType type, const char *const suf1, const size_t len1, 1760 const char *const suf2, const size_t len2) 1761 FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT 1762 { 1763 if (dir == NULL || dir_len == 0) { 1764 return dest; 1765 } 1766 dest = strcpy_comma_escaped(dest, dir, dir_len); 1767 bool append_nvim = (type == kXDGDataHome || type == kXDGConfigHome); 1768 if (append_nvim) { 1769 if (!after_pathsep(dest - 1, dest)) { 1770 *dest++ = PATHSEP; 1771 } 1772 const char *appname = get_appname(false); 1773 size_t appname_len = strlen(appname); 1774 assert(appname_len < (IOSIZE - sizeof("-data"))); 1775 xmemcpyz(IObuff, appname, appname_len); 1776 #if defined(MSWIN) 1777 if (type == kXDGDataHome || type == kXDGStateHome) { 1778 xstrlcat(IObuff, "-data", IOSIZE); 1779 appname_len += 5; 1780 } 1781 #endif 1782 xmemcpyz(dest, IObuff, appname_len); 1783 dest += appname_len; 1784 if (suf1 != NULL) { 1785 *dest++ = PATHSEP; 1786 memmove(dest, suf1, len1); 1787 dest += len1; 1788 if (suf2 != NULL) { 1789 *dest++ = PATHSEP; 1790 memmove(dest, suf2, len2); 1791 dest += len2; 1792 } 1793 } 1794 } 1795 *dest++ = ','; 1796 return dest; 1797 } 1798 1799 char *get_lib_dir(void) 1800 { 1801 // TODO(bfredl): too fragile? Ideally default_lib_dir would be made empty 1802 // in an appimage build 1803 if (strlen(default_lib_dir) != 0 1804 && os_isdir(default_lib_dir)) { 1805 return xstrdup(default_lib_dir); 1806 } 1807 1808 // Find library path relative to the nvim binary: ../lib/nvim/ 1809 char exe_name[MAXPATHL]; 1810 vim_get_prefix_from_exepath(exe_name); 1811 if (append_path(exe_name, "lib/nvim", MAXPATHL) == OK) { 1812 return xstrdup(exe_name); 1813 } 1814 return NULL; 1815 } 1816 1817 /// Determine the startup value for &runtimepath 1818 /// 1819 /// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing 1820 /// configuration and data files in the same path. #4403 1821 /// 1822 /// @param clean_arg Nvim was started with --clean. 1823 /// @return allocated string with the value 1824 char *runtimepath_default(bool clean_arg) 1825 { 1826 size_t rtp_size = 0; 1827 char *const data_home = clean_arg 1828 ? NULL 1829 : stdpaths_get_xdg_var(kXDGDataHome); 1830 char *const config_home = clean_arg 1831 ? NULL 1832 : stdpaths_get_xdg_var(kXDGConfigHome); 1833 char *const vimruntime = vim_getenv("VIMRUNTIME"); 1834 char *const libdir = get_lib_dir(); 1835 char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs); 1836 char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs); 1837 #define SITE_SIZE (sizeof("site") - 1) 1838 #define AFTER_SIZE (sizeof("after") - 1) 1839 size_t data_len = 0; 1840 size_t config_len = 0; 1841 size_t vimruntime_len = 0; 1842 size_t libdir_len = 0; 1843 size_t appname_len = strlen(get_appname(false)); 1844 if (data_home != NULL) { 1845 data_len = strlen(data_home); 1846 size_t nvim_data_size = appname_len; 1847 #if defined(MSWIN) 1848 nvim_data_size += sizeof("-data") - 1; // -1: NULL byte should be ignored 1849 #endif 1850 if (data_len != 0) { 1851 rtp_size += ((data_len + memcnt(data_home, ',', data_len) 1852 + nvim_data_size + 1 + SITE_SIZE + 1 1853 + !after_pathsep(data_home, data_home + data_len)) * 2 1854 + AFTER_SIZE + 1); 1855 } 1856 } 1857 if (config_home != NULL) { 1858 config_len = strlen(config_home); 1859 if (config_len != 0) { 1860 rtp_size += ((config_len + memcnt(config_home, ',', config_len) 1861 + appname_len + 1 1862 + !after_pathsep(config_home, config_home + config_len)) * 2 1863 + AFTER_SIZE + 1); 1864 } 1865 } 1866 if (vimruntime != NULL) { 1867 vimruntime_len = strlen(vimruntime); 1868 if (vimruntime_len != 0) { 1869 rtp_size += vimruntime_len + memcnt(vimruntime, ',', vimruntime_len) + 1; 1870 } 1871 } 1872 if (libdir != NULL) { 1873 libdir_len = strlen(libdir); 1874 if (libdir_len != 0) { 1875 rtp_size += libdir_len + memcnt(libdir, ',', libdir_len) + 1; 1876 } 1877 } 1878 rtp_size += compute_double_env_sep_len(data_dirs, 1879 appname_len + 1 + SITE_SIZE + 1, 1880 AFTER_SIZE + 1); 1881 rtp_size += compute_double_env_sep_len(config_dirs, appname_len + 1, 1882 AFTER_SIZE + 1); 1883 char *rtp = NULL; 1884 if (rtp_size == 0) { 1885 goto freeall; 1886 } 1887 rtp = xmalloc(rtp_size); 1888 char *rtp_cur = rtp; 1889 rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome, 1890 NULL, 0, NULL, 0); 1891 rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, NULL, 0, NULL, 0, true); 1892 rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome, 1893 "site", SITE_SIZE, NULL, 0); 1894 rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, NULL, 0, 1895 true); 1896 rtp_cur = add_dir(rtp_cur, vimruntime, vimruntime_len, kXDGNone, 1897 NULL, 0, NULL, 0); 1898 rtp_cur = add_dir(rtp_cur, libdir, libdir_len, kXDGNone, NULL, 0, NULL, 0); 1899 rtp_cur = add_env_sep_dirs(rtp_cur, data_dirs, "site", SITE_SIZE, 1900 "after", AFTER_SIZE, false); 1901 rtp_cur = add_dir(rtp_cur, data_home, data_len, kXDGDataHome, 1902 "site", SITE_SIZE, "after", AFTER_SIZE); 1903 rtp_cur = add_env_sep_dirs(rtp_cur, config_dirs, "after", AFTER_SIZE, NULL, 0, 1904 false); 1905 rtp_cur = add_dir(rtp_cur, config_home, config_len, kXDGConfigHome, 1906 "after", AFTER_SIZE, NULL, 0); 1907 // Strip trailing comma. 1908 rtp_cur[-1] = NUL; 1909 assert((size_t)(rtp_cur - rtp) == rtp_size); 1910 #undef SITE_SIZE 1911 #undef AFTER_SIZE 1912 freeall: 1913 xfree(data_dirs); 1914 xfree(config_dirs); 1915 xfree(data_home); 1916 xfree(config_home); 1917 xfree(vimruntime); 1918 xfree(libdir); 1919 1920 return rtp; 1921 } 1922 1923 static void cmd_source(char *fname, exarg_T *eap) 1924 { 1925 if (*fname != NUL && eap != NULL && eap->addr_count > 0) { 1926 // if a filename is specified to :source, then a range is not allowed 1927 emsg(_(e_norange)); 1928 return; 1929 } 1930 1931 if (eap != NULL && *fname == NUL) { 1932 if (eap->forceit) { 1933 // a file name is needed to source normal mode commands 1934 emsg(_(e_argreq)); 1935 } else { 1936 // source ex commands from the current buffer 1937 cmd_source_buffer(eap, false); 1938 } 1939 } else if (eap != NULL && eap->forceit) { 1940 // ":source!": read Normal mode commands 1941 // Need to execute the commands directly. This is required at least 1942 // for: 1943 // - ":g" command busy 1944 // - after ":argdo", ":windo" or ":bufdo" 1945 // - another command follows 1946 // - inside a loop 1947 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL 1948 || eap->cstack->cs_idx >= 0); 1949 1950 // ":source" read ex commands 1951 } else if (do_source(fname, false, DOSO_NONE, NULL) == FAIL) { 1952 semsg(_(e_notopen), fname); 1953 } 1954 } 1955 1956 /// ":source [{fname}]" 1957 void ex_source(exarg_T *eap) 1958 { 1959 cmd_source(eap->arg, eap); 1960 } 1961 1962 /// ":options" 1963 void ex_options(exarg_T *eap) 1964 { 1965 char buf[500]; 1966 bool multi_mods = 0; 1967 1968 buf[0] = NUL; 1969 add_win_cmd_modifiers(buf, &cmdmod, &multi_mods); 1970 1971 os_setenv("OPTWIN_CMD", buf, 1); 1972 cmd_source(SYS_OPTWIN_FILE, NULL); 1973 } 1974 1975 /// ":source" and associated commands. 1976 /// 1977 /// @return address holding the next breakpoint line for a source cookie 1978 linenr_T *source_breakpoint(void *cookie) 1979 { 1980 return &((source_cookie_T *)cookie)->breakpoint; 1981 } 1982 1983 /// @return the address holding the debug tick for a source cookie. 1984 int *source_dbg_tick(void *cookie) 1985 { 1986 return &((source_cookie_T *)cookie)->dbg_tick; 1987 } 1988 1989 /// @return the nesting level for a source cookie. 1990 int source_level(void *cookie) 1991 FUNC_ATTR_PURE 1992 { 1993 return ((source_cookie_T *)cookie)->level; 1994 } 1995 1996 /// Special function to open a file without handle inheritance. 1997 /// If possible the handle is closed on exec(). 1998 static FILE *fopen_noinh_readbin(char *filename) 1999 { 2000 #ifdef MSWIN 2001 int fd_tmp = os_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0); 2002 #else 2003 int fd_tmp = os_open(filename, O_RDONLY, 0); 2004 #endif 2005 2006 if (fd_tmp < 0) { 2007 return NULL; 2008 } 2009 2010 os_set_cloexec(fd_tmp); 2011 2012 return fdopen(fd_tmp, READBIN); 2013 } 2014 2015 /// Concatenate Vimscript line if it starts with a line continuation into a growarray 2016 /// (excluding the continuation chars and leading whitespace) 2017 /// 2018 /// @note Growsize of the growarray may be changed to speed up concatenations! 2019 /// 2020 /// @param ga the growarray to append to 2021 /// @param init_growsize the starting growsize value of the growarray 2022 /// @param p pointer to the beginning of the line to consider 2023 /// @param len the length of this line 2024 /// 2025 /// @return true if this line did begin with a continuation (the next line 2026 /// should also be considered, if it exists); false otherwise 2027 static bool concat_continued_line(garray_T *const ga, const int init_growsize, const char *const p, 2028 size_t len) 2029 FUNC_ATTR_NONNULL_ALL 2030 { 2031 const char *const line = skipwhite_len(p, len); 2032 len -= (size_t)(line - p); 2033 // Skip lines starting with '\" ', concat lines starting with '\' 2034 if (len >= 3 && strncmp(line, "\"\\ ", 3) == 0) { 2035 return true; 2036 } else if (len == 0 || line[0] != '\\') { 2037 return false; 2038 } 2039 if (ga->ga_len > init_growsize) { 2040 ga_set_growsize(ga, MIN(ga->ga_len, 8000)); 2041 } 2042 ga_concat_len(ga, line + 1, len - 1); 2043 return true; 2044 } 2045 2046 /// Create a new script item and allocate script-local vars. @see new_script_vars 2047 /// 2048 /// @param name File name of the script. NULL for anonymous :source. 2049 /// @param[out] sid_out SID of the new item. 2050 /// 2051 /// @return pointer to the created script item. 2052 scriptitem_T *new_script_item(char *const name, scid_T *const sid_out) 2053 FUNC_ATTR_NONNULL_RET 2054 { 2055 static scid_T last_current_SID = 0; 2056 const scid_T sid = ++last_current_SID; 2057 if (sid_out != NULL) { 2058 *sid_out = sid; 2059 } 2060 ga_grow(&script_items, sid - script_items.ga_len); 2061 while (script_items.ga_len < sid) { 2062 scriptitem_T *si = xcalloc(1, sizeof(scriptitem_T)); 2063 script_items.ga_len++; 2064 SCRIPT_ITEM(script_items.ga_len) = si; 2065 si->sn_name = NULL; 2066 2067 // Allocate the local script variables to use for this script. 2068 new_script_vars(script_items.ga_len); 2069 2070 si->sn_prof_on = false; 2071 } 2072 SCRIPT_ITEM(sid)->sn_name = name; 2073 return SCRIPT_ITEM(sid); 2074 } 2075 2076 /// Initialization for sourcing lines from the current buffer. Reads all the 2077 /// lines from the buffer and stores it in the cookie grow array. 2078 /// Returns a pointer to the name ":source buffer=<n>" on success and NULL on failure. 2079 static char *do_source_buffer_init(source_cookie_T *sp, const exarg_T *eap, bool ex_lua) 2080 FUNC_ATTR_NONNULL_ALL 2081 { 2082 if (curbuf == NULL) { 2083 return NULL; 2084 } 2085 2086 char *fname; 2087 if (curbuf->b_ffname != NULL) { 2088 fname = xstrdup(curbuf->b_ffname); 2089 } else { 2090 if (ex_lua) { 2091 // Use ":{range}lua buffer=<num>" as the script name 2092 snprintf(IObuff, IOSIZE, ":{range}lua buffer=%d", curbuf->b_fnum); 2093 } else { 2094 // Use ":source buffer=<num>" as the script name 2095 snprintf(IObuff, IOSIZE, ":source buffer=%d", curbuf->b_fnum); 2096 } 2097 fname = xstrdup(IObuff); 2098 } 2099 2100 ga_init(&sp->buflines, sizeof(char *), 100); 2101 // Copy the lines from the buffer into a grow array 2102 for (linenr_T curr_lnum = eap->line1; curr_lnum <= eap->line2; curr_lnum++) { 2103 GA_APPEND(char *, &sp->buflines, xstrdup(ml_get(curr_lnum))); 2104 } 2105 sp->buf_lnum = 0; 2106 sp->source_from_buf_or_str = true; 2107 // When sourcing a range of lines from a buffer, use buffer line number. 2108 sp->sourcing_lnum = eap->line1 - 1; 2109 2110 return fname; 2111 } 2112 2113 /// Initialization for sourcing lines from a string. Reads all the 2114 /// lines from the string and stores it in the cookie grow array. 2115 static void do_source_str_init(source_cookie_T *sp, const char *str) 2116 FUNC_ATTR_NONNULL_ALL 2117 { 2118 ga_init(&sp->buflines, sizeof(char *), 100); 2119 // Copy the lines from the string into a grow array 2120 while (*str != NUL) { 2121 const char *eol = skip_to_newline(str); 2122 GA_APPEND(char *, &sp->buflines, xmemdupz(str, (size_t)(eol - str))); 2123 str = eol + (*eol != NUL); 2124 } 2125 sp->buf_lnum = 0; 2126 sp->source_from_buf_or_str = true; 2127 } 2128 2129 void cmd_source_buffer(const exarg_T *const eap, bool ex_lua) 2130 FUNC_ATTR_NONNULL_ALL 2131 { 2132 do_source_ext(NULL, false, DOSO_NONE, NULL, eap, ex_lua, NULL); 2133 } 2134 2135 /// Executes lines in `str` as Ex commands. 2136 /// 2137 /// @see do_source_ext() 2138 int do_source_str(const char *str, char *traceback_name) 2139 FUNC_ATTR_NONNULL_ALL 2140 { 2141 char *const sourcing_name = SOURCING_NAME; 2142 const linenr_T sourcing_lnum = SOURCING_LNUM; 2143 char sname_buf[256]; 2144 if (sourcing_name != NULL) { 2145 snprintf(sname_buf, sizeof(sname_buf), "%s called at %s:%" PRIdLINENR, 2146 traceback_name, sourcing_name, sourcing_lnum); 2147 traceback_name = sname_buf; 2148 } 2149 return do_source_ext(traceback_name, false, DOSO_NONE, NULL, NULL, false, str); 2150 } 2151 2152 /// When fname is a .lua file nlua_exec_file() is invoked to source it. 2153 /// Otherwise reads the file `fname` and executes its lines as Ex commands. 2154 /// 2155 /// This function may be called recursively! 2156 /// 2157 /// @see do_source_str 2158 /// 2159 /// @param fname if NULL, source from the current buffer 2160 /// @param check_other check for .vimrc and _vimrc 2161 /// @param is_vimrc DOSO_ value 2162 /// @param ret_sid if not NULL and we loaded the script before, don't load it again 2163 /// @param eap used when sourcing lines from a buffer instead of a file 2164 /// @param str if not NULL, source from the given string 2165 /// 2166 /// @return FAIL if file could not be opened, OK otherwise 2167 /// 2168 /// If a scriptitem_T was found or created "*ret_sid" is set to the SID. 2169 static int do_source_ext(char *const fname, const bool check_other, const int is_vimrc, 2170 int *const ret_sid, const exarg_T *const eap, const bool ex_lua, 2171 const char *const str) 2172 { 2173 source_cookie_T cookie; 2174 uint8_t *firstline = NULL; 2175 int retval = FAIL; 2176 int save_debug_break_level = debug_break_level; 2177 scriptitem_T *si = NULL; 2178 proftime_T wait_start; 2179 bool trigger_source_post = false; 2180 ESTACK_CHECK_DECLARATION; 2181 2182 CLEAR_FIELD(cookie); 2183 char *fname_exp = NULL; 2184 if (fname == NULL) { 2185 assert(str == NULL); 2186 // sourcing lines from a buffer 2187 fname_exp = do_source_buffer_init(&cookie, eap, ex_lua); 2188 if (fname_exp == NULL) { 2189 return FAIL; 2190 } 2191 } else if (str != NULL) { 2192 do_source_str_init(&cookie, str); 2193 fname_exp = xstrdup(fname); 2194 } else { 2195 char *p = expand_env_save(fname); 2196 if (p == NULL) { 2197 return retval; 2198 } 2199 fname_exp = fix_fname(p); 2200 xfree(p); 2201 if (fname_exp == NULL) { 2202 return retval; 2203 } 2204 if (os_isdir(fname_exp)) { 2205 smsg(0, _("Cannot source a directory: \"%s\""), fname); 2206 goto theend; 2207 } 2208 } 2209 2210 // See if we loaded this script before. 2211 int sid = str != NULL ? SID_STR : find_script_by_name(fname_exp); 2212 if (sid > 0 && ret_sid != NULL) { 2213 // Already loaded and no need to load again, return here. 2214 *ret_sid = sid; 2215 retval = OK; 2216 goto theend; 2217 } 2218 2219 if (str == NULL) { 2220 // Apply SourceCmd autocommands, they should get the file and source it. 2221 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL) 2222 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp, 2223 false, curbuf)) { 2224 retval = aborting() ? FAIL : OK; 2225 if (retval == OK) { 2226 // Apply SourcePost autocommands. 2227 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf); 2228 } 2229 goto theend; 2230 } 2231 2232 // Apply SourcePre autocommands, they may get the file. 2233 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, false, curbuf); 2234 } 2235 2236 if (!cookie.source_from_buf_or_str) { 2237 cookie.fp = fopen_noinh_readbin(fname_exp); 2238 } 2239 if (cookie.fp == NULL && check_other) { 2240 // Try again, replacing file name ".nvimrc" by "_nvimrc" or vice versa, 2241 // and ".exrc" by "_exrc" or vice versa. 2242 char *p = path_tail(fname_exp); 2243 if ((*p == '.' || *p == '_') 2244 && (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) { 2245 *p = (*p == '_') ? '.' : '_'; 2246 cookie.fp = fopen_noinh_readbin(fname_exp); 2247 } 2248 } 2249 2250 if (cookie.fp == NULL && !cookie.source_from_buf_or_str) { 2251 if (p_verbose > 1) { 2252 verbose_enter(); 2253 if (SOURCING_NAME == NULL) { 2254 smsg(0, _("could not source \"%s\""), fname); 2255 } else { 2256 smsg(0, _("line %" PRId64 ": could not source \"%s\""), 2257 (int64_t)SOURCING_LNUM, fname); 2258 } 2259 verbose_leave(); 2260 } 2261 goto theend; 2262 } 2263 2264 // The file exists. 2265 // - In verbose mode, give a message. 2266 // - For a vimrc file, may want to call vimrc_found(). 2267 if (p_verbose > 1) { 2268 verbose_enter(); 2269 if (SOURCING_NAME == NULL) { 2270 smsg(0, _("sourcing \"%s\""), fname); 2271 } else { 2272 smsg(0, _("line %" PRId64 ": sourcing \"%s\""), (int64_t)SOURCING_LNUM, fname); 2273 } 2274 verbose_leave(); 2275 } 2276 if (is_vimrc == DOSO_VIMRC) { 2277 vimrc_found(fname_exp, "MYVIMRC"); 2278 } 2279 2280 #ifdef USE_CRNL 2281 // If no automatic file format: Set default to CR-NL. 2282 if (*p_ffs == NUL) { 2283 cookie.fileformat = EOL_DOS; 2284 } else { 2285 cookie.fileformat = EOL_UNKNOWN; 2286 } 2287 #endif 2288 2289 // Check if this script has a breakpoint. 2290 cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, 0); 2291 cookie.fname = fname_exp; 2292 cookie.dbg_tick = debug_tick; 2293 2294 cookie.level = ex_nesting_level; 2295 2296 // start measuring script load time if --startuptime was passed and 2297 // time_fd was successfully opened afterwards. 2298 proftime_T rel_time; 2299 proftime_T start_time; 2300 FILE * const l_time_fd = time_fd; 2301 if (l_time_fd != NULL) { 2302 time_push(&rel_time, &start_time); 2303 } 2304 2305 const int l_do_profiling = do_profiling; 2306 if (l_do_profiling == PROF_YES) { 2307 prof_child_enter(&wait_start); // entering a child now 2308 } 2309 2310 // Don't use local function variables, if called from a function. 2311 // Also starts profiling timer for nested script. 2312 funccal_entry_T funccalp_entry; 2313 save_funccal(&funccalp_entry); 2314 2315 const sctx_T save_current_sctx = current_sctx; 2316 2317 // Always use a new sequence number. 2318 current_sctx.sc_seq = ++last_current_SID_seq; 2319 2320 if (sid > 0) { 2321 // loading the same script again 2322 si = SCRIPT_ITEM(sid); 2323 } else if (str == NULL) { 2324 // It's new, generate a new SID. 2325 si = new_script_item(fname_exp, &sid); 2326 si->sn_lua = path_with_extension(fname_exp, "lua"); 2327 fname_exp = xstrdup(si->sn_name); // used for autocmd 2328 if (ret_sid != NULL) { 2329 *ret_sid = sid; 2330 } 2331 } 2332 // Sourcing a string doesn't allocate a script item immediately. 2333 assert((si != NULL) == (str == NULL)); 2334 2335 // Don't change sc_sid to SID_STR when sourcing a string from a Lua script, 2336 // as keeping the current sc_sid allows more useful :verbose messages. 2337 if (str == NULL || !script_is_lua(current_sctx.sc_sid)) { 2338 current_sctx.sc_sid = sid; 2339 current_sctx.sc_lnum = 0; 2340 } 2341 2342 // Keep the sourcing name/lnum, for recursive calls. 2343 estack_push(ETYPE_SCRIPT, si != NULL ? si->sn_name : fname_exp, 0); 2344 ESTACK_CHECK_SETUP; 2345 2346 if (l_do_profiling == PROF_YES && si != NULL) { 2347 bool forceit = false; 2348 2349 // Check if we do profiling for this script. 2350 if (!si->sn_prof_on && has_profiling(true, si->sn_name, &forceit)) { 2351 profile_init(si); 2352 si->sn_pr_force = forceit; 2353 } 2354 if (si->sn_prof_on) { 2355 si->sn_pr_count++; 2356 si->sn_pr_start = profile_start(); 2357 si->sn_pr_children = profile_zero(); 2358 } 2359 } 2360 2361 cookie.conv.vc_type = CONV_NONE; // no conversion 2362 2363 // Check if treesitter detects this range as Lua (for injections like vimdoc codeblocks) 2364 bool ts_lua = false; 2365 if (fname == NULL && eap != NULL && !ex_lua 2366 && !strequal(curbuf->b_p_ft, "lua") 2367 && !(curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) { 2368 MAXSIZE_TEMP_ARRAY(args, 3); 2369 ADD_C(args, INTEGER_OBJ(curbuf->handle)); 2370 ADD_C(args, INTEGER_OBJ(eap->line1)); 2371 ADD_C(args, INTEGER_OBJ(eap->line2)); 2372 Error err = ERROR_INIT; 2373 Object result = NLUA_EXEC_STATIC("return require('vim._core.util').source_is_lua(...)", 2374 args, kRetNilBool, NULL, &err); 2375 if (!ERROR_SET(&err) && LUARET_TRUTHY(result)) { 2376 ts_lua = true; 2377 } 2378 api_clear_error(&err); 2379 } 2380 2381 if (fname == NULL 2382 && (ex_lua || ts_lua || strequal(curbuf->b_p_ft, "lua") 2383 || (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua")))) { 2384 // Source lines from the current buffer as lua 2385 nlua_exec_ga(&cookie.buflines, fname_exp); 2386 } else if (si != NULL && si->sn_lua) { 2387 // Source the file as lua 2388 nlua_exec_file(fname_exp); 2389 } else { 2390 // Read the first line so we can check for a UTF-8 BOM. 2391 firstline = (uint8_t *)getsourceline(0, (void *)&cookie, 0, true); 2392 if (firstline != NULL && strlen((char *)firstline) >= 3 && firstline[0] == 0xef 2393 && firstline[1] == 0xbb && firstline[2] == 0xbf) { 2394 // Found BOM; setup conversion, skip over BOM and recode the line. 2395 convert_setup(&cookie.conv, "utf-8", p_enc); 2396 char *p = string_convert(&cookie.conv, (char *)firstline + 3, NULL); 2397 if (p == NULL) { 2398 p = xstrdup((char *)firstline + 3); 2399 } 2400 xfree(firstline); 2401 firstline = (uint8_t *)p; 2402 } 2403 // Call do_cmdline, which will call getsourceline() to get the lines. 2404 do_cmdline((char *)firstline, getsourceline, (void *)&cookie, 2405 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); 2406 } 2407 retval = OK; 2408 2409 if (l_do_profiling == PROF_YES && si != NULL) { 2410 // Get "si" again, "script_items" may have been reallocated. 2411 si = SCRIPT_ITEM(current_sctx.sc_sid); 2412 if (si->sn_prof_on) { 2413 si->sn_pr_start = profile_end(si->sn_pr_start); 2414 si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start); 2415 si->sn_pr_total = profile_add(si->sn_pr_total, si->sn_pr_start); 2416 si->sn_pr_self = profile_self(si->sn_pr_self, si->sn_pr_start, 2417 si->sn_pr_children); 2418 } 2419 } 2420 2421 if (got_int) { 2422 emsg(_(e_interr)); 2423 } 2424 ESTACK_CHECK_NOW; 2425 estack_pop(); 2426 if (p_verbose > 1) { 2427 verbose_enter(); 2428 smsg(0, _("finished sourcing %s"), fname); 2429 if (SOURCING_NAME != NULL) { 2430 smsg(0, _("continuing in %s"), SOURCING_NAME); 2431 } 2432 verbose_leave(); 2433 } 2434 2435 if (l_time_fd != NULL) { 2436 vim_snprintf(IObuff, IOSIZE, "sourcing %s", fname); 2437 time_msg(IObuff, &start_time); 2438 time_pop(rel_time); 2439 } 2440 2441 if (!got_int) { 2442 trigger_source_post = true; 2443 } 2444 2445 // After a "finish" in debug mode, need to break at first command of next 2446 // sourced file. 2447 if (save_debug_break_level > ex_nesting_level 2448 && debug_break_level == ex_nesting_level) { 2449 debug_break_level++; 2450 } 2451 2452 current_sctx = save_current_sctx; 2453 restore_funccal(); 2454 if (l_do_profiling == PROF_YES) { 2455 prof_child_exit(&wait_start); // leaving a child now 2456 } 2457 if (cookie.fp != NULL) { 2458 fclose(cookie.fp); 2459 } 2460 if (cookie.source_from_buf_or_str) { 2461 ga_clear_strings(&cookie.buflines); 2462 } 2463 xfree(cookie.nextline); 2464 xfree(firstline); 2465 convert_setup(&cookie.conv, NULL, NULL); 2466 2467 if (str == NULL && trigger_source_post) { 2468 apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf); 2469 } 2470 2471 theend: 2472 xfree(fname_exp); 2473 return retval; 2474 } 2475 2476 /// @param check_other check for .vimrc and _vimrc 2477 /// @param is_vimrc DOSO_ value 2478 int do_source(char *fname, bool check_other, int is_vimrc, int *ret_sid) 2479 { 2480 return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, false, NULL); 2481 } 2482 2483 /// Checks if the script with the given script ID is a Lua script. 2484 bool script_is_lua(scid_T sid) 2485 { 2486 if (sid == SID_LUA) { 2487 return true; 2488 } 2489 if (!SCRIPT_ID_VALID(sid)) { 2490 return false; 2491 } 2492 return SCRIPT_ITEM(sid)->sn_lua; 2493 } 2494 2495 /// Find an already loaded script "name". 2496 /// If found returns its script ID. If not found returns -1. 2497 int find_script_by_name(char *name) 2498 { 2499 assert(script_items.ga_len >= 0); 2500 for (int sid = script_items.ga_len; sid > 0; sid--) { 2501 // We used to check inode here, but that doesn't work: 2502 // - If a script is edited and written, it may get a different 2503 // inode number, even though to the user it is the same script. 2504 // - If a script is deleted and another script is written, with a 2505 // different name, the inode may be re-used. 2506 scriptitem_T *si = SCRIPT_ITEM(sid); 2507 if (si->sn_name != NULL && path_fnamecmp(si->sn_name, name) == 0) { 2508 return sid; 2509 } 2510 } 2511 return -1; 2512 } 2513 2514 /// ":scriptnames" 2515 void ex_scriptnames(exarg_T *eap) 2516 { 2517 if (eap->addr_count > 0 || *eap->arg != NUL) { 2518 // :script {scriptId}: edit the script 2519 if (eap->addr_count > 0 && !SCRIPT_ID_VALID(eap->line2)) { 2520 emsg(_(e_invarg)); 2521 } else { 2522 if (eap->addr_count > 0) { 2523 eap->arg = SCRIPT_ITEM(eap->line2)->sn_name; 2524 } else { 2525 expand_env(eap->arg, NameBuff, MAXPATHL); 2526 eap->arg = NameBuff; 2527 } 2528 do_exedit(eap, NULL); 2529 } 2530 return; 2531 } 2532 2533 msg_ext_set_kind("list_cmd"); 2534 for (int i = 1; i <= script_items.ga_len && !got_int; i++) { 2535 if (SCRIPT_ITEM(i)->sn_name != NULL) { 2536 home_replace(NULL, SCRIPT_ITEM(i)->sn_name, NameBuff, MAXPATHL, true); 2537 vim_snprintf(IObuff, IOSIZE, "%3d: %s", i, NameBuff); 2538 if (!message_filtered(IObuff)) { 2539 if (msg_col > 0) { 2540 msg_putchar('\n'); 2541 } 2542 msg_outtrans(IObuff, 0, false); 2543 line_breakcheck(); 2544 } 2545 } 2546 } 2547 } 2548 2549 #if defined(BACKSLASH_IN_FILENAME) 2550 /// Fix slashes in the list of script names for 'shellslash'. 2551 void scriptnames_slash_adjust(void) 2552 { 2553 for (int i = 1; i <= script_items.ga_len; i++) { 2554 if (SCRIPT_ITEM(i)->sn_name != NULL) { 2555 slash_adjust(SCRIPT_ITEM(i)->sn_name); 2556 } 2557 } 2558 } 2559 2560 #endif 2561 2562 /// Get a pointer to a script name. Used for ":verbose set". 2563 /// Message appended to "Last set from " 2564 /// 2565 /// @param should_free if non-NULL and the script name is a file path, call 2566 /// home_replace_save() on it and set *should_free to true. 2567 char *get_scriptname(sctx_T script_ctx, bool *should_free) 2568 { 2569 if (should_free != NULL) { 2570 *should_free = false; 2571 } 2572 2573 switch (script_ctx.sc_sid) { 2574 case SID_MODELINE: 2575 return _("modeline"); 2576 case SID_CMDARG: 2577 return _("--cmd argument"); 2578 case SID_CARG: 2579 return _("-c argument"); 2580 case SID_ENV: 2581 return _("environment variable"); 2582 case SID_ERROR: 2583 return _("error handler"); 2584 case SID_WINLAYOUT: 2585 return _("changed window size"); 2586 case SID_LUA: 2587 return _("Lua"); 2588 case SID_API_CLIENT: 2589 snprintf(IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), script_ctx.sc_chan); 2590 return IObuff; 2591 case SID_STR: 2592 return _("anonymous :source"); 2593 default: { 2594 char *const sname = SCRIPT_ITEM(script_ctx.sc_sid)->sn_name; 2595 if (sname == NULL) { 2596 snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"), 2597 script_ctx.sc_sid); 2598 return IObuff; 2599 } 2600 if (should_free != NULL) { 2601 *should_free = true; 2602 return home_replace_save(NULL, sname); 2603 } else { 2604 return sname; 2605 } 2606 } 2607 } 2608 } 2609 2610 #if defined(EXITFREE) 2611 void free_scriptnames(void) 2612 { 2613 profile_reset(); 2614 2615 # define FREE_SCRIPTNAME(item) \ 2616 do { \ 2617 scriptitem_T *_si = *(item); \ 2618 /* the variables themselves are cleared in evalvars_clear() */ \ 2619 xfree(_si->sn_vars); \ 2620 xfree(_si->sn_name); \ 2621 ga_clear(&_si->sn_prl_ga); \ 2622 xfree(_si); \ 2623 } while (0) \ 2624 2625 GA_DEEP_CLEAR(&script_items, scriptitem_T *, FREE_SCRIPTNAME); 2626 } 2627 #endif 2628 2629 void free_autoload_scriptnames(void) 2630 { 2631 ga_clear_strings(&ga_loaded); 2632 } 2633 2634 linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) 2635 FUNC_ATTR_PURE 2636 { 2637 return fgetline == getsourceline 2638 ? ((source_cookie_T *)cookie)->sourcing_lnum 2639 : SOURCING_LNUM; 2640 } 2641 2642 /// Return a List of script-local functions defined in the script with id "sid". 2643 static list_T *get_script_local_funcs(scid_T sid) 2644 { 2645 hashtab_T *const functbl = func_tbl_get(); 2646 list_T *l = tv_list_alloc((ptrdiff_t)functbl->ht_used); 2647 2648 // Iterate through all the functions in the global function hash table 2649 // looking for functions with script ID "sid". 2650 HASHTAB_ITER(functbl, hi, { 2651 const ufunc_T *const fp = HI2UF(hi); 2652 // Add functions with script id == "sid" 2653 if (fp->uf_script_ctx.sc_sid == sid) { 2654 const char *const name = fp->uf_name_exp != NULL ? fp->uf_name_exp : fp->uf_name; 2655 tv_list_append_string(l, name, -1); 2656 } 2657 }); 2658 2659 return l; 2660 } 2661 2662 /// "getscriptinfo()" function 2663 void f_getscriptinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 2664 { 2665 tv_list_alloc_ret(rettv, script_items.ga_len); 2666 2667 if (tv_check_for_opt_dict_arg(argvars, 0) == FAIL) { 2668 return; 2669 } 2670 2671 list_T *l = rettv->vval.v_list; 2672 2673 regmatch_T regmatch = { 2674 .regprog = NULL, 2675 .rm_ic = p_ic, 2676 }; 2677 bool filterpat = false; 2678 varnumber_T sid = -1; 2679 2680 char *pat = NULL; 2681 if (argvars[0].v_type == VAR_DICT) { 2682 dictitem_T *sid_di = tv_dict_find(argvars[0].vval.v_dict, S_LEN("sid")); 2683 if (sid_di != NULL) { 2684 bool error = false; 2685 sid = tv_get_number_chk(&sid_di->di_tv, &error); 2686 if (error) { 2687 return; 2688 } 2689 if (sid <= 0) { 2690 semsg(_(e_invargNval), "sid", tv_get_string(&sid_di->di_tv)); 2691 return; 2692 } 2693 } else { 2694 pat = tv_dict_get_string(argvars[0].vval.v_dict, "name", true); 2695 if (pat != NULL) { 2696 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 2697 } 2698 if (regmatch.regprog != NULL) { 2699 filterpat = true; 2700 } 2701 } 2702 } 2703 2704 for (varnumber_T i = sid > 0 ? sid : 1; 2705 (i == sid || sid <= 0) && i <= script_items.ga_len; i++) { 2706 scriptitem_T *si = SCRIPT_ITEM(i); 2707 2708 if (si->sn_name == NULL) { 2709 continue; 2710 } 2711 2712 if (filterpat && !vim_regexec(®match, si->sn_name, 0)) { 2713 continue; 2714 } 2715 2716 dict_T *d = tv_dict_alloc(); 2717 tv_list_append_dict(l, d); 2718 tv_dict_add_str(d, S_LEN("name"), si->sn_name); 2719 tv_dict_add_nr(d, S_LEN("sid"), i); 2720 tv_dict_add_nr(d, S_LEN("version"), 1); 2721 // Vim9 autoload script (:h vim9-autoload), not applicable to Nvim. 2722 tv_dict_add_bool(d, S_LEN("autoload"), false); 2723 2724 // When a script ID is specified, return information about only the 2725 // specified script, and add the script-local variables and functions. 2726 if (sid > 0) { 2727 dict_T *var_dict = tv_dict_copy(NULL, &si->sn_vars->sv_dict, true, get_copyID()); 2728 tv_dict_add_dict(d, S_LEN("variables"), var_dict); 2729 tv_dict_add_list(d, S_LEN("functions"), get_script_local_funcs((scid_T)sid)); 2730 } 2731 } 2732 2733 vim_regfree(regmatch.regprog); 2734 xfree(pat); 2735 } 2736 2737 /// Get one full line from a sourced file. 2738 /// Called by do_cmdline() when it's called from do_source(). 2739 /// 2740 /// @return pointer to the line in allocated memory, or NULL for end-of-file or 2741 /// some error. 2742 char *getsourceline(int c, void *cookie, int indent, bool do_concat) 2743 { 2744 source_cookie_T *sp = (source_cookie_T *)cookie; 2745 char *line; 2746 2747 // If breakpoints have been added/deleted need to check for it. 2748 if ((sp->dbg_tick < debug_tick) && !sp->source_from_buf_or_str) { 2749 sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM); 2750 sp->dbg_tick = debug_tick; 2751 } 2752 if (do_profiling == PROF_YES) { 2753 script_line_end(); 2754 } 2755 // Set the current sourcing line number. 2756 SOURCING_LNUM = sp->sourcing_lnum + 1; 2757 // Get current line. If there is a read-ahead line, use it, otherwise get 2758 // one now. "fp" is NULL if actually using a string. 2759 if (sp->finished || (!sp->source_from_buf_or_str && sp->fp == NULL)) { 2760 line = NULL; 2761 } else if (sp->nextline == NULL) { 2762 line = get_one_sourceline(sp); 2763 } else { 2764 line = sp->nextline; 2765 sp->nextline = NULL; 2766 sp->sourcing_lnum++; 2767 } 2768 if (line != NULL && do_profiling == PROF_YES) { 2769 script_line_start(); 2770 } 2771 2772 // Only concatenate lines starting with a \ when 'cpoptions' doesn't 2773 // contain the 'C' flag. 2774 if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { 2775 char *p; 2776 // compensate for the one line read-ahead 2777 sp->sourcing_lnum--; 2778 2779 // Get the next line and concatenate it when it starts with a 2780 // backslash. We always need to read the next line, keep it in 2781 // sp->nextline. 2782 // Also check for a comment in between continuation lines: "\ . 2783 sp->nextline = get_one_sourceline(sp); 2784 if (sp->nextline != NULL 2785 && (*(p = skipwhite(sp->nextline)) == '\\' 2786 || (p[0] == '"' && p[1] == '\\' && p[2] == ' '))) { 2787 garray_T ga; 2788 2789 ga_init(&ga, (int)sizeof(char), 400); 2790 ga_concat(&ga, line); 2791 while (sp->nextline != NULL 2792 && concat_continued_line(&ga, 400, sp->nextline, strlen(sp->nextline))) { 2793 xfree(sp->nextline); 2794 sp->nextline = get_one_sourceline(sp); 2795 } 2796 ga_append(&ga, NUL); 2797 xfree(line); 2798 line = ga.ga_data; 2799 } 2800 } 2801 2802 if (line != NULL && sp->conv.vc_type != CONV_NONE) { 2803 // Convert the encoding of the script line. 2804 char *s = string_convert(&sp->conv, line, NULL); 2805 if (s != NULL) { 2806 xfree(line); 2807 line = s; 2808 } 2809 } 2810 2811 // Did we encounter a breakpoint? 2812 if (!sp->source_from_buf_or_str 2813 && sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) { 2814 dbg_breakpoint(sp->fname, SOURCING_LNUM); 2815 // Find next breakpoint. 2816 sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM); 2817 sp->dbg_tick = debug_tick; 2818 } 2819 2820 return line; 2821 } 2822 2823 static char *get_one_sourceline(source_cookie_T *sp) 2824 { 2825 garray_T ga; 2826 int len; 2827 int c; 2828 char *buf; 2829 #ifdef USE_CRNL 2830 bool has_cr; // CR-LF found 2831 #endif 2832 bool have_read = false; 2833 2834 // use a growarray to store the sourced line 2835 ga_init(&ga, 1, 250); 2836 2837 // Loop until there is a finished line (or end-of-file). 2838 sp->sourcing_lnum++; 2839 while (true) { 2840 // make room to read at least 120 (more) characters 2841 ga_grow(&ga, 120); 2842 if (sp->source_from_buf_or_str) { 2843 if (sp->buf_lnum >= sp->buflines.ga_len) { 2844 break; // all the lines are processed 2845 } 2846 ga_concat(&ga, ((char **)sp->buflines.ga_data)[sp->buf_lnum]); 2847 sp->buf_lnum++; 2848 ga_grow(&ga, 1); 2849 buf = (char *)ga.ga_data; 2850 buf[ga.ga_len++] = NUL; 2851 len = ga.ga_len; 2852 } else { 2853 buf = ga.ga_data; 2854 retry: 2855 errno = 0; 2856 if (fgets(buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, sp->fp) == NULL) { 2857 if (errno == EINTR) { 2858 goto retry; 2859 } 2860 break; 2861 } 2862 len = ga.ga_len + (int)strlen(buf + ga.ga_len); 2863 } 2864 #ifdef USE_CRNL 2865 // Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the 2866 // CTRL-Z by its own, or after a NL. 2867 if ((len == 1 || (len >= 2 && buf[len - 2] == '\n')) 2868 && sp->fileformat == EOL_DOS 2869 && buf[len - 1] == Ctrl_Z) { 2870 buf[len - 1] = NUL; 2871 break; 2872 } 2873 #endif 2874 2875 have_read = true; 2876 ga.ga_len = len; 2877 2878 // If the line was longer than the buffer, read more. 2879 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n') { 2880 continue; 2881 } 2882 2883 if (len >= 1 && buf[len - 1] == '\n') { // remove trailing NL 2884 #ifdef USE_CRNL 2885 has_cr = (len >= 2 && buf[len - 2] == '\r'); 2886 if (sp->fileformat == EOL_UNKNOWN) { 2887 if (has_cr) { 2888 sp->fileformat = EOL_DOS; 2889 } else { 2890 sp->fileformat = EOL_UNIX; 2891 } 2892 } 2893 2894 if (sp->fileformat == EOL_DOS) { 2895 if (has_cr) { // replace trailing CR 2896 buf[len - 2] = '\n'; 2897 len--; 2898 ga.ga_len--; 2899 } else { // lines like ":map xx yy^M" will have failed 2900 if (!sp->error) { 2901 msg_source(HL_ATTR(HLF_W)); 2902 emsg(_("W15: Warning: Wrong line separator, ^M may be missing")); 2903 } 2904 sp->error = true; 2905 sp->fileformat = EOL_UNIX; 2906 } 2907 } 2908 #endif 2909 // The '\n' is escaped if there is an odd number of ^V's just 2910 // before it, first set "c" just before the 'V's and then check 2911 // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo 2912 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {} 2913 if ((len & 1) != (c & 1)) { // escaped NL, read more 2914 sp->sourcing_lnum++; 2915 continue; 2916 } 2917 2918 buf[len - 1] = NUL; // remove the NL 2919 } 2920 2921 // Check for ^C here now and then, so recursive :so can be broken. 2922 line_breakcheck(); 2923 break; 2924 } 2925 2926 if (have_read) { 2927 return ga.ga_data; 2928 } 2929 2930 xfree(ga.ga_data); 2931 return NULL; 2932 } 2933 2934 /// Returns true if sourcing a script either from a file or a buffer or a string. 2935 /// Otherwise returns false. 2936 int sourcing_a_script(exarg_T *eap) 2937 { 2938 return getline_equal(eap->ea_getline, eap->cookie, getsourceline); 2939 } 2940 2941 /// ":scriptencoding": Set encoding conversion for a sourced script. 2942 /// Without the multi-byte feature it's simply ignored. 2943 void ex_scriptencoding(exarg_T *eap) 2944 { 2945 if (!sourcing_a_script(eap)) { 2946 emsg(_("E167: :scriptencoding used outside of a sourced file")); 2947 return; 2948 } 2949 2950 char *name = (*eap->arg != NUL) ? enc_canonize(eap->arg) : eap->arg; 2951 2952 // Setup for conversion from the specified encoding to 'encoding'. 2953 source_cookie_T *sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie); 2954 convert_setup(&sp->conv, name, p_enc); 2955 2956 if (name != eap->arg) { 2957 xfree(name); 2958 } 2959 } 2960 2961 /// ":finish": Mark a sourced file as finished. 2962 void ex_finish(exarg_T *eap) 2963 { 2964 if (sourcing_a_script(eap)) { 2965 do_finish(eap, false); 2966 } else { 2967 emsg(_("E168: :finish used outside of a sourced file")); 2968 } 2969 } 2970 2971 /// Mark a sourced file as finished. Possibly makes the ":finish" pending. 2972 /// Also called for a pending finish at the ":endtry" or after returning from 2973 /// an extra do_cmdline(). "reanimate" is used in the latter case. 2974 void do_finish(exarg_T *eap, bool reanimate) 2975 { 2976 if (reanimate) { 2977 ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = false; 2978 } 2979 2980 // Cleanup (and deactivate) conditionals, but stop when a try conditional 2981 // not in its finally clause (which then is to be executed next) is found. 2982 // In this case, make the ":finish" pending for execution at the ":endtry". 2983 // Otherwise, finish normally. 2984 int idx = cleanup_conditionals(eap->cstack, 0, true); 2985 if (idx >= 0) { 2986 eap->cstack->cs_pending[idx] = CSTP_FINISH; 2987 report_make_pending(CSTP_FINISH, NULL); 2988 } else { 2989 ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = true; 2990 } 2991 } 2992 2993 /// @return true when a sourced file had the ":finish" command: Don't give error 2994 /// message for missing ":endif". 2995 /// false when not sourcing a file. 2996 bool source_finished(LineGetter fgetline, void *cookie) 2997 { 2998 return getline_equal(fgetline, cookie, getsourceline) 2999 && ((source_cookie_T *)getline_cookie(fgetline, cookie))->finished; 3000 } 3001 3002 /// Return the autoload script name for a function or variable name 3003 /// Caller must make sure that "name" contains AUTOLOAD_CHAR. 3004 /// 3005 /// @param[in] name Variable/function name. 3006 /// @param[in] name_len Name length. 3007 /// 3008 /// @return [allocated] autoload script name. 3009 char *autoload_name(const char *const name, const size_t name_len) 3010 FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT 3011 { 3012 // Get the script file name: replace '#' with '/', append ".vim". 3013 char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); 3014 memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); 3015 memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); 3016 size_t auchar_idx = 0; 3017 for (size_t i = sizeof("autoload/") - 1; 3018 i - sizeof("autoload/") + 1 < name_len; 3019 i++) { 3020 if (scriptname[i] == AUTOLOAD_CHAR) { 3021 scriptname[i] = '/'; 3022 auchar_idx = i; 3023 } 3024 } 3025 memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); 3026 3027 return scriptname; 3028 } 3029 3030 /// If name has a package name try autoloading the script for it 3031 /// 3032 /// @param[in] name Variable/function name. 3033 /// @param[in] name_len Name length. 3034 /// @param[in] reload If true, load script again when already loaded. 3035 /// 3036 /// @return true if a package was loaded. 3037 bool script_autoload(const char *const name, const size_t name_len, const bool reload) 3038 { 3039 // If there is no '#' after name[0] there is no package name. 3040 const char *p = memchr(name, AUTOLOAD_CHAR, name_len); 3041 if (p == NULL || p == name) { 3042 return false; 3043 } 3044 3045 bool ret = false; 3046 char *tofree = autoload_name(name, name_len); 3047 char *scriptname = tofree; 3048 3049 // Find the name in the list of previously loaded package names. Skip 3050 // "autoload/", it's always the same. 3051 int i = 0; 3052 for (; i < ga_loaded.ga_len; i++) { 3053 if (strcmp(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) { 3054 break; 3055 } 3056 } 3057 if (!reload && i < ga_loaded.ga_len) { 3058 ret = false; // Was loaded already. 3059 } else { 3060 // Remember the name if it wasn't loaded already. 3061 if (i == ga_loaded.ga_len) { 3062 GA_APPEND(char *, &ga_loaded, scriptname); 3063 tofree = NULL; 3064 } 3065 3066 // Try loading the package from $VIMRUNTIME/autoload/<name>.vim 3067 // Use "ret_sid" to avoid loading the same script again. 3068 int ret_sid; 3069 if (do_in_runtimepath(scriptname, DIP_START, source_callback, &ret_sid) == OK) { 3070 ret = true; 3071 } 3072 } 3073 3074 xfree(tofree); 3075 return ret; 3076 }