ex_docmd.c (247316B)
1 // ex_docmd.c: functions for executing an Ex command line. 2 3 #include <assert.h> 4 #include <ctype.h> 5 #include <inttypes.h> 6 #include <limits.h> 7 #include <stdbool.h> 8 #include <stddef.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <uv.h> 13 14 #include "auto/config.h" 15 #include "nvim/api/private/defs.h" 16 #include "nvim/api/private/dispatch.h" 17 #include "nvim/api/private/helpers.h" 18 #include "nvim/api/ui.h" 19 #include "nvim/api/vimscript.h" 20 #include "nvim/arglist.h" 21 #include "nvim/ascii_defs.h" 22 #include "nvim/autocmd.h" 23 #include "nvim/autocmd_defs.h" 24 #include "nvim/buffer.h" 25 #include "nvim/buffer_defs.h" 26 #include "nvim/change.h" 27 #include "nvim/channel.h" 28 #include "nvim/charset.h" 29 #include "nvim/clipboard.h" 30 #include "nvim/cmdexpand.h" 31 #include "nvim/cmdexpand_defs.h" 32 #include "nvim/cursor.h" 33 #include "nvim/debugger.h" 34 #include "nvim/digraph.h" 35 #include "nvim/drawscreen.h" 36 #include "nvim/edit.h" 37 #include "nvim/errors.h" 38 #include "nvim/eval/fs.h" 39 #include "nvim/eval/typval.h" 40 #include "nvim/eval/typval_defs.h" 41 #include "nvim/eval/userfunc.h" 42 #include "nvim/eval/vars.h" 43 #include "nvim/event/loop.h" 44 #include "nvim/event/multiqueue.h" 45 #include "nvim/ex_cmds.h" 46 #include "nvim/ex_cmds2.h" 47 #include "nvim/ex_cmds_defs.h" 48 #include "nvim/ex_docmd.h" 49 #include "nvim/ex_eval.h" 50 #include "nvim/ex_eval_defs.h" 51 #include "nvim/ex_getln.h" 52 #include "nvim/file_search.h" 53 #include "nvim/fileio.h" 54 #include "nvim/fold.h" 55 #include "nvim/garray.h" 56 #include "nvim/garray_defs.h" 57 #include "nvim/getchar.h" 58 #include "nvim/gettext_defs.h" 59 #include "nvim/globals.h" 60 #include "nvim/highlight_defs.h" 61 #include "nvim/highlight_group.h" 62 #include "nvim/input.h" 63 #include "nvim/keycodes.h" 64 #include "nvim/lua/executor.h" 65 #include "nvim/macros_defs.h" 66 #include "nvim/main.h" 67 #include "nvim/mark.h" 68 #include "nvim/mark_defs.h" 69 #include "nvim/mbyte.h" 70 #include "nvim/memline.h" 71 #include "nvim/memline_defs.h" 72 #include "nvim/memory.h" 73 #include "nvim/message.h" 74 #include "nvim/mouse.h" 75 #include "nvim/move.h" 76 #include "nvim/normal.h" 77 #include "nvim/normal_defs.h" 78 #include "nvim/option.h" 79 #include "nvim/option_defs.h" 80 #include "nvim/option_vars.h" 81 #include "nvim/optionstr.h" 82 #include "nvim/os/fs.h" 83 #include "nvim/os/input.h" 84 #include "nvim/os/os.h" 85 #include "nvim/os/os_defs.h" 86 #include "nvim/os/shell.h" 87 #include "nvim/path.h" 88 #include "nvim/plines.h" 89 #include "nvim/popupmenu.h" 90 #include "nvim/pos_defs.h" 91 #include "nvim/profile.h" 92 #include "nvim/quickfix.h" 93 #include "nvim/regexp.h" 94 #include "nvim/regexp_defs.h" 95 #include "nvim/runtime.h" 96 #include "nvim/runtime_defs.h" 97 #include "nvim/search.h" 98 #include "nvim/shada.h" 99 #include "nvim/state.h" 100 #include "nvim/state_defs.h" 101 #include "nvim/statusline.h" 102 #include "nvim/strings.h" 103 #include "nvim/tag.h" 104 #include "nvim/types_defs.h" 105 #include "nvim/ui.h" 106 #include "nvim/ui_client.h" 107 #include "nvim/undo.h" 108 #include "nvim/undo_defs.h" 109 #include "nvim/usercmd.h" 110 #include "nvim/vim_defs.h" 111 #include "nvim/window.h" 112 #include "nvim/winfloat.h" 113 114 static const char e_ambiguous_use_of_user_defined_command[] 115 = N_("E464: Ambiguous use of user-defined command"); 116 static const char e_no_call_stack_to_substitute_for_stack[] 117 = N_("E489: No call stack to substitute for \"<stack>\""); 118 static const char e_not_an_editor_command[] 119 = N_("E492: Not an editor command"); 120 static const char e_no_autocommand_file_name_to_substitute_for_afile[] 121 = N_("E495: No autocommand file name to substitute for \"<afile>\""); 122 static const char e_no_autocommand_buffer_number_to_substitute_for_abuf[] 123 = N_("E496: No autocommand buffer number to substitute for \"<abuf>\""); 124 static const char e_no_autocommand_match_name_to_substitute_for_amatch[] 125 = N_("E497: No autocommand match name to substitute for \"<amatch>\""); 126 static const char e_no_source_file_name_to_substitute_for_sfile[] 127 = N_("E498: No :source file name to substitute for \"<sfile>\""); 128 static const char e_no_line_number_to_use_for_slnum[] 129 = N_("E842: No line number to use for \"<slnum>\""); 130 static const char e_no_line_number_to_use_for_sflnum[] 131 = N_("E961: No line number to use for \"<sflnum>\""); 132 static const char e_no_script_file_name_to_substitute_for_script[] 133 = N_("E1274: No script file name to substitute for \"<script>\""); 134 135 static int quitmore = 0; 136 static bool ex_pressedreturn = false; 137 138 // Struct for storing a line inside a while/for loop 139 typedef struct { 140 char *line; // command line 141 linenr_T lnum; // sourcing_lnum of the line 142 } wcmd_T; 143 144 #define FREE_WCMD(wcmd) xfree((wcmd)->line) 145 146 /// Structure used to store info for line position in a while or for loop. 147 /// This is required, because do_one_cmd() may invoke ex_function(), which 148 /// reads more lines that may come from the while/for loop. 149 struct loop_cookie { 150 garray_T *lines_gap; // growarray with line info 151 int current_line; // last read line from growarray 152 int repeating; // true when looping a second time 153 // When "repeating" is false use "getline" and "cookie" to get lines 154 LineGetter lc_getline; 155 void *cookie; 156 }; 157 158 // Struct to save a few things while debugging. Used in do_cmdline() only. 159 struct dbg_stuff { 160 int trylevel; 161 int force_abort; 162 except_T *caught_stack; 163 char *vv_exception; 164 char *vv_throwpoint; 165 int did_emsg; 166 int got_int; 167 bool did_throw; 168 int need_rethrow; 169 int check_cstack; 170 except_T *current_exception; 171 }; 172 173 #include "ex_docmd.c.generated.h" 174 175 // Declare cmdnames[]. 176 #include "ex_cmds_defs.generated.h" 177 178 static char dollar_command[2] = { '$', 0 }; 179 180 static void save_dbg_stuff(struct dbg_stuff *dsp) 181 { 182 dsp->trylevel = trylevel; 183 trylevel = 0; 184 dsp->force_abort = force_abort; 185 force_abort = false; 186 dsp->caught_stack = caught_stack; 187 caught_stack = NULL; 188 dsp->vv_exception = v_exception(NULL); 189 dsp->vv_throwpoint = v_throwpoint(NULL); 190 191 // Necessary for debugging an inactive ":catch", ":finally", ":endtry". 192 dsp->did_emsg = did_emsg; 193 did_emsg = false; 194 dsp->got_int = got_int; 195 got_int = false; 196 dsp->did_throw = did_throw; 197 did_throw = false; 198 dsp->need_rethrow = need_rethrow; 199 need_rethrow = false; 200 dsp->check_cstack = check_cstack; 201 check_cstack = false; 202 dsp->current_exception = current_exception; 203 current_exception = NULL; 204 } 205 206 static void restore_dbg_stuff(struct dbg_stuff *dsp) 207 { 208 suppress_errthrow = false; 209 trylevel = dsp->trylevel; 210 force_abort = dsp->force_abort; 211 caught_stack = dsp->caught_stack; 212 v_exception(dsp->vv_exception); 213 v_throwpoint(dsp->vv_throwpoint); 214 did_emsg = dsp->did_emsg; 215 got_int = dsp->got_int; 216 did_throw = dsp->did_throw; 217 need_rethrow = dsp->need_rethrow; 218 check_cstack = dsp->check_cstack; 219 current_exception = dsp->current_exception; 220 } 221 222 /// Check if ffname differs from fnum. 223 /// fnum is a buffer number. 0 == current buffer, 1-or-more must be a valid buffer ID. 224 /// ffname is a full path to where a buffer lives on-disk or would live on-disk. 225 static bool is_other_file(int fnum, char *ffname) 226 { 227 if (fnum != 0) { 228 if (fnum == curbuf->b_fnum) { 229 return false; 230 } 231 232 return true; 233 } 234 235 if (ffname == NULL) { 236 return true; 237 } 238 239 if (*ffname == NUL) { 240 return false; 241 } 242 243 if (!curbuf->file_id_valid 244 && curbuf->b_sfname != NULL 245 && *curbuf->b_sfname != NUL) { 246 // This occurs with unsaved buffers. In which case `ffname` 247 // actually corresponds to curbuf->b_sfname 248 return path_fnamecmp(ffname, curbuf->b_sfname) != 0; 249 } 250 251 return otherfile(ffname); 252 } 253 254 /// Repeatedly get commands for Ex mode, until the ":vi" command is given. 255 void do_exmode(void) 256 { 257 exmode_active = true; 258 State = MODE_NORMAL; 259 may_trigger_modechanged(); 260 261 // When using ":global /pat/ visual" and then "Q" we return to continue 262 // the :global command. 263 if (global_busy) { 264 return; 265 } 266 267 int save_msg_scroll = msg_scroll; 268 RedrawingDisabled++; // don't redisplay the window 269 no_wait_return++; // don't wait for return 270 271 msg(_("Entering Ex mode. Type \"visual\" to go to Normal mode."), 0); 272 while (exmode_active) { 273 // Check for a ":normal" command and no more characters left. 274 if (ex_normal_busy > 0 && typebuf.tb_len == 0) { 275 exmode_active = false; 276 break; 277 } 278 msg_scroll = true; 279 need_wait_return = false; 280 ex_pressedreturn = false; 281 ex_no_reprint = false; 282 varnumber_T changedtick = buf_get_changedtick(curbuf); 283 int prev_msg_row = msg_row; 284 linenr_T prev_line = curwin->w_cursor.lnum; 285 cmdline_row = msg_row; 286 do_cmdline(NULL, getexline, NULL, 0); 287 lines_left = Rows - 1; 288 289 if ((prev_line != curwin->w_cursor.lnum 290 || changedtick != buf_get_changedtick(curbuf)) && !ex_no_reprint) { 291 if (curbuf->b_ml.ml_flags & ML_EMPTY) { 292 emsg(_(e_empty_buffer)); 293 } else { 294 if (ex_pressedreturn) { 295 // Make sure the message overwrites the right line and isn't throttled. 296 msg_scroll_flush(); 297 // go up one line, to overwrite the ":<CR>" line, so the 298 // output doesn't contain empty lines. 299 msg_row = prev_msg_row; 300 if (prev_msg_row == Rows - 1) { 301 msg_row--; 302 } 303 } 304 msg_col = 0; 305 print_line_no_prefix(curwin->w_cursor.lnum, false, false); 306 msg_clr_eos(); 307 } 308 } else if (ex_pressedreturn && !ex_no_reprint) { // must be at EOF 309 if (curbuf->b_ml.ml_flags & ML_EMPTY) { 310 emsg(_(e_empty_buffer)); 311 } else { 312 emsg(_("E501: At end-of-file")); 313 } 314 } 315 } 316 317 RedrawingDisabled--; 318 no_wait_return--; 319 redraw_all_later(UPD_NOT_VALID); 320 update_screen(); 321 need_wait_return = false; 322 msg_scroll = save_msg_scroll; 323 } 324 325 /// Print the executed command for when 'verbose' is set. 326 /// 327 /// @param lnum if 0, only print the command. 328 static void msg_verbose_cmd(linenr_T lnum, char *cmd) 329 FUNC_ATTR_NONNULL_ALL 330 { 331 no_wait_return++; 332 verbose_enter_scroll(); 333 334 if (lnum == 0) { 335 smsg(0, _("Executing: %s"), cmd); 336 } else { 337 smsg(0, _("line %" PRIdLINENR ": %s"), lnum, cmd); 338 } 339 if (msg_silent == 0) { 340 msg_puts("\n"); // don't overwrite this 341 } 342 343 verbose_leave_scroll(); 344 no_wait_return--; 345 } 346 347 static int cmdline_call_depth = 0; ///< recursiveness 348 349 /// Start executing an Ex command line. 350 /// 351 /// @return FAIL if too recursive, OK otherwise. 352 static int do_cmdline_start(void) 353 { 354 assert(cmdline_call_depth >= 0); 355 // It's possible to create an endless loop with ":execute", catch that 356 // here. The value of 200 allows nested function calls, ":source", etc. 357 // Allow 200 or 'maxfuncdepth', whatever is larger. 358 if (cmdline_call_depth >= 200 && cmdline_call_depth >= p_mfd) { 359 return FAIL; 360 } 361 cmdline_call_depth++; 362 start_batch_changes(); 363 return OK; 364 } 365 366 /// End executing an Ex command line. 367 static void do_cmdline_end(void) 368 { 369 cmdline_call_depth--; 370 assert(cmdline_call_depth >= 0); 371 end_batch_changes(); 372 } 373 374 /// Execute a simple command line. Used for translated commands like "*". 375 int do_cmdline_cmd(const char *cmd) 376 { 377 return do_cmdline((char *)cmd, NULL, NULL, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); 378 } 379 380 /// do_cmdline(): execute one Ex command line 381 /// 382 /// 1. Execute "cmdline" when it is not NULL. 383 /// If "cmdline" is NULL, or more lines are needed, fgetline() is used. 384 /// 2. Split up in parts separated with '|'. 385 /// 386 /// This function can be called recursively! 387 /// 388 /// flags: 389 /// DOCMD_VERBOSE - The command will be included in the error message. 390 /// DOCMD_NOWAIT - Don't call wait_return() and friends. 391 /// DOCMD_REPEAT - Repeat execution until fgetline() returns NULL. 392 /// DOCMD_KEYTYPED - Don't reset KeyTyped. 393 /// DOCMD_EXCRESET - Reset the exception environment (used for debugging). 394 /// DOCMD_KEEPLINE - Store first typed line (for repeating with "."). 395 /// 396 /// @param cookie argument for fgetline() 397 /// 398 /// @return FAIL if cmdline could not be executed, OK otherwise 399 int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) 400 { 401 char *next_cmdline; // next cmd to execute 402 char *cmdline_copy = NULL; // copy of cmd line 403 bool used_getline = false; // used "fgetline" to obtain command 404 static int recursive = 0; // recursive depth 405 bool msg_didout_before_start = false; 406 int count = 0; // line number count 407 bool did_inc = false; // incremented RedrawingDisabled 408 bool did_block = false; // emitted cmdline_block event 409 int retval = OK; 410 cstack_T cstack = { // conditional stack 411 .cs_idx = -1, 412 }; 413 garray_T lines_ga; // keep lines for ":while"/":for" 414 int current_line = 0; // active line in lines_ga 415 char *fname = NULL; // function or script name 416 linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie 417 int *dbg_tick = NULL; // ptr to dbg_tick field in cookie 418 struct dbg_stuff debug_saved; // saved things for debug mode 419 msglist_T *private_msg_list; 420 421 // "fgetline" and "cookie" passed to do_one_cmd() 422 char *(*cmd_getline)(int, void *, int, bool); 423 void *cmd_cookie; 424 struct loop_cookie cmd_loop_cookie; 425 426 // For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory 427 // location for storing error messages to be converted to an exception. 428 // This ensures that the do_errthrow() call in do_one_cmd() does not 429 // combine the messages stored by an earlier invocation of do_one_cmd() 430 // with the command name of the later one. This would happen when 431 // BufWritePost autocommands are executed after a write error. 432 msglist_T **saved_msg_list = msg_list; 433 msg_list = &private_msg_list; 434 private_msg_list = NULL; 435 436 if (do_cmdline_start() == FAIL) { 437 emsg(_(e_command_too_recursive)); 438 // When converting to an exception, we do not include the command name 439 // since this is not an error of the specific command. 440 do_errthrow((cstack_T *)NULL, NULL); 441 msg_list = saved_msg_list; 442 return FAIL; 443 } 444 445 ga_init(&lines_ga, (int)sizeof(wcmd_T), 10); 446 447 void *real_cookie = getline_cookie(fgetline, cookie); 448 449 // Inside a function use a higher nesting level. 450 bool getline_is_func = getline_equal(fgetline, cookie, get_func_line); 451 if (getline_is_func && ex_nesting_level == func_level(real_cookie)) { 452 ex_nesting_level++; 453 } 454 455 // Get the function or script name and the address where the next breakpoint 456 // line and the debug tick for a function or script are stored. 457 if (getline_is_func) { 458 fname = func_name(real_cookie); 459 breakpoint = func_breakpoint(real_cookie); 460 dbg_tick = func_dbg_tick(real_cookie); 461 } else if (getline_equal(fgetline, cookie, getsourceline)) { 462 fname = SOURCING_NAME; 463 breakpoint = source_breakpoint(real_cookie); 464 dbg_tick = source_dbg_tick(real_cookie); 465 } 466 467 // Initialize "force_abort" and "suppress_errthrow" at the top level. 468 if (!recursive) { 469 force_abort = false; 470 suppress_errthrow = false; 471 } 472 473 // If requested, store and reset the global values controlling the 474 // exception handling (used when debugging). Otherwise clear it to avoid 475 // a bogus compiler warning when the optimizer uses inline functions... 476 if (flags & DOCMD_EXCRESET) { 477 save_dbg_stuff(&debug_saved); 478 } else { 479 CLEAR_FIELD(debug_saved); 480 } 481 482 int initial_trylevel = trylevel; 483 484 // "did_throw" will be set to true when an exception is being thrown. 485 did_throw = false; 486 // "did_emsg" will be set to true when emsg() is used, in which case we 487 // cancel the whole command line, and any if/endif or loop. 488 // If force_abort is set, we cancel everything. 489 did_emsg = false; 490 491 // KeyTyped is only set when calling vgetc(). Reset it here when not 492 // calling vgetc() (sourced command lines). 493 if (!(flags & DOCMD_KEYTYPED) 494 && !getline_equal(fgetline, cookie, getexline)) { 495 KeyTyped = false; 496 } 497 498 // Continue executing command lines: 499 // - when inside an ":if", ":while" or ":for" 500 // - for multiple commands on one line, separated with '|' 501 // - when repeating until there are no more lines (for ":source") 502 next_cmdline = cmdline; 503 do { 504 getline_is_func = getline_equal(fgetline, cookie, get_func_line); 505 506 // stop skipping cmds for an error msg after all endif/while/for 507 if (next_cmdline == NULL 508 && !force_abort 509 && cstack.cs_idx < 0 510 && !(getline_is_func 511 && func_has_abort(real_cookie))) { 512 did_emsg = false; 513 } 514 515 // 1. If repeating a line in a loop, get a line from lines_ga. 516 // 2. If no line given: Get an allocated line with fgetline(). 517 // 3. If a line is given: Make a copy, so we can mess with it. 518 519 // 1. If repeating, get a previous line from lines_ga. 520 if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) { 521 // Each '|' separated command is stored separately in lines_ga, to 522 // be able to jump to it. Don't use next_cmdline now. 523 XFREE_CLEAR(cmdline_copy); 524 525 // Check if a function has returned or, unless it has an unclosed 526 // try conditional, aborted. 527 if (getline_is_func) { 528 if (do_profiling == PROF_YES) { 529 func_line_end(real_cookie); 530 } 531 if (func_has_ended(real_cookie)) { 532 retval = FAIL; 533 break; 534 } 535 } else if (do_profiling == PROF_YES 536 && getline_equal(fgetline, cookie, getsourceline)) { 537 script_line_end(); 538 } 539 540 // Check if a sourced file hit a ":finish" command. 541 if (source_finished(fgetline, cookie)) { 542 retval = FAIL; 543 break; 544 } 545 546 // If breakpoints have been added/deleted need to check for it. 547 if (breakpoint != NULL && dbg_tick != NULL 548 && *dbg_tick != debug_tick) { 549 *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), 550 fname, SOURCING_LNUM); 551 *dbg_tick = debug_tick; 552 } 553 554 next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line; 555 SOURCING_LNUM = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; 556 557 // Did we encounter a breakpoint? 558 if (breakpoint != NULL && *breakpoint != 0 && *breakpoint <= SOURCING_LNUM) { 559 dbg_breakpoint(fname, SOURCING_LNUM); 560 // Find next breakpoint. 561 *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), 562 fname, SOURCING_LNUM); 563 *dbg_tick = debug_tick; 564 } 565 if (do_profiling == PROF_YES) { 566 if (getline_is_func) { 567 func_line_start(real_cookie); 568 } else if (getline_equal(fgetline, cookie, getsourceline)) { 569 script_line_start(); 570 } 571 } 572 } 573 574 // 2. If no line given, get an allocated line with fgetline(). 575 if (next_cmdline == NULL) { 576 int indent = cstack.cs_idx < 0 ? 0 : (cstack.cs_idx + 1) * 2; 577 578 if (count == 1 && getline_equal(fgetline, cookie, getexline)) { 579 if (ui_has(kUICmdline)) { 580 // Emit cmdline_block event for loop/conditional block. 581 ui_ext_cmdline_block_append(0, last_cmdline); 582 did_block = true; 583 } 584 // Need to set msg_didout for the first line after an ":if", 585 // otherwise the ":if" will be overwritten. 586 msg_didout = true; 587 } 588 589 if (fgetline == NULL || (next_cmdline = fgetline(':', cookie, indent, true)) == NULL) { 590 // Don't call wait_return() for aborted command line. The NULL 591 // returned for the end of a sourced file or executed function 592 // doesn't do this. 593 if (KeyTyped && !(flags & DOCMD_REPEAT)) { 594 need_wait_return = false; 595 } 596 retval = FAIL; 597 break; 598 } 599 used_getline = true; 600 601 // Emit all but the first cmdline_block event immediately; waiting until after 602 // command execution would mess up event ordering with nested command lines. 603 if (ui_has(kUICmdline) && count > 0 && getline_equal(fgetline, cookie, getexline)) { 604 ui_ext_cmdline_block_append((size_t)indent, next_cmdline); 605 } 606 607 // Keep the first typed line. Clear it when more lines are typed. 608 if (flags & DOCMD_KEEPLINE) { 609 xfree(repeat_cmdline); 610 if (count == 0) { 611 repeat_cmdline = xstrdup(next_cmdline); 612 } else { 613 repeat_cmdline = NULL; 614 } 615 } 616 } else if (cmdline_copy == NULL) { 617 // 3. Make a copy of the command so we can mess with it. 618 next_cmdline = xstrdup(next_cmdline); 619 } 620 cmdline_copy = next_cmdline; 621 622 int current_line_before = 0; 623 // Inside a while/for loop, and when the command looks like a ":while" 624 // or ":for", the line is stored, because we may need it later when 625 // looping. 626 // 627 // When there is a '|' and another command, it is stored separately, 628 // because we need to be able to jump back to it from an 629 // :endwhile/:endfor. 630 // 631 // Pass a different "fgetline" function to do_one_cmd() below, 632 // that it stores lines in or reads them from "lines_ga". Makes it 633 // possible to define a function inside a while/for loop. 634 if ((cstack.cs_looplevel > 0 || has_loop_cmd(next_cmdline))) { 635 cmd_getline = get_loop_line; 636 cmd_cookie = (void *)&cmd_loop_cookie; 637 cmd_loop_cookie.lines_gap = &lines_ga; 638 cmd_loop_cookie.current_line = current_line; 639 cmd_loop_cookie.lc_getline = fgetline; 640 cmd_loop_cookie.cookie = cookie; 641 cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); 642 643 // Save the current line when encountering it the first time. 644 if (current_line == lines_ga.ga_len) { 645 store_loop_line(&lines_ga, next_cmdline); 646 } 647 current_line_before = current_line; 648 } else { 649 cmd_getline = fgetline; 650 cmd_cookie = cookie; 651 } 652 653 did_endif = false; 654 655 if (count++ == 0) { 656 // All output from the commands is put below each other, without 657 // waiting for a return. Don't do this when executing commands 658 // from a script or when being called recursive (e.g. for ":e 659 // +command file"). 660 if (!(flags & DOCMD_NOWAIT) && !recursive) { 661 msg_didout_before_start = msg_didout; 662 msg_didany = false; // no output yet 663 msg_start(); 664 msg_scroll = true; // put messages below each other 665 no_wait_return++; // don't wait for return until finished 666 RedrawingDisabled++; 667 did_inc = true; 668 } 669 } 670 671 if ((p_verbose >= 15 && SOURCING_NAME != NULL) || p_verbose >= 16) { 672 msg_verbose_cmd(SOURCING_LNUM, cmdline_copy); 673 } 674 675 // 2. Execute one '|' separated command. 676 // do_one_cmd() will return NULL if there is no trailing '|'. 677 // "cmdline_copy" can change, e.g. for '%' and '#' expansion. 678 recursive++; 679 next_cmdline = do_one_cmd(&cmdline_copy, flags, &cstack, cmd_getline, cmd_cookie); 680 recursive--; 681 682 if (cmd_cookie == (void *)&cmd_loop_cookie) { 683 // Use "current_line" from "cmd_loop_cookie", it may have been 684 // incremented when defining a function. 685 current_line = cmd_loop_cookie.current_line; 686 } 687 688 if (next_cmdline == NULL) { 689 XFREE_CLEAR(cmdline_copy); 690 691 // If the command was typed, remember it for the ':' register. 692 // Do this AFTER executing the command to make :@: work. 693 if (getline_equal(fgetline, cookie, getexline) && new_last_cmdline != NULL) { 694 xfree(last_cmdline); 695 last_cmdline = new_last_cmdline; 696 new_last_cmdline = NULL; 697 } 698 } else { 699 // need to copy the command after the '|' to cmdline_copy, for the 700 // next do_one_cmd() 701 STRMOVE(cmdline_copy, next_cmdline); 702 next_cmdline = cmdline_copy; 703 } 704 705 // reset did_emsg for a function that is not aborted by an error 706 if (did_emsg && !force_abort 707 && getline_equal(fgetline, cookie, get_func_line) 708 && !func_has_abort(real_cookie)) { 709 did_emsg = false; 710 } 711 712 if (cstack.cs_looplevel > 0) { 713 current_line++; 714 715 // An ":endwhile", ":endfor" and ":continue" is handled here. 716 // If we were executing commands, jump back to the ":while" or 717 // ":for". 718 // If we were not executing commands, decrement cs_looplevel. 719 if (cstack.cs_lflags & (CSL_HAD_CONT | CSL_HAD_ENDLOOP)) { 720 cstack.cs_lflags &= ~(CSL_HAD_CONT | CSL_HAD_ENDLOOP); 721 722 // Jump back to the matching ":while" or ":for". Be careful 723 // not to use a cs_line[] from an entry that isn't a ":while" 724 // or ":for": It would make "current_line" invalid and can 725 // cause a crash. 726 if (!did_emsg && !got_int && !did_throw 727 && cstack.cs_idx >= 0 728 && (cstack.cs_flags[cstack.cs_idx] 729 & (CSF_WHILE | CSF_FOR)) 730 && cstack.cs_line[cstack.cs_idx] >= 0 731 && (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE)) { 732 current_line = cstack.cs_line[cstack.cs_idx]; 733 // remember we jumped there 734 cstack.cs_lflags |= CSL_HAD_LOOP; 735 line_breakcheck(); // check if CTRL-C typed 736 737 // Check for the next breakpoint at or after the ":while" 738 // or ":for". 739 if (breakpoint != NULL && lines_ga.ga_len > current_line) { 740 *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), fname, 741 ((wcmd_T *)lines_ga.ga_data)[current_line].lnum - 1); 742 *dbg_tick = debug_tick; 743 } 744 } else { 745 // can only get here with ":endwhile" or ":endfor" 746 if (cstack.cs_idx >= 0) { 747 rewind_conditionals(&cstack, cstack.cs_idx - 1, 748 CSF_WHILE | CSF_FOR, &cstack.cs_looplevel); 749 } 750 } 751 } else if (cstack.cs_lflags & CSL_HAD_LOOP) { 752 // For a ":while" or ":for" we need to remember the line number. 753 cstack.cs_lflags &= ~CSL_HAD_LOOP; 754 cstack.cs_line[cstack.cs_idx] = current_line_before; 755 } 756 } 757 758 // When not inside any ":while" loop, clear remembered lines. 759 if (cstack.cs_looplevel == 0) { 760 if (!GA_EMPTY(&lines_ga)) { 761 SOURCING_LNUM = ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; 762 GA_DEEP_CLEAR(&lines_ga, wcmd_T, FREE_WCMD); 763 } 764 current_line = 0; 765 } 766 767 // A ":finally" makes did_emsg, got_int and did_throw pending for 768 // being restored at the ":endtry". Reset them here and set the 769 // ACTIVE and FINALLY flags, so that the finally clause gets executed. 770 // This includes the case where a missing ":endif", ":endwhile" or 771 // ":endfor" was detected by the ":finally" itself. 772 if (cstack.cs_lflags & CSL_HAD_FINA) { 773 cstack.cs_lflags &= ~CSL_HAD_FINA; 774 report_make_pending((cstack.cs_pending[cstack.cs_idx] 775 & (CSTP_ERROR | CSTP_INTERRUPT | CSTP_THROW)), 776 did_throw ? current_exception : NULL); 777 did_emsg = got_int = did_throw = false; 778 cstack.cs_flags[cstack.cs_idx] |= CSF_ACTIVE | CSF_FINALLY; 779 } 780 781 // Update global "trylevel" for recursive calls to do_cmdline() from 782 // within this loop. 783 trylevel = initial_trylevel + cstack.cs_trylevel; 784 785 // If the outermost try conditional (across function calls and sourced 786 // files) is aborted because of an error, an interrupt, or an uncaught 787 // exception, cancel everything. If it is left normally, reset 788 // force_abort to get the non-EH compatible abortion behavior for 789 // the rest of the script. 790 if (trylevel == 0 && !did_emsg && !got_int && !did_throw) { 791 force_abort = false; 792 } 793 794 // Convert an interrupt to an exception if appropriate. 795 do_intthrow(&cstack); 796 797 // Continue executing command lines when: 798 // - no CTRL-C typed, no aborting error, no exception thrown or try 799 // conditionals need to be checked for executing finally clauses or 800 // catching an interrupt exception 801 // - didn't get an error message or lines are not typed 802 // - there is a command after '|', inside a :if, :while, :for or :try, or 803 // looping for ":source" command or function call. 804 } while (!((got_int || (did_emsg && force_abort) || did_throw) 805 && cstack.cs_trylevel == 0) 806 && !(did_emsg 807 // Keep going when inside try/catch, so that the error can be 808 // deal with, except when it is a syntax error, it may cause 809 // the :endtry to be missed. 810 && (cstack.cs_trylevel == 0 || did_emsg_syntax) 811 && used_getline 812 && getline_equal(fgetline, cookie, getexline)) 813 && (next_cmdline != NULL 814 || cstack.cs_idx >= 0 815 || (flags & DOCMD_REPEAT))); 816 817 xfree(cmdline_copy); 818 did_emsg_syntax = false; 819 GA_DEEP_CLEAR(&lines_ga, wcmd_T, FREE_WCMD); 820 821 if (cstack.cs_idx >= 0) { 822 // If a sourced file or executed function ran to its end, report the 823 // unclosed conditional. 824 if (!got_int && !did_throw && !aborting() 825 && ((getline_equal(fgetline, cookie, getsourceline) 826 && !source_finished(fgetline, cookie)) 827 || (getline_equal(fgetline, cookie, get_func_line) 828 && !func_has_ended(real_cookie)))) { 829 if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY) { 830 emsg(_(e_endtry)); 831 } else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE) { 832 emsg(_(e_endwhile)); 833 } else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR) { 834 emsg(_(e_endfor)); 835 } else { 836 emsg(_(e_endif)); 837 } 838 } 839 840 // Reset "trylevel" in case of a ":finish" or ":return" or a missing 841 // ":endtry" in a sourced file or executed function. If the try 842 // conditional is in its finally clause, ignore anything pending. 843 // If it is in a catch clause, finish the caught exception. 844 // Also cleanup any "cs_forinfo" structures. 845 do { 846 int idx = cleanup_conditionals(&cstack, 0, true); 847 848 if (idx >= 0) { 849 idx--; // remove try block not in its finally clause 850 } 851 rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR, 852 &cstack.cs_looplevel); 853 } while (cstack.cs_idx >= 0); 854 trylevel = initial_trylevel; 855 } 856 857 // If a missing ":endtry", ":endwhile", ":endfor", or ":endif" or a memory 858 // lack was reported above and the error message is to be converted to an 859 // exception, do this now after rewinding the cstack. 860 do_errthrow(&cstack, getline_equal(fgetline, cookie, get_func_line) ? "endfunction" : NULL); 861 862 if (trylevel == 0) { 863 // When an exception is being thrown out of the outermost try 864 // conditional, discard the uncaught exception, disable the conversion 865 // of interrupts or errors to exceptions, and ensure that no more 866 // commands are executed. 867 if (did_throw) { 868 handle_did_throw(); 869 } else if (got_int || (did_emsg && force_abort)) { 870 // On an interrupt or an aborting error not converted to an exception, 871 // disable the conversion of errors to exceptions. (Interrupts are not 872 // converted any more, here.) This enables also the interrupt message 873 // when force_abort is set and did_emsg unset in case of an interrupt 874 // from a finally clause after an error. 875 suppress_errthrow = true; 876 } 877 } 878 879 // The current cstack will be freed when do_cmdline() returns. An uncaught 880 // exception will have to be rethrown in the previous cstack. If a function 881 // has just returned or a script file was just finished and the previous 882 // cstack belongs to the same function or, respectively, script file, it 883 // will have to be checked for finally clauses to be executed due to the 884 // ":return" or ":finish". This is done in do_one_cmd(). 885 if (did_throw) { 886 need_rethrow = true; 887 } 888 if ((getline_equal(fgetline, cookie, getsourceline) 889 && ex_nesting_level > source_level(real_cookie)) 890 || (getline_equal(fgetline, cookie, get_func_line) 891 && ex_nesting_level > func_level(real_cookie) + 1)) { 892 if (!did_throw) { 893 check_cstack = true; 894 } 895 } else { 896 // When leaving a function, reduce nesting level. 897 if (getline_equal(fgetline, cookie, get_func_line)) { 898 ex_nesting_level--; 899 } 900 // Go to debug mode when returning from a function in which we are 901 // single-stepping. 902 if ((getline_equal(fgetline, cookie, getsourceline) 903 || getline_equal(fgetline, cookie, get_func_line)) 904 && ex_nesting_level + 1 <= debug_break_level) { 905 do_debug(getline_equal(fgetline, cookie, getsourceline) 906 ? _("End of sourced file") 907 : _("End of function")); 908 } 909 } 910 911 // Restore the exception environment (done after returning from the 912 // debugger). 913 if (flags & DOCMD_EXCRESET) { 914 restore_dbg_stuff(&debug_saved); 915 } 916 917 msg_list = saved_msg_list; 918 919 // Cleanup if "cs_emsg_silent_list" remains. 920 if (cstack.cs_emsg_silent_list != NULL) { 921 eslist_T *temp; 922 for (eslist_T *elem = cstack.cs_emsg_silent_list; elem != NULL; elem = temp) { 923 temp = elem->next; 924 xfree(elem); 925 } 926 } 927 928 // If there was too much output to fit on the command line, ask the user to 929 // hit return before redrawing the screen. With the ":global" command we do 930 // this only once after the command is finished. 931 if (did_inc) { 932 RedrawingDisabled--; 933 no_wait_return--; 934 msg_scroll = false; 935 936 // When just finished an ":if"-":else" which was typed, no need to 937 // wait for hit-return. Also for an error situation. 938 if (retval == FAIL 939 || (did_endif && KeyTyped && !did_emsg)) { 940 need_wait_return = false; 941 msg_didany = false; // don't wait when restarting edit 942 } else if (need_wait_return) { 943 // The msg_start() above clears msg_didout. The wait_return() we do 944 // here should not overwrite the command that may be shown before 945 // doing that. 946 msg_didout |= msg_didout_before_start; 947 wait_return(false); 948 } 949 } 950 951 if (did_block) { 952 ui_ext_cmdline_block_leave(); 953 } 954 955 did_endif = false; // in case do_cmdline used recursively 956 957 do_cmdline_end(); 958 return retval; 959 } 960 961 /// Handle when "did_throw" is set after executing commands. 962 void handle_did_throw(void) 963 { 964 assert(current_exception != NULL); 965 char *p = NULL; 966 msglist_T *messages = NULL; 967 ESTACK_CHECK_DECLARATION; 968 969 // If the uncaught exception is a user exception, report it as an 970 // error. If it is an error exception, display the saved error 971 // message now. For an interrupt exception, do nothing; the 972 // interrupt message is given elsewhere. 973 switch (current_exception->type) { 974 case ET_USER: 975 vim_snprintf(IObuff, IOSIZE, 976 _("E605: Exception not caught: %s"), 977 current_exception->value); 978 p = xstrdup(IObuff); 979 break; 980 case ET_ERROR: 981 messages = current_exception->messages; 982 current_exception->messages = NULL; 983 break; 984 case ET_INTERRUPT: 985 break; 986 } 987 988 estack_push(ETYPE_EXCEPT, current_exception->throw_name, current_exception->throw_lnum); 989 ESTACK_CHECK_SETUP; 990 current_exception->throw_name = NULL; 991 992 discard_current_exception(); // uses IObuff if 'verbose' 993 994 // If "silent!" is active the uncaught exception is not fatal. 995 if (emsg_silent == 0) { 996 suppress_errthrow = true; 997 force_abort = true; 998 } 999 1000 if (messages != NULL) { 1001 do { 1002 msglist_T *next = messages->next; 1003 emsg_multiline(messages->msg, "emsg", HLF_E, messages->multiline); 1004 xfree(messages->msg); 1005 xfree(messages->sfile); 1006 xfree(messages); 1007 messages = next; 1008 } while (messages != NULL); 1009 } else if (p != NULL) { 1010 emsg(p); 1011 xfree(p); 1012 } 1013 xfree(SOURCING_NAME); 1014 ESTACK_CHECK_NOW; 1015 estack_pop(); 1016 } 1017 1018 /// Obtain a line when inside a ":while" or ":for" loop. 1019 static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) 1020 { 1021 struct loop_cookie *cp = (struct loop_cookie *)cookie; 1022 1023 if (cp->current_line + 1 >= cp->lines_gap->ga_len) { 1024 if (cp->repeating) { 1025 return NULL; // trying to read past ":endwhile"/":endfor" 1026 } 1027 char *line; 1028 // First time inside the ":while"/":for": get line normally. 1029 if (cp->lc_getline == NULL) { 1030 line = getcmdline(c, 0, indent, do_concat); 1031 } else { 1032 line = cp->lc_getline(c, cp->cookie, indent, do_concat); 1033 } 1034 if (line != NULL) { 1035 store_loop_line(cp->lines_gap, line); 1036 cp->current_line++; 1037 } 1038 1039 return line; 1040 } 1041 1042 KeyTyped = false; 1043 cp->current_line++; 1044 wcmd_T *wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line; 1045 SOURCING_LNUM = wp->lnum; 1046 return xstrdup(wp->line); 1047 } 1048 1049 /// Store a line in "gap" so that a ":while" loop can execute it again. 1050 static void store_loop_line(garray_T *gap, char *line) 1051 { 1052 wcmd_T *p = GA_APPEND_VIA_PTR(wcmd_T, gap); 1053 p->line = xstrdup(line); 1054 p->lnum = SOURCING_LNUM; 1055 } 1056 1057 /// If "fgetline" is get_loop_line(), return true if the getline it uses equals 1058 /// "func". * Otherwise return true when "fgetline" equals "func". 1059 /// 1060 /// @param cookie argument for fgetline() 1061 bool getline_equal(LineGetter fgetline, void *cookie, LineGetter func) 1062 { 1063 // When "fgetline" is "get_loop_line()" use the "cookie" to find the 1064 // function that's originally used to obtain the lines. This may be 1065 // nested several levels. 1066 LineGetter gp = fgetline; 1067 struct loop_cookie *cp = (struct loop_cookie *)cookie; 1068 while (gp == get_loop_line) { 1069 gp = cp->lc_getline; 1070 cp = cp->cookie; 1071 } 1072 return gp == func; 1073 } 1074 1075 /// If "fgetline" is get_loop_line(), return the cookie used by the original 1076 /// getline function. Otherwise return "cookie". 1077 /// 1078 /// @param cookie argument for fgetline() 1079 void *getline_cookie(LineGetter fgetline, void *cookie) 1080 { 1081 // When "fgetline" is "get_loop_line()" use the "cookie" to find the 1082 // cookie that's originally used to obtain the lines. This may be nested 1083 // several levels. 1084 LineGetter gp = fgetline; 1085 struct loop_cookie *cp = (struct loop_cookie *)cookie; 1086 while (gp == get_loop_line) { 1087 gp = cp->lc_getline; 1088 cp = cp->cookie; 1089 } 1090 return cp; 1091 } 1092 1093 /// Helper function to apply an offset for buffer commands, i.e. ":bdelete", 1094 /// ":bwipeout", etc. 1095 /// 1096 /// @return the buffer number. 1097 static int compute_buffer_local_count(cmd_addr_T addr_type, linenr_T lnum, int offset) 1098 { 1099 int count = offset; 1100 1101 buf_T *buf = firstbuf; 1102 while (buf->b_next != NULL && buf->b_fnum < lnum) { 1103 buf = buf->b_next; 1104 } 1105 while (count != 0) { 1106 count += (count < 0) ? 1 : -1; 1107 buf_T *nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; 1108 if (nextbuf == NULL) { 1109 break; 1110 } 1111 buf = nextbuf; 1112 if (addr_type == ADDR_LOADED_BUFFERS) { 1113 // skip over unloaded buffers 1114 while (buf->b_ml.ml_mfp == NULL) { 1115 nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; 1116 if (nextbuf == NULL) { 1117 break; 1118 } 1119 buf = nextbuf; 1120 } 1121 } 1122 } 1123 // we might have gone too far, last buffer is not loaded 1124 if (addr_type == ADDR_LOADED_BUFFERS) { 1125 while (buf->b_ml.ml_mfp == NULL) { 1126 buf_T *nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next; 1127 if (nextbuf == NULL) { 1128 break; 1129 } 1130 buf = nextbuf; 1131 } 1132 } 1133 return buf->b_fnum; 1134 } 1135 1136 /// @return the window number of "win" or, 1137 /// the number of windows if "win" is NULL 1138 static int current_win_nr(const win_T *win) 1139 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 1140 { 1141 int nr = 0; 1142 1143 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 1144 nr++; 1145 if (wp == win) { 1146 break; 1147 } 1148 } 1149 return nr; 1150 } 1151 1152 static int current_tab_nr(tabpage_T *tab) 1153 { 1154 int nr = 0; 1155 1156 FOR_ALL_TABS(tp) { 1157 nr++; 1158 if (tp == tab) { 1159 break; 1160 } 1161 } 1162 return nr; 1163 } 1164 1165 #define CURRENT_WIN_NR current_win_nr(curwin) 1166 #define LAST_WIN_NR current_win_nr(NULL) 1167 #define CURRENT_TAB_NR current_tab_nr(curtab) 1168 #define LAST_TAB_NR current_tab_nr(NULL) 1169 1170 /// Figure out the address type for ":wincmd". 1171 static void get_wincmd_addr_type(const char *arg, exarg_T *eap) 1172 { 1173 switch (*arg) { 1174 case 'S': 1175 case Ctrl_S: 1176 case 's': 1177 case Ctrl_N: 1178 case 'n': 1179 case 'j': 1180 case Ctrl_J: 1181 case 'k': 1182 case Ctrl_K: 1183 case 'T': 1184 case Ctrl_R: 1185 case 'r': 1186 case 'R': 1187 case 'K': 1188 case 'J': 1189 case '+': 1190 case '-': 1191 case Ctrl__: 1192 case '_': 1193 case '|': 1194 case ']': 1195 case Ctrl_RSB: 1196 case 'g': 1197 case Ctrl_G: 1198 case Ctrl_V: 1199 case 'v': 1200 case 'h': 1201 case Ctrl_H: 1202 case 'l': 1203 case Ctrl_L: 1204 case 'H': 1205 case 'L': 1206 case '>': 1207 case '<': 1208 case '}': 1209 case 'f': 1210 case 'F': 1211 case Ctrl_F: 1212 case 'i': 1213 case Ctrl_I: 1214 case 'd': 1215 case Ctrl_D: 1216 // window size or any count 1217 eap->addr_type = ADDR_OTHER; 1218 break; 1219 1220 case Ctrl_HAT: 1221 case '^': 1222 // buffer number 1223 eap->addr_type = ADDR_BUFFERS; 1224 break; 1225 1226 case Ctrl_Q: 1227 case 'q': 1228 case Ctrl_C: 1229 case 'c': 1230 case Ctrl_O: 1231 case 'o': 1232 case Ctrl_W: 1233 case 'w': 1234 case 'W': 1235 case 'x': 1236 case Ctrl_X: 1237 // window number 1238 eap->addr_type = ADDR_WINDOWS; 1239 break; 1240 1241 case Ctrl_Z: 1242 case 'z': 1243 case 'P': 1244 case 't': 1245 case Ctrl_T: 1246 case 'b': 1247 case Ctrl_B: 1248 case 'p': 1249 case Ctrl_P: 1250 case '=': 1251 case CAR: 1252 // no count 1253 eap->addr_type = ADDR_NONE; 1254 break; 1255 } 1256 } 1257 1258 /// Skip colons and trailing whitespace, returning a pointer to the first 1259 /// non-colon, non-whitespace character. 1260 // 1261 /// @param skipleadingwhite Skip leading whitespace too 1262 static char *skip_colon_white(const char *p, bool skipleadingwhite) 1263 { 1264 if (skipleadingwhite) { 1265 p = skipwhite(p); 1266 } 1267 1268 while (*p == ':') { 1269 p = skipwhite(p + 1); 1270 } 1271 1272 return (char *)p; 1273 } 1274 1275 /// Set the addr type for command 1276 /// 1277 /// @param p pointer to character after command name in cmdline 1278 void set_cmd_addr_type(exarg_T *eap, char *p) 1279 { 1280 // ea.addr_type for user commands is set by find_ucmd 1281 if (IS_USER_CMDIDX(eap->cmdidx)) { 1282 return; 1283 } 1284 if (eap->cmdidx != CMD_SIZE) { 1285 eap->addr_type = cmdnames[(int)eap->cmdidx].cmd_addr_type; 1286 } else { 1287 eap->addr_type = ADDR_LINES; 1288 } 1289 // :wincmd range depends on the argument 1290 if (eap->cmdidx == CMD_wincmd && p != NULL) { 1291 get_wincmd_addr_type(skipwhite(p), eap); 1292 } 1293 // :.cc in quickfix window uses line number 1294 if ((eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) && bt_quickfix(curbuf)) { 1295 eap->addr_type = ADDR_OTHER; 1296 } 1297 } 1298 1299 /// Get default range number for command based on its address type 1300 linenr_T get_cmd_default_range(exarg_T *eap) 1301 { 1302 switch (eap->addr_type) { 1303 case ADDR_LINES: 1304 case ADDR_OTHER: 1305 // Default is the cursor line number. Avoid using an invalid 1306 // line number though. 1307 return MIN(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count); 1308 break; 1309 case ADDR_WINDOWS: 1310 return CURRENT_WIN_NR; 1311 break; 1312 case ADDR_ARGUMENTS: 1313 return MIN(curwin->w_arg_idx + 1, ARGCOUNT); 1314 break; 1315 case ADDR_LOADED_BUFFERS: 1316 case ADDR_BUFFERS: 1317 return curbuf->b_fnum; 1318 break; 1319 case ADDR_TABS: 1320 return CURRENT_TAB_NR; 1321 break; 1322 case ADDR_TABS_RELATIVE: 1323 case ADDR_UNSIGNED: 1324 return 1; 1325 break; 1326 case ADDR_QUICKFIX: 1327 return (linenr_T)qf_get_cur_idx(eap); 1328 break; 1329 case ADDR_QUICKFIX_VALID: 1330 return qf_get_cur_valid_idx(eap); 1331 break; 1332 default: 1333 return 0; 1334 // Will give an error later if a range is found. 1335 break; 1336 } 1337 } 1338 1339 /// Set default command range for -range=% based on the addr type of the command 1340 void set_cmd_dflall_range(exarg_T *eap) 1341 { 1342 buf_T *buf; 1343 1344 eap->line1 = 1; 1345 switch (eap->addr_type) { 1346 case ADDR_LINES: 1347 case ADDR_OTHER: 1348 eap->line2 = curbuf->b_ml.ml_line_count; 1349 break; 1350 case ADDR_LOADED_BUFFERS: 1351 buf = firstbuf; 1352 while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) { 1353 buf = buf->b_next; 1354 } 1355 eap->line1 = buf->b_fnum; 1356 buf = lastbuf; 1357 while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { 1358 buf = buf->b_prev; 1359 } 1360 eap->line2 = buf->b_fnum; 1361 break; 1362 case ADDR_BUFFERS: 1363 eap->line1 = firstbuf->b_fnum; 1364 eap->line2 = lastbuf->b_fnum; 1365 break; 1366 case ADDR_WINDOWS: 1367 eap->line2 = LAST_WIN_NR; 1368 break; 1369 case ADDR_TABS: 1370 eap->line2 = LAST_TAB_NR; 1371 break; 1372 case ADDR_TABS_RELATIVE: 1373 eap->line2 = 1; 1374 break; 1375 case ADDR_ARGUMENTS: 1376 if (ARGCOUNT == 0) { 1377 eap->line1 = eap->line2 = 0; 1378 } else { 1379 eap->line2 = ARGCOUNT; 1380 } 1381 break; 1382 case ADDR_QUICKFIX_VALID: 1383 eap->line2 = (linenr_T)qf_get_valid_size(eap); 1384 if (eap->line2 == 0) { 1385 eap->line2 = 1; 1386 } 1387 break; 1388 case ADDR_NONE: 1389 case ADDR_UNSIGNED: 1390 case ADDR_QUICKFIX: 1391 iemsg(_("INTERNAL: Cannot use EX_DFLALL " 1392 "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX")); 1393 break; 1394 } 1395 } 1396 1397 static void parse_register(exarg_T *eap) 1398 { 1399 // Accept numbered register only when no count allowed (:put) 1400 if ((eap->argt & EX_REGSTR) 1401 && *eap->arg != NUL 1402 // Do not allow register = for user commands 1403 && (!IS_USER_CMDIDX(eap->cmdidx) || *eap->arg != '=') 1404 && !((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg))) { 1405 if (valid_yank_reg(*eap->arg, 1406 (!IS_USER_CMDIDX(eap->cmdidx) 1407 && eap->cmdidx != CMD_put && eap->cmdidx != CMD_iput))) { 1408 eap->regname = (uint8_t)(*eap->arg++); 1409 // for '=' register: accept the rest of the line as an expression 1410 if (eap->arg[-1] == '=' && eap->arg[0] != NUL) { 1411 if (!eap->skip) { 1412 set_expr_line(xstrdup(eap->arg)); 1413 } 1414 eap->arg += strlen(eap->arg); 1415 } 1416 eap->arg = skipwhite(eap->arg); 1417 } 1418 } 1419 } 1420 1421 // Change line1 and line2 of Ex command to use count 1422 void set_cmd_count(exarg_T *eap, linenr_T count, bool validate) 1423 { 1424 if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 1425 eap->line2 = count; 1426 if (eap->addr_count == 0) { 1427 eap->addr_count = 1; 1428 } 1429 } else { 1430 eap->line1 = eap->line2; 1431 if (eap->line2 >= INT32_MAX - (count - 1)) { 1432 eap->line2 = INT32_MAX; 1433 } else { 1434 eap->line2 += count - 1; 1435 } 1436 eap->addr_count++; 1437 // Be vi compatible: no error message for out of range. 1438 if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { 1439 eap->line2 = curbuf->b_ml.ml_line_count; 1440 } 1441 } 1442 } 1443 1444 static int parse_count(exarg_T *eap, const char **errormsg, bool validate) 1445 { 1446 // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a 1447 // count, it's a buffer name. 1448 char *p; 1449 1450 if ((eap->argt & EX_COUNT) && ascii_isdigit(*eap->arg) 1451 && (!(eap->argt & EX_BUFNAME) || *(p = skipdigits(eap->arg + 1)) == NUL 1452 || ascii_iswhite(*p))) { 1453 linenr_T n = getdigits_int32(&eap->arg, false, INT32_MAX); 1454 eap->arg = skipwhite(eap->arg); 1455 1456 if (eap->args != NULL) { 1457 assert(eap->argc > 0 && eap->arg >= eap->args[0]); 1458 // If eap->arg is still pointing to the first argument, just make eap->args[0] point to the 1459 // same location. This is needed for usecases like vim.cmd.sleep('10m'). If eap->arg is 1460 // pointing outside the first argument, shift arguments by 1. 1461 if (eap->arg < eap->args[0] + eap->arglens[0]) { 1462 eap->arglens[0] -= (size_t)(eap->arg - eap->args[0]); 1463 eap->args[0] = eap->arg; 1464 } else { 1465 shift_cmd_args(eap); 1466 } 1467 } 1468 1469 if (n <= 0 && (eap->argt & EX_ZEROR) == 0) { 1470 if (errormsg != NULL) { 1471 *errormsg = _(e_zerocount); 1472 } 1473 return FAIL; 1474 } 1475 set_cmd_count(eap, n, validate); 1476 } 1477 1478 return OK; 1479 } 1480 1481 /// Check if command is not implemented 1482 bool is_cmd_ni(cmdidx_T cmdidx) 1483 { 1484 return !IS_USER_CMDIDX(cmdidx) && (cmdnames[cmdidx].cmd_func == ex_ni 1485 || cmdnames[cmdidx].cmd_func == ex_script_ni); 1486 } 1487 1488 // Find the command name after skipping range specifiers. 1489 static char *find_excmd_after_range(exarg_T *eap) 1490 { 1491 // Save location after command modifiers. 1492 char *cmd = eap->cmd; 1493 eap->cmd = skip_range(eap->cmd, NULL); 1494 char *p = find_ex_command(eap, NULL); 1495 eap->cmd = cmd; // Restore original position for address parsing 1496 return p; 1497 } 1498 1499 // Set the forceit flag based on the presence of '!' after the command. 1500 static bool parse_bang(const exarg_T *eap, char **p) 1501 { 1502 if (**p == '!' 1503 && eap->cmdidx != CMD_substitute 1504 && eap->cmdidx != CMD_smagic 1505 && eap->cmdidx != CMD_snomagic) { 1506 (*p)++; 1507 return true; 1508 } 1509 return false; 1510 } 1511 1512 /// Check if command expects expression arguments that need special parsing 1513 bool cmd_has_expr_args(cmdidx_T cmdidx) 1514 { 1515 return cmdidx == CMD_execute 1516 || cmdidx == CMD_echo 1517 || cmdidx == CMD_echon 1518 || cmdidx == CMD_echomsg 1519 || cmdidx == CMD_echoerr; 1520 } 1521 1522 /// Parse command line and return information about the first command. 1523 /// If parsing is done successfully, need to free cmod_filter_pat and cmod_filter_regmatch.regprog 1524 /// after calling, usually done using undo_cmdmod() or execute_cmd(). 1525 /// 1526 /// @param cmdline Command line string 1527 /// @param[out] eap Ex command arguments 1528 /// @param[out] cmdinfo Command parse information 1529 /// @param[out] errormsg Error message, if any 1530 /// 1531 /// @return Success or failure 1532 bool parse_cmdline(char **cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const char **errormsg) 1533 { 1534 char *after_modifier = NULL; 1535 bool retval = false; 1536 // parsing the command modifiers may set ex_pressedreturn 1537 const bool save_ex_pressedreturn = ex_pressedreturn; 1538 // parsing the command range may require moving the cursor 1539 const pos_T save_cursor = curwin->w_cursor; 1540 // parsing the command range may set the last search pattern 1541 save_last_search_pattern(); 1542 1543 // Initialize cmdinfo 1544 CLEAR_POINTER(cmdinfo); 1545 1546 // Initialize eap 1547 *eap = (exarg_T){ 1548 .line1 = 1, 1549 .line2 = 1, 1550 .cmd = *cmdline, 1551 .cmdlinep = cmdline, 1552 .ea_getline = NULL, 1553 .cookie = NULL, 1554 }; 1555 1556 // Parse command modifiers 1557 if (parse_command_modifiers(eap, errormsg, &cmdinfo->cmdmod, false) == FAIL) { 1558 goto end; 1559 } 1560 after_modifier = eap->cmd; 1561 1562 // We need the command name to know what kind of range it uses. 1563 char *p = find_excmd_after_range(eap); 1564 if (p == NULL) { 1565 *errormsg = _(e_ambiguous_use_of_user_defined_command); 1566 goto end; 1567 } 1568 1569 // Set command address type and parse command range 1570 set_cmd_addr_type(eap, p); 1571 if (parse_cmd_address(eap, errormsg, true) == FAIL) { 1572 goto end; 1573 } 1574 1575 // Skip colon and whitespace 1576 eap->cmd = skip_colon_white(eap->cmd, true); 1577 // Fail if command is a comment or if command doesn't exist 1578 if (*eap->cmd == NUL || *eap->cmd == '"') { 1579 goto end; 1580 } 1581 // Fail if command is invalid 1582 if (eap->cmdidx == CMD_SIZE) { 1583 xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE); 1584 // If the modifier was parsed OK the error must be in the following command 1585 char *cmdname = after_modifier ? after_modifier : *cmdline; 1586 append_command(cmdname); 1587 *errormsg = IObuff; 1588 goto end; 1589 } 1590 1591 // Correctly set 'forceit' for commands 1592 eap->forceit = parse_bang(eap, &p); 1593 1594 // Parse arguments. 1595 if (!IS_USER_CMDIDX(eap->cmdidx)) { 1596 eap->argt = cmdnames[(int)eap->cmdidx].cmd_argt; 1597 } 1598 // Skip to start of argument. 1599 // Don't do this for the ":!" command, because ":!! -l" needs the space. 1600 eap->arg = eap->cmdidx == CMD_bang ? p : skipwhite(p); 1601 1602 // Don't treat ":r! filter" like a bang 1603 if (eap->cmdidx == CMD_read && eap->forceit) { 1604 eap->forceit = false; // :r! filter 1605 } 1606 1607 // Check for '|' to separate commands and '"' to start comments. 1608 // Don't do this for ":read !cmd" and ":write !cmd". 1609 if ((eap->argt & EX_TRLBAR)) { 1610 separate_nextcmd(eap); 1611 } else if (cmd_has_expr_args(eap->cmdidx)) { 1612 // For commands without EX_TRLBAR, check for '|' separator 1613 // by skipping over expressions (including string literals) 1614 char *arg = eap->arg; 1615 while (*arg != NUL && *arg != '|' && *arg != '\n') { 1616 char *start = arg; 1617 skip_expr(&arg, NULL); 1618 // If skip_expr didn't advance, move forward to avoid infinite loop 1619 if (arg == start) { 1620 arg++; 1621 } 1622 } 1623 if (*arg == '|' || *arg == '\n') { 1624 eap->nextcmd = check_nextcmd(arg); 1625 *arg = NUL; 1626 } 1627 } 1628 // Fail if command doesn't support bang but is used with a bang 1629 if (!(eap->argt & EX_BANG) && eap->forceit) { 1630 *errormsg = _(e_nobang); 1631 goto end; 1632 } 1633 // Fail if command doesn't support a range but it is given a range 1634 if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) { 1635 *errormsg = _(e_norange); 1636 goto end; 1637 } 1638 // Set default range for command if required 1639 if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) { 1640 set_cmd_dflall_range(eap); 1641 } 1642 1643 // Parse register and count 1644 parse_register(eap); 1645 if (parse_count(eap, errormsg, false) == FAIL) { 1646 goto end; 1647 } 1648 1649 // Remove leading whitespace and colon from next command 1650 if (eap->nextcmd) { 1651 eap->nextcmd = skip_colon_white(eap->nextcmd, true); 1652 } 1653 1654 // Set the "magic" values (characters that get treated specially) 1655 if (eap->argt & EX_XFILE) { 1656 cmdinfo->magic.file = true; 1657 } 1658 if (eap->argt & EX_TRLBAR) { 1659 cmdinfo->magic.bar = true; 1660 } 1661 1662 retval = true; 1663 end: 1664 if (!retval) { 1665 undo_cmdmod(&cmdinfo->cmdmod); 1666 } 1667 ex_pressedreturn = save_ex_pressedreturn; 1668 curwin->w_cursor = save_cursor; 1669 restore_last_search_pattern(); 1670 return retval; 1671 } 1672 1673 // Shift Ex-command arguments to the right. 1674 static void shift_cmd_args(exarg_T *eap) 1675 { 1676 assert(eap->args != NULL && eap->argc > 0); 1677 1678 char **oldargs = eap->args; 1679 size_t *oldarglens = eap->arglens; 1680 1681 eap->argc--; 1682 eap->args = eap->argc > 0 ? xcalloc(eap->argc, sizeof(char *)) : NULL; 1683 eap->arglens = eap->argc > 0 ? xcalloc(eap->argc, sizeof(size_t)) : NULL; 1684 1685 for (size_t i = 0; i < eap->argc; i++) { 1686 eap->args[i] = oldargs[i + 1]; 1687 eap->arglens[i] = oldarglens[i + 1]; 1688 } 1689 1690 // If there are no arguments, make eap->arg point to the end of string. 1691 eap->arg = (eap->argc > 0 ? eap->args[0] : (oldargs[0] + oldarglens[0])); 1692 1693 xfree(oldargs); 1694 xfree(oldarglens); 1695 } 1696 1697 static int execute_cmd0(int *retv, exarg_T *eap, const char **errormsg, bool preview) 1698 { 1699 // If filename expansion is enabled, expand filenames 1700 if (eap->argt & EX_XFILE) { 1701 if (expand_filename(eap, eap->cmdlinep, errormsg) == FAIL) { 1702 return FAIL; 1703 } 1704 } 1705 1706 // Accept buffer name. Cannot be used at the same time with a buffer 1707 // number. Don't do this for a user command. 1708 if ((eap->argt & EX_BUFNAME) && *eap->arg != NUL && eap->addr_count == 0 1709 && !IS_USER_CMDIDX(eap->cmdidx)) { 1710 if (eap->args == NULL) { 1711 // If argument positions are not specified, search the argument for the buffer name. 1712 // :bdelete, :bwipeout and :bunload take several arguments, separated by spaces: 1713 // find next space (skipping over escaped characters). 1714 // The others take one argument: ignore trailing spaces. 1715 char *p; 1716 1717 if (eap->cmdidx == CMD_bdelete || eap->cmdidx == CMD_bwipeout 1718 || eap->cmdidx == CMD_bunload) { 1719 p = skiptowhite_esc(eap->arg); 1720 } else { 1721 p = eap->arg + strlen(eap->arg); 1722 while (p > eap->arg && ascii_iswhite(p[-1])) { 1723 p--; 1724 } 1725 } 1726 eap->line2 = buflist_findpat(eap->arg, p, (eap->argt & EX_BUFUNL) != 0, 1727 false, false); 1728 eap->addr_count = 1; 1729 eap->arg = skipwhite(p); 1730 } else { 1731 // If argument positions are specified, just use the first argument 1732 eap->line2 = buflist_findpat(eap->args[0], 1733 eap->args[0] + eap->arglens[0], 1734 (eap->argt & EX_BUFUNL) != 0, false, false); 1735 eap->addr_count = 1; 1736 shift_cmd_args(eap); 1737 } 1738 if (eap->line2 < 0) { // failed 1739 return FAIL; 1740 } 1741 } 1742 1743 // The :try command saves the emsg_silent flag, reset it here when 1744 // ":silent! try" was used, it should only apply to :try itself. 1745 if (eap->cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) { 1746 emsg_silent -= cmdmod.cmod_did_esilent; 1747 emsg_silent = MAX(emsg_silent, 0); 1748 cmdmod.cmod_did_esilent = 0; 1749 } 1750 1751 // Execute the command 1752 if (IS_USER_CMDIDX(eap->cmdidx)) { 1753 // Execute a user-defined command. 1754 *retv = do_ucmd(eap, preview); 1755 } else { 1756 // Call the function to execute the builtin command or the preview callback. 1757 eap->errmsg = NULL; 1758 if (preview) { 1759 *retv = (cmdnames[eap->cmdidx].cmd_preview_func)(eap, cmdpreview_get_ns(), 1760 cmdpreview_get_bufnr()); 1761 } else { 1762 (cmdnames[eap->cmdidx].cmd_func)(eap); 1763 } 1764 if (eap->errmsg != NULL) { 1765 *errormsg = eap->errmsg; 1766 } 1767 } 1768 1769 return OK; 1770 } 1771 1772 /// Execute an Ex command using parsed command line information. 1773 /// Does not do any validation of the Ex command arguments. 1774 /// 1775 /// @param eap Ex-command arguments 1776 /// @param cmdinfo Command parse information 1777 /// @param preview Execute command preview callback instead of actual command 1778 int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) 1779 { 1780 int retv = 0; 1781 if (do_cmdline_start() == FAIL) { 1782 emsg(_(e_command_too_recursive)); 1783 return retv; 1784 } 1785 1786 const char *errormsg = NULL; 1787 1788 cmdmod_T save_cmdmod = cmdmod; 1789 cmdmod = cmdinfo->cmdmod; 1790 1791 // Apply command modifiers 1792 apply_cmdmod(&cmdmod); 1793 1794 if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) 1795 // allow :put in terminals 1796 && !(curbuf->terminal && (eap->cmdidx == CMD_put || eap->cmdidx == CMD_iput))) { 1797 errormsg = _(e_modifiable); 1798 goto end; 1799 } 1800 if (!IS_USER_CMDIDX(eap->cmdidx)) { 1801 if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) { 1802 // Command not allowed in the command line window 1803 errormsg = _(e_cmdwin); 1804 goto end; 1805 } 1806 if (text_locked() && !(eap->argt & EX_LOCK_OK)) { 1807 // Command not allowed when text is locked 1808 errormsg = _(get_text_locked_msg()); 1809 goto end; 1810 } 1811 } 1812 // Disallow editing another buffer when "curbuf->b_ro_locked" is set. 1813 // Do allow ":checktime" (it is postponed). 1814 // Do allow ":edit" (check for an argument later). 1815 // Do allow ":file" with no arguments 1816 if (!(eap->argt & EX_CMDWIN) 1817 && eap->cmdidx != CMD_checktime 1818 && eap->cmdidx != CMD_edit 1819 && !(eap->cmdidx == CMD_file && *eap->arg == NUL) 1820 && !IS_USER_CMDIDX(eap->cmdidx) 1821 && curbuf_locked()) { 1822 goto end; 1823 } 1824 1825 correct_range(eap); 1826 1827 if (((eap->argt & EX_WHOLEFOLD) || eap->addr_count >= 2) && !global_busy 1828 && eap->addr_type == ADDR_LINES) { 1829 // Put the first line at the start of a closed fold, put the last line 1830 // at the end of a closed fold. 1831 hasFolding(curwin, eap->line1, &eap->line1, NULL); 1832 hasFolding(curwin, eap->line2, NULL, &eap->line2); 1833 } 1834 1835 // Use first argument as count when possible 1836 if (parse_count(eap, &errormsg, true) == FAIL) { 1837 goto end; 1838 } 1839 1840 cstack_T cstack = { .cs_idx = -1 }; 1841 eap->cstack = &cstack; 1842 1843 // Execute the command 1844 execute_cmd0(&retv, eap, &errormsg, preview); 1845 1846 end: 1847 if (errormsg != NULL && *errormsg != NUL) { 1848 emsg(errormsg); 1849 } 1850 1851 // Undo command modifiers 1852 undo_cmdmod(&cmdmod); 1853 cmdmod = save_cmdmod; 1854 1855 do_cmdline_end(); 1856 return retv; 1857 } 1858 1859 static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie) 1860 { 1861 // Count this line for profiling if skip is true. 1862 if (do_profiling == PROF_YES 1863 && (!eap->skip || cstack->cs_idx == 0 1864 || (cstack->cs_idx > 0 1865 && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))) { 1866 bool skip = did_emsg || got_int || did_throw; 1867 1868 if (eap->cmdidx == CMD_catch) { 1869 skip = !skip && !(cstack->cs_idx >= 0 1870 && (cstack->cs_flags[cstack->cs_idx] & CSF_THROWN) 1871 && !(cstack->cs_flags[cstack->cs_idx] & CSF_CAUGHT)); 1872 } else if (eap->cmdidx == CMD_else || eap->cmdidx == CMD_elseif) { 1873 skip = skip || !(cstack->cs_idx >= 0 1874 && !(cstack->cs_flags[cstack->cs_idx] 1875 & (CSF_ACTIVE | CSF_TRUE))); 1876 } else if (eap->cmdidx == CMD_finally) { 1877 skip = false; 1878 } else if (eap->cmdidx != CMD_endif 1879 && eap->cmdidx != CMD_endfor 1880 && eap->cmdidx != CMD_endtry 1881 && eap->cmdidx != CMD_endwhile) { 1882 skip = eap->skip; 1883 } 1884 1885 if (!skip) { 1886 if (getline_equal(fgetline, cookie, get_func_line)) { 1887 func_line_exec(getline_cookie(fgetline, cookie)); 1888 } else if (getline_equal(fgetline, cookie, getsourceline)) { 1889 script_line_exec(); 1890 } 1891 } 1892 } 1893 } 1894 1895 static bool skip_cmd(const exarg_T *eap) 1896 { 1897 // Skip the command when it's not going to be executed. 1898 // The commands like :if, :endif, etc. always need to be executed. 1899 // Also make an exception for commands that handle a trailing command 1900 // themselves. 1901 if (eap->skip) { 1902 switch (eap->cmdidx) { 1903 // commands that need evaluation 1904 case CMD_while: 1905 case CMD_endwhile: 1906 case CMD_for: 1907 case CMD_endfor: 1908 case CMD_if: 1909 case CMD_elseif: 1910 case CMD_else: 1911 case CMD_endif: 1912 case CMD_try: 1913 case CMD_catch: 1914 case CMD_finally: 1915 case CMD_endtry: 1916 case CMD_function: 1917 break; 1918 1919 // Commands that handle '|' themselves. Check: A command should 1920 // either have the EX_TRLBAR flag, appear in this list or appear in 1921 // the list at ":help :bar". 1922 case CMD_aboveleft: 1923 case CMD_and: 1924 case CMD_belowright: 1925 case CMD_botright: 1926 case CMD_browse: 1927 case CMD_call: 1928 case CMD_confirm: 1929 case CMD_const: 1930 case CMD_delfunction: 1931 case CMD_djump: 1932 case CMD_dlist: 1933 case CMD_dsearch: 1934 case CMD_dsplit: 1935 case CMD_echo: 1936 case CMD_echoerr: 1937 case CMD_echomsg: 1938 case CMD_echon: 1939 case CMD_eval: 1940 case CMD_execute: 1941 case CMD_filter: 1942 case CMD_help: 1943 case CMD_hide: 1944 case CMD_horizontal: 1945 case CMD_ijump: 1946 case CMD_ilist: 1947 case CMD_isearch: 1948 case CMD_isplit: 1949 case CMD_keepalt: 1950 case CMD_keepjumps: 1951 case CMD_keepmarks: 1952 case CMD_keeppatterns: 1953 case CMD_leftabove: 1954 case CMD_let: 1955 case CMD_lockmarks: 1956 case CMD_lockvar: 1957 case CMD_lua: 1958 case CMD_match: 1959 case CMD_mzscheme: 1960 case CMD_noautocmd: 1961 case CMD_noswapfile: 1962 case CMD_perl: 1963 case CMD_psearch: 1964 case CMD_python: 1965 case CMD_py3: 1966 case CMD_python3: 1967 case CMD_pythonx: 1968 case CMD_pyx: 1969 case CMD_return: 1970 case CMD_rightbelow: 1971 case CMD_ruby: 1972 case CMD_silent: 1973 case CMD_smagic: 1974 case CMD_snomagic: 1975 case CMD_substitute: 1976 case CMD_syntax: 1977 case CMD_tab: 1978 case CMD_tcl: 1979 case CMD_throw: 1980 case CMD_tilde: 1981 case CMD_topleft: 1982 case CMD_unlet: 1983 case CMD_unlockvar: 1984 case CMD_verbose: 1985 case CMD_vertical: 1986 case CMD_wincmd: 1987 break; 1988 1989 default: 1990 return true; 1991 } 1992 } 1993 return false; 1994 } 1995 1996 /// Execute one Ex command. 1997 /// 1998 /// If "flags" has DOCMD_VERBOSE, the command will be included in the error 1999 /// message. 2000 /// 2001 /// 1. skip comment lines and leading space 2002 /// 2. handle command modifiers 2003 /// 3. skip over the range to find the command 2004 /// 4. parse the range 2005 /// 5. parse the command 2006 /// 6. parse arguments 2007 /// 7. switch on command name 2008 /// 2009 /// Note: "fgetline" can be NULL. 2010 /// 2011 /// This function may be called recursively! 2012 /// 2013 /// @param cookie argument for fgetline() 2014 static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline, 2015 void *cookie) 2016 { 2017 const char *errormsg = NULL; // error message 2018 const int save_reg_executing = reg_executing; 2019 const bool save_pending_end_reg_executing = pending_end_reg_executing; 2020 2021 exarg_T ea = { 2022 .line1 = 1, 2023 .line2 = 1, 2024 }; 2025 ex_nesting_level++; 2026 2027 // When the last file has not been edited :q has to be typed twice. 2028 if (quitmore 2029 // avoid that a function call in 'statusline' does this 2030 && !getline_equal(fgetline, cookie, get_func_line) 2031 // avoid that an autocommand, e.g. QuitPre, does this 2032 && !getline_equal(fgetline, cookie, getnextac)) { 2033 quitmore--; 2034 } 2035 2036 // Reset browse, confirm, etc.. They are restored when returning, for 2037 // recursive calls. 2038 cmdmod_T save_cmdmod = cmdmod; 2039 2040 // "#!anything" is handled like a comment. 2041 if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') { 2042 goto doend; 2043 } 2044 2045 // 1. Skip comment lines and leading white space and colons. 2046 // 2. Handle command modifiers. 2047 2048 // The "ea" structure holds the arguments that can be used. 2049 ea.cmd = *cmdlinep; 2050 ea.cmdlinep = cmdlinep; 2051 ea.ea_getline = fgetline; 2052 ea.cookie = cookie; 2053 ea.cstack = cstack; 2054 2055 if (parse_command_modifiers(&ea, &errormsg, &cmdmod, false) == FAIL) { 2056 goto doend; 2057 } 2058 apply_cmdmod(&cmdmod); 2059 2060 char *after_modifier = ea.cmd; 2061 2062 ea.skip = (did_emsg 2063 || got_int 2064 || did_throw 2065 || (cstack->cs_idx >= 0 2066 && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))); 2067 2068 // 3. Skip over the range to find the command. Let "p" point to after it. 2069 // 2070 // We need the command to know what kind of range it uses. 2071 char *p = find_excmd_after_range(&ea); 2072 profile_cmd(&ea, cstack, fgetline, cookie); 2073 2074 if (!exiting) { 2075 // May go to debug mode. If this happens and the ">quit" debug command is 2076 // used, throw an interrupt exception and skip the next command. 2077 dbg_check_breakpoint(&ea); 2078 } 2079 if (!ea.skip && got_int) { 2080 ea.skip = true; 2081 do_intthrow(cstack); 2082 } 2083 2084 // 4. Parse a range specifier of the form: addr [,addr] [;addr] .. 2085 // 2086 // where 'addr' is: 2087 // 2088 // % (entire file) 2089 // $ [+-NUM] 2090 // 'x [+-NUM] (where x denotes a currently defined mark) 2091 // . [+-NUM] 2092 // [+-NUM].. 2093 // NUM 2094 // 2095 // The ea.cmd pointer is updated to point to the first character following the 2096 // range spec. If an initial address is found, but no second, the upper bound 2097 // is equal to the lower. 2098 set_cmd_addr_type(&ea, p); 2099 2100 if (parse_cmd_address(&ea, &errormsg, false) == FAIL) { 2101 goto doend; 2102 } 2103 2104 // 5. Parse the command. 2105 2106 // Skip ':' and any white space 2107 ea.cmd = skip_colon_white(ea.cmd, true); 2108 2109 // If we got a line, but no command, then go to the line. 2110 // If we find a '|' or '\n' we set ea.nextcmd. 2111 if (*ea.cmd == NUL || *ea.cmd == '"' 2112 || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { 2113 // strange vi behaviour: 2114 // ":3" jumps to line 3 2115 // ":3|..." prints line 3 2116 // ":|" prints current line 2117 if (ea.skip) { // skip this if inside :if 2118 goto doend; 2119 } 2120 assert(errormsg == NULL); 2121 errormsg = ex_range_without_command(&ea); 2122 goto doend; 2123 } 2124 2125 // If this looks like an undefined user command and there are CmdUndefined 2126 // autocommands defined, trigger the matching autocommands. 2127 if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip 2128 && ASCII_ISUPPER(*ea.cmd) 2129 && has_event(EVENT_CMDUNDEFINED)) { 2130 char *cmdname = ea.cmd; 2131 while (ASCII_ISALNUM(*cmdname)) { 2132 cmdname++; 2133 } 2134 cmdname = xmemdupz(ea.cmd, (size_t)(cmdname - ea.cmd)); 2135 int ret = apply_autocmds(EVENT_CMDUNDEFINED, cmdname, cmdname, true, NULL); 2136 xfree(cmdname); 2137 // If the autocommands did something and didn't cause an error, try 2138 // finding the command again. 2139 p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd; 2140 } 2141 2142 if (p == NULL) { 2143 if (!ea.skip) { 2144 errormsg = _(e_ambiguous_use_of_user_defined_command); 2145 } 2146 goto doend; 2147 } 2148 2149 // Check for wrong commands. 2150 if (ea.cmdidx == CMD_SIZE) { 2151 if (!ea.skip) { 2152 xstrlcpy(IObuff, _(e_not_an_editor_command), IOSIZE); 2153 // If the modifier was parsed OK the error must be in the following 2154 // command 2155 char *cmdname = after_modifier ? after_modifier : *cmdlinep; 2156 if (!(flags & DOCMD_VERBOSE)) { 2157 append_command(cmdname); 2158 } 2159 errormsg = IObuff; 2160 did_emsg_syntax = true; 2161 verify_command(cmdname); 2162 } 2163 goto doend; 2164 } 2165 2166 // set when Not Implemented 2167 const int ni = is_cmd_ni(ea.cmdidx); 2168 2169 // Determine if command has forceit flag ('!') 2170 ea.forceit = parse_bang(&ea, &p); 2171 2172 // 6. Parse arguments. Then check for errors. 2173 if (!IS_USER_CMDIDX(ea.cmdidx)) { 2174 ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt; 2175 } 2176 2177 if (!ea.skip) { 2178 if (sandbox != 0 && !(ea.argt & EX_SBOXOK)) { 2179 // Command not allowed in sandbox. 2180 errormsg = _(e_sandbox); 2181 goto doend; 2182 } 2183 if (!MODIFIABLE(curbuf) && (ea.argt & EX_MODIFY) 2184 // allow :put in terminals 2185 && !(curbuf->terminal && (ea.cmdidx == CMD_put || ea.cmdidx == CMD_iput))) { 2186 // Command not allowed in non-'modifiable' buffer 2187 errormsg = _(e_modifiable); 2188 goto doend; 2189 } 2190 2191 if (!IS_USER_CMDIDX(ea.cmdidx)) { 2192 if (cmdwin_type != 0 && !(ea.argt & EX_CMDWIN)) { 2193 // Command not allowed in the command line window 2194 errormsg = _(e_cmdwin); 2195 goto doend; 2196 } 2197 if (text_locked() && !(ea.argt & EX_LOCK_OK)) { 2198 // Command not allowed when text is locked 2199 errormsg = _(get_text_locked_msg()); 2200 goto doend; 2201 } 2202 } 2203 2204 // Disallow editing another buffer when "curbuf->b_ro_locked" is set. 2205 // Do allow ":checktime" (it is postponed). 2206 // Do allow ":edit" (check for an argument later). 2207 // Do allow ":file" with no arguments (check for an argument later). 2208 if (!(ea.argt & EX_CMDWIN) 2209 && ea.cmdidx != CMD_checktime 2210 && ea.cmdidx != CMD_edit 2211 && ea.cmdidx != CMD_file 2212 && !IS_USER_CMDIDX(ea.cmdidx) 2213 && curbuf_locked()) { 2214 goto doend; 2215 } 2216 2217 if (!ni && !(ea.argt & EX_RANGE) && ea.addr_count > 0) { 2218 // no range allowed 2219 errormsg = _(e_norange); 2220 goto doend; 2221 } 2222 } 2223 2224 if (!ni && !(ea.argt & EX_BANG) && ea.forceit) { // no <!> allowed 2225 errormsg = _(e_nobang); 2226 goto doend; 2227 } 2228 2229 // Don't complain about the range if it is not used 2230 // (could happen if line_count is accidentally set to 0). 2231 if (!ea.skip && !ni && (ea.argt & EX_RANGE)) { 2232 // If the range is backwards, ask for confirmation and, if given, swap 2233 // ea.line1 & ea.line2 so it's forwards again. 2234 // When global command is busy, don't ask, will fail below. 2235 if (!global_busy && ea.line1 > ea.line2) { 2236 if (msg_silent == 0) { 2237 if ((flags & DOCMD_VERBOSE) || exmode_active) { 2238 errormsg = _("E493: Backwards range given"); 2239 goto doend; 2240 } 2241 if (ask_yesno(_("Backwards range given, OK to swap")) != 'y') { 2242 goto doend; 2243 } 2244 } 2245 linenr_T lnum = ea.line1; 2246 ea.line1 = ea.line2; 2247 ea.line2 = lnum; 2248 } 2249 if ((errormsg = invalid_range(&ea)) != NULL) { 2250 goto doend; 2251 } 2252 } 2253 2254 if ((ea.addr_type == ADDR_OTHER) && ea.addr_count == 0) { 2255 // default is 1, not cursor 2256 ea.line2 = 1; 2257 } 2258 2259 correct_range(&ea); 2260 2261 if (((ea.argt & EX_WHOLEFOLD) || ea.addr_count >= 2) && !global_busy 2262 && ea.addr_type == ADDR_LINES) { 2263 // Put the first line at the start of a closed fold, put the last line 2264 // at the end of a closed fold. 2265 hasFolding(curwin, ea.line1, &ea.line1, NULL); 2266 hasFolding(curwin, ea.line2, NULL, &ea.line2); 2267 } 2268 2269 // For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' 2270 // option here, so things like % get expanded. 2271 p = replace_makeprg(&ea, p, cmdlinep); 2272 if (p == NULL) { 2273 goto doend; 2274 } 2275 2276 // Skip to start of argument. 2277 // Don't do this for the ":!" command, because ":!! -l" needs the space. 2278 ea.arg = ea.cmdidx == CMD_bang ? p : skipwhite(p); 2279 2280 // ":file" cannot be run with an argument when "curbuf->b_ro_locked" is set 2281 if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked()) { 2282 goto doend; 2283 } 2284 2285 // Check for "++opt=val" argument. 2286 // Must be first, allow ":w ++enc=utf8 !cmd" 2287 if (ea.argt & EX_ARGOPT) { 2288 while (ea.arg[0] == '+' && ea.arg[1] == '+') { 2289 if (getargopt(&ea) == FAIL && !ni) { 2290 errormsg = _(e_invarg); 2291 goto doend; 2292 } 2293 } 2294 } 2295 2296 if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { 2297 if (*ea.arg == '>') { // append 2298 if (*++ea.arg != '>') { // typed wrong 2299 errormsg = _("E494: Use w or w>>"); 2300 goto doend; 2301 } 2302 ea.arg = skipwhite(ea.arg + 1); 2303 ea.append = true; 2304 } else if (*ea.arg == '!' && ea.cmdidx == CMD_write) { // :w !filter 2305 ea.arg++; 2306 ea.usefilter = true; 2307 } 2308 } else if (ea.cmdidx == CMD_read) { 2309 if (ea.forceit) { 2310 ea.usefilter = true; // :r! filter if ea.forceit 2311 ea.forceit = false; 2312 } else if (*ea.arg == '!') { // :r !filter 2313 ea.arg++; 2314 ea.usefilter = true; 2315 } 2316 } else if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { 2317 ea.amount = 1; 2318 while (*ea.arg == *ea.cmd) { // count number of '>' or '<' 2319 ea.arg++; 2320 ea.amount++; 2321 } 2322 ea.arg = skipwhite(ea.arg); 2323 } 2324 2325 // Check for "+command" argument, before checking for next command. 2326 // Don't do this for ":read !cmd" and ":write !cmd". 2327 if ((ea.argt & EX_CMDARG) && !ea.usefilter) { 2328 ea.do_ecmd_cmd = getargcmd(&ea.arg); 2329 } 2330 2331 // Check for '|' to separate commands and '"' to start comments. 2332 // Don't do this for ":read !cmd" and ":write !cmd". 2333 if ((ea.argt & EX_TRLBAR) && !ea.usefilter) { 2334 separate_nextcmd(&ea); 2335 } else if (ea.cmdidx == CMD_bang 2336 || ea.cmdidx == CMD_terminal 2337 || ea.cmdidx == CMD_global 2338 || ea.cmdidx == CMD_vglobal 2339 || ea.usefilter) { 2340 // Check for <newline> to end a shell command. 2341 // Also do this for ":read !cmd", ":write !cmd" and ":global". 2342 // Any others? 2343 for (char *s = ea.arg; *s; s++) { 2344 // Remove one backslash before a newline. 2345 if (*s == '\\' && s[1] == '\n') { 2346 STRMOVE(s, s + 1); 2347 } else if (*s == '\n') { 2348 ea.nextcmd = s + 1; 2349 *s = NUL; 2350 break; 2351 } 2352 } 2353 } 2354 2355 if ((ea.argt & EX_DFLALL) && ea.addr_count == 0) { 2356 set_cmd_dflall_range(&ea); 2357 } 2358 2359 // Parse register and count 2360 parse_register(&ea); 2361 if (parse_count(&ea, &errormsg, true) == FAIL) { 2362 goto doend; 2363 } 2364 2365 // Check for flags: 'l', 'p' and '#'. 2366 if (ea.argt & EX_FLAGS) { 2367 get_flags(&ea); 2368 } 2369 if (!ni && !(ea.argt & EX_EXTRA) && *ea.arg != NUL 2370 && *ea.arg != '"' && (*ea.arg != '|' || (ea.argt & EX_TRLBAR) == 0)) { 2371 // no arguments allowed but there is something 2372 errormsg = ex_errmsg(e_trailing_arg, ea.arg); 2373 goto doend; 2374 } 2375 2376 if (!ni && (ea.argt & EX_NEEDARG) && *ea.arg == NUL) { 2377 errormsg = _(e_argreq); 2378 goto doend; 2379 } 2380 2381 if (skip_cmd(&ea)) { 2382 goto doend; 2383 } 2384 2385 // 7. Execute the command. 2386 int retv = 0; 2387 if (execute_cmd0(&retv, &ea, &errormsg, false) == FAIL) { 2388 goto doend; 2389 } 2390 2391 // If the command just executed called do_cmdline(), any throw or ":return" 2392 // or ":finish" encountered there must also check the cstack of the still 2393 // active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught 2394 // exception, or reanimate a returned function or finished script file and 2395 // return or finish it again. 2396 if (need_rethrow) { 2397 do_throw(cstack); 2398 } else if (check_cstack) { 2399 if (source_finished(fgetline, cookie)) { 2400 do_finish(&ea, true); 2401 } else if (getline_equal(fgetline, cookie, get_func_line) 2402 && current_func_returned()) { 2403 do_return(&ea, true, false, NULL); 2404 } 2405 } 2406 need_rethrow = check_cstack = false; 2407 2408 doend: 2409 // can happen with zero line number 2410 if (curwin->w_cursor.lnum == 0) { 2411 curwin->w_cursor.lnum = 1; 2412 curwin->w_cursor.col = 0; 2413 } 2414 2415 if (errormsg != NULL && *errormsg != NUL && !did_emsg) { 2416 if (flags & DOCMD_VERBOSE) { 2417 if (errormsg != IObuff) { 2418 xstrlcpy(IObuff, errormsg, IOSIZE); 2419 errormsg = IObuff; 2420 } 2421 append_command(*ea.cmdlinep); 2422 } 2423 emsg(errormsg); 2424 } 2425 do_errthrow(cstack, 2426 (ea.cmdidx != CMD_SIZE 2427 && !IS_USER_CMDIDX(ea.cmdidx)) ? cmdnames[(int)ea.cmdidx].cmd_name : NULL); 2428 2429 undo_cmdmod(&cmdmod); 2430 cmdmod = save_cmdmod; 2431 reg_executing = save_reg_executing; 2432 pending_end_reg_executing = save_pending_end_reg_executing; 2433 2434 if (ea.nextcmd && *ea.nextcmd == NUL) { // not really a next command 2435 ea.nextcmd = NULL; 2436 } 2437 2438 ex_nesting_level--; 2439 xfree(ea.cmdline_tofree); 2440 2441 return ea.nextcmd; 2442 } 2443 2444 static char ex_error_buf[MSG_BUF_LEN]; 2445 2446 /// @return an error message with argument included. 2447 /// Uses a static buffer, only the last error will be kept. 2448 /// "msg" will be translated, caller should use N_(). 2449 char *ex_errmsg(const char *const msg, const char *const arg) 2450 FUNC_ATTR_NONNULL_ALL 2451 { 2452 vim_snprintf(ex_error_buf, MSG_BUF_LEN, _(msg), arg); 2453 return ex_error_buf; 2454 } 2455 2456 /// The "+" string used in place of an empty command in Ex mode. 2457 /// This string is used in pointer comparison. 2458 static char exmode_plus[] = "+"; 2459 2460 /// Handle a range without a command. 2461 /// Returns an error message on failure. 2462 static char *ex_range_without_command(exarg_T *eap) 2463 { 2464 char *errormsg = NULL; 2465 2466 if (*eap->cmd == '|' || (exmode_active && eap->cmd != exmode_plus + 1)) { 2467 eap->cmdidx = CMD_print; 2468 eap->argt = EX_RANGE | EX_COUNT | EX_TRLBAR; 2469 if ((errormsg = invalid_range(eap)) == NULL) { 2470 correct_range(eap); 2471 ex_print(eap); 2472 } 2473 } else if (eap->addr_count != 0) { 2474 eap->line2 = MIN(eap->line2, curbuf->b_ml.ml_line_count); 2475 2476 if (eap->line2 < 0) { 2477 errormsg = _(e_invrange); 2478 } else { 2479 if (eap->line2 == 0) { 2480 curwin->w_cursor.lnum = 1; 2481 } else { 2482 curwin->w_cursor.lnum = eap->line2; 2483 } 2484 beginline(BL_SOL | BL_FIX); 2485 } 2486 } 2487 return errormsg; 2488 } 2489 2490 /// Parse and skip over command modifiers: 2491 /// - update eap->cmd 2492 /// - store flags in "cmod". 2493 /// - Set ex_pressedreturn for an empty command line. 2494 /// 2495 /// @param skip_only if false, undo_cmdmod() must be called later to free 2496 /// any cmod_filter_pat and cmod_filter_regmatch.regprog, 2497 /// and ex_pressedreturn may be set. 2498 /// @param[out] errormsg potential error message. 2499 /// 2500 /// Call apply_cmdmod() to get the side effects of the modifiers: 2501 /// - Increment "sandbox" for ":sandbox" 2502 /// - set p_verbose for ":verbose" 2503 /// - set msg_silent for ":silent" 2504 /// - set 'eventignore' to "all" for ":noautocmd" 2505 /// 2506 /// @return FAIL when the command is not to be executed. 2507 int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, bool skip_only) 2508 { 2509 char *orig_cmd = eap->cmd; 2510 char *cmd_start = NULL; 2511 bool use_plus_cmd = false; 2512 bool has_visual_range = false; 2513 CLEAR_POINTER(cmod); 2514 2515 if (strncmp(eap->cmd, "'<,'>", 5) == 0) { 2516 // The automatically inserted Visual area range is skipped, so that 2517 // typing ":cmdmod cmd" in Visual mode works without having to move the 2518 // range to after the modifiers. The command will be "'<,'>cmdmod cmd", 2519 // parse "cmdmod cmd" and then put back "'<,'>" before "cmd" below. 2520 eap->cmd += 5; 2521 cmd_start = eap->cmd; 2522 has_visual_range = true; 2523 } 2524 2525 // Repeat until no more command modifiers are found. 2526 while (true) { 2527 while (*eap->cmd == ' ' 2528 || *eap->cmd == '\t' 2529 || *eap->cmd == ':') { 2530 eap->cmd++; 2531 } 2532 2533 // in ex mode, an empty command (after modifiers) works like :+ 2534 if (*eap->cmd == NUL && exmode_active 2535 && getline_equal(eap->ea_getline, eap->cookie, getexline) 2536 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { 2537 eap->cmd = exmode_plus; 2538 use_plus_cmd = true; 2539 if (!skip_only) { 2540 ex_pressedreturn = true; 2541 } 2542 break; // no modifiers following 2543 } 2544 2545 // ignore comment and empty lines 2546 if (*eap->cmd == '"') { 2547 // a comment ends at a NL 2548 eap->nextcmd = vim_strchr(eap->cmd, '\n'); 2549 if (eap->nextcmd != NULL) { 2550 eap->nextcmd++; 2551 } 2552 return FAIL; 2553 } 2554 if (*eap->cmd == '\n') { 2555 eap->nextcmd = eap->cmd + 1; 2556 return FAIL; 2557 } 2558 if (*eap->cmd == NUL) { 2559 if (!skip_only) { 2560 ex_pressedreturn = true; 2561 } 2562 return FAIL; 2563 } 2564 2565 char *p = skip_range(eap->cmd, NULL); 2566 switch (*p) { 2567 // When adding an entry, also modify cmdmods[] 2568 case 'a': 2569 if (!checkforcmd(&eap->cmd, "aboveleft", 3)) { 2570 break; 2571 } 2572 cmod->cmod_split |= WSP_ABOVE; 2573 continue; 2574 2575 case 'b': 2576 if (checkforcmd(&eap->cmd, "belowright", 3)) { 2577 cmod->cmod_split |= WSP_BELOW; 2578 continue; 2579 } 2580 if (checkforcmd(&eap->cmd, "browse", 3)) { 2581 cmod->cmod_flags |= CMOD_BROWSE; 2582 continue; 2583 } 2584 if (!checkforcmd(&eap->cmd, "botright", 2)) { 2585 break; 2586 } 2587 cmod->cmod_split |= WSP_BOT; 2588 continue; 2589 2590 case 'c': 2591 if (!checkforcmd(&eap->cmd, "confirm", 4)) { 2592 break; 2593 } 2594 cmod->cmod_flags |= CMOD_CONFIRM; 2595 continue; 2596 2597 case 'k': 2598 if (checkforcmd(&eap->cmd, "keepmarks", 3)) { 2599 cmod->cmod_flags |= CMOD_KEEPMARKS; 2600 continue; 2601 } 2602 if (checkforcmd(&eap->cmd, "keepalt", 5)) { 2603 cmod->cmod_flags |= CMOD_KEEPALT; 2604 continue; 2605 } 2606 if (checkforcmd(&eap->cmd, "keeppatterns", 5)) { 2607 cmod->cmod_flags |= CMOD_KEEPPATTERNS; 2608 continue; 2609 } 2610 if (!checkforcmd(&eap->cmd, "keepjumps", 5)) { 2611 break; 2612 } 2613 cmod->cmod_flags |= CMOD_KEEPJUMPS; 2614 continue; 2615 2616 case 'f': { // only accept ":filter {pat} cmd" 2617 char *reg_pat; 2618 2619 if (!checkforcmd(&p, "filter", 4) || *p == NUL || ends_excmd(*p)) { 2620 break; 2621 } 2622 if (*p == '!') { 2623 cmod->cmod_filter_force = true; 2624 p = skipwhite(p + 1); 2625 if (*p == NUL || ends_excmd(*p)) { 2626 break; 2627 } 2628 } 2629 if (skip_only) { 2630 p = skip_vimgrep_pat(p, NULL, NULL); 2631 } else { 2632 // NOTE: This puts a NUL after the pattern. 2633 p = skip_vimgrep_pat(p, ®_pat, NULL); 2634 } 2635 if (p == NULL || *p == NUL) { 2636 break; 2637 } 2638 if (!skip_only) { 2639 cmod->cmod_filter_pat = xstrdup(reg_pat); 2640 cmod->cmod_filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); 2641 if (cmod->cmod_filter_regmatch.regprog == NULL) { 2642 break; 2643 } 2644 } 2645 eap->cmd = p; 2646 continue; 2647 } 2648 2649 case 'h': 2650 if (checkforcmd(&eap->cmd, "horizontal", 3)) { 2651 cmod->cmod_split |= WSP_HOR; 2652 continue; 2653 } 2654 // ":hide" and ":hide | cmd" are not modifiers 2655 if (p != eap->cmd || !checkforcmd(&p, "hide", 3) 2656 || *p == NUL || ends_excmd(*p)) { 2657 break; 2658 } 2659 eap->cmd = p; 2660 cmod->cmod_flags |= CMOD_HIDE; 2661 continue; 2662 2663 case 'l': 2664 if (checkforcmd(&eap->cmd, "lockmarks", 3)) { 2665 cmod->cmod_flags |= CMOD_LOCKMARKS; 2666 continue; 2667 } 2668 2669 if (!checkforcmd(&eap->cmd, "leftabove", 5)) { 2670 break; 2671 } 2672 cmod->cmod_split |= WSP_ABOVE; 2673 continue; 2674 2675 case 'n': 2676 if (checkforcmd(&eap->cmd, "noautocmd", 3)) { 2677 cmod->cmod_flags |= CMOD_NOAUTOCMD; 2678 continue; 2679 } 2680 if (!checkforcmd(&eap->cmd, "noswapfile", 3)) { 2681 break; 2682 } 2683 cmod->cmod_flags |= CMOD_NOSWAPFILE; 2684 continue; 2685 2686 case 'r': 2687 if (!checkforcmd(&eap->cmd, "rightbelow", 6)) { 2688 break; 2689 } 2690 cmod->cmod_split |= WSP_BELOW; 2691 continue; 2692 2693 case 's': 2694 if (checkforcmd(&eap->cmd, "sandbox", 3)) { 2695 cmod->cmod_flags |= CMOD_SANDBOX; 2696 continue; 2697 } 2698 if (!checkforcmd(&eap->cmd, "silent", 3)) { 2699 break; 2700 } 2701 cmod->cmod_flags |= CMOD_SILENT; 2702 if (*eap->cmd == '!' && !ascii_iswhite(eap->cmd[-1])) { 2703 // ":silent!", but not "silent !cmd" 2704 eap->cmd = skipwhite(eap->cmd + 1); 2705 cmod->cmod_flags |= CMOD_ERRSILENT; 2706 } 2707 continue; 2708 2709 case 't': 2710 if (checkforcmd(&p, "tab", 3)) { 2711 if (!skip_only) { 2712 int tabnr = (int)get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, 2713 false, 1, errormsg); 2714 if (eap->cmd == NULL) { 2715 return false; 2716 } 2717 2718 if (tabnr == MAXLNUM) { 2719 cmod->cmod_tab = tabpage_index(curtab) + 1; 2720 } else { 2721 if (tabnr < 0 || tabnr > LAST_TAB_NR) { 2722 *errormsg = _(e_invrange); 2723 return false; 2724 } 2725 cmod->cmod_tab = tabnr + 1; 2726 } 2727 } 2728 eap->cmd = p; 2729 continue; 2730 } 2731 if (!checkforcmd(&eap->cmd, "topleft", 2)) { 2732 break; 2733 } 2734 cmod->cmod_split |= WSP_TOP; 2735 continue; 2736 2737 case 'u': 2738 if (!checkforcmd(&eap->cmd, "unsilent", 3)) { 2739 break; 2740 } 2741 cmod->cmod_flags |= CMOD_UNSILENT; 2742 continue; 2743 2744 case 'v': 2745 if (checkforcmd(&eap->cmd, "vertical", 4)) { 2746 cmod->cmod_split |= WSP_VERT; 2747 continue; 2748 } 2749 if (!checkforcmd(&p, "verbose", 4)) { 2750 break; 2751 } 2752 if (ascii_isdigit(*eap->cmd)) { 2753 // zero means not set, one is verbose == 0, etc. 2754 cmod->cmod_verbose = atoi(eap->cmd) + 1; 2755 } else { 2756 cmod->cmod_verbose = 2; // default: verbose == 1 2757 } 2758 eap->cmd = p; 2759 continue; 2760 } 2761 break; 2762 } 2763 2764 if (has_visual_range) { 2765 if (eap->cmd > cmd_start) { 2766 // Move the '<,'> range to after the modifiers and insert a colon. 2767 // Since the modifiers have been parsed put the colon on top of the 2768 // space: "'<,'>mod cmd" -> "mod:'<,'>cmd 2769 // Put eap->cmd after the colon. 2770 if (use_plus_cmd) { 2771 size_t len = strlen(cmd_start); 2772 2773 // Special case: empty command uses "+": 2774 // "'<,'>mods" -> "mods *+ 2775 // Use "*" instead of "'<,'>" to avoid the command getting 2776 // longer, in case is was allocated. 2777 memmove(orig_cmd, cmd_start, len); 2778 xmemcpyz(orig_cmd + len, S_LEN(" *+")); 2779 } else { 2780 memmove(cmd_start - 5, cmd_start, (size_t)(eap->cmd - cmd_start)); 2781 eap->cmd -= 5; 2782 memmove(eap->cmd - 1, ":'<,'>", 6); 2783 } 2784 } else { 2785 // No modifiers, move the pointer back. 2786 // Special case: change empty command to "+". 2787 if (use_plus_cmd) { 2788 eap->cmd = "'<,'>+"; 2789 } else { 2790 eap->cmd = orig_cmd; 2791 } 2792 } 2793 } else if (use_plus_cmd) { 2794 eap->cmd = exmode_plus; 2795 } 2796 2797 return OK; 2798 } 2799 2800 /// Apply the command modifiers. Saves current state in "cmdmod", call 2801 /// undo_cmdmod() later. 2802 void apply_cmdmod(cmdmod_T *cmod) 2803 { 2804 if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) { 2805 sandbox++; 2806 cmod->cmod_did_sandbox = true; 2807 } 2808 if (cmod->cmod_verbose > 0) { 2809 if (cmod->cmod_verbose_save == 0) { 2810 cmod->cmod_verbose_save = p_verbose + 1; 2811 } 2812 p_verbose = cmod->cmod_verbose - 1; 2813 } 2814 2815 if ((cmod->cmod_flags & (CMOD_SILENT | CMOD_UNSILENT)) 2816 && cmod->cmod_save_msg_silent == 0) { 2817 cmod->cmod_save_msg_silent = msg_silent + 1; 2818 cmod->cmod_save_msg_scroll = msg_scroll; 2819 } 2820 if (cmod->cmod_flags & CMOD_SILENT) { 2821 msg_silent++; 2822 } 2823 if (cmod->cmod_flags & CMOD_UNSILENT) { 2824 msg_silent = 0; 2825 } 2826 2827 if (cmod->cmod_flags & CMOD_ERRSILENT) { 2828 emsg_silent++; 2829 cmod->cmod_did_esilent++; 2830 } 2831 2832 if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmod->cmod_save_ei == NULL) { 2833 // Set 'eventignore' to "all". 2834 // First save the existing option value for restoring it later. 2835 cmod->cmod_save_ei = xstrdup(p_ei); 2836 set_option_direct(kOptEventignore, STATIC_CSTR_AS_OPTVAL("all"), 0, SID_NONE); 2837 } 2838 } 2839 2840 /// Undo and free contents of "cmod". 2841 void undo_cmdmod(cmdmod_T *cmod) 2842 FUNC_ATTR_NONNULL_ALL 2843 { 2844 if (cmod->cmod_verbose_save > 0) { 2845 p_verbose = cmod->cmod_verbose_save - 1; 2846 cmod->cmod_verbose_save = 0; 2847 } 2848 2849 if (cmod->cmod_did_sandbox) { 2850 sandbox--; 2851 cmod->cmod_did_sandbox = false; 2852 } 2853 2854 if (cmod->cmod_save_ei != NULL) { 2855 // Restore 'eventignore' to the value before ":noautocmd". 2856 set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(cmod->cmod_save_ei), 0, SID_NONE); 2857 free_string_option(cmod->cmod_save_ei); 2858 cmod->cmod_save_ei = NULL; 2859 } 2860 2861 xfree(cmod->cmod_filter_pat); 2862 vim_regfree(cmod->cmod_filter_regmatch.regprog); 2863 2864 if (cmod->cmod_save_msg_silent > 0) { 2865 // messages could be enabled for a serious error, need to check if the 2866 // counters don't become negative 2867 if (!did_emsg || msg_silent > cmod->cmod_save_msg_silent - 1) { 2868 msg_silent = cmod->cmod_save_msg_silent - 1; 2869 } 2870 emsg_silent -= cmod->cmod_did_esilent; 2871 emsg_silent = MAX(emsg_silent, 0); 2872 // Restore msg_scroll, it's set by file I/O commands, even when no 2873 // message is actually displayed. 2874 msg_scroll = cmod->cmod_save_msg_scroll; 2875 2876 // "silent reg" or "silent echo x" inside "redir" leaves msg_col 2877 // somewhere in the line. Put it back in the first column. 2878 if (redirecting()) { 2879 msg_col = 0; 2880 } 2881 2882 cmod->cmod_save_msg_silent = 0; 2883 cmod->cmod_did_esilent = 0; 2884 } 2885 } 2886 2887 /// Parse the address range, if any, in "eap". 2888 /// May set the last search pattern, unless "silent" is true. 2889 /// 2890 /// @return FAIL and set "errormsg" or return OK. 2891 int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) 2892 FUNC_ATTR_NONNULL_ALL 2893 { 2894 int address_count = 1; 2895 linenr_T lnum; 2896 bool need_check_cursor = false; 2897 int ret = FAIL; 2898 2899 // Repeat for all ',' or ';' separated addresses. 2900 while (true) { 2901 eap->line1 = eap->line2; 2902 eap->line2 = get_cmd_default_range(eap); 2903 eap->cmd = skipwhite(eap->cmd); 2904 lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent, 2905 eap->addr_count == 0, address_count++, errormsg); 2906 if (eap->cmd == NULL) { // error detected 2907 goto theend; 2908 } 2909 if (lnum == MAXLNUM) { 2910 if (*eap->cmd == '%') { // '%' - all lines 2911 eap->cmd++; 2912 switch (eap->addr_type) { 2913 case ADDR_LINES: 2914 case ADDR_OTHER: 2915 eap->line1 = 1; 2916 eap->line2 = curbuf->b_ml.ml_line_count; 2917 break; 2918 case ADDR_LOADED_BUFFERS: { 2919 buf_T *buf = firstbuf; 2920 2921 while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) { 2922 buf = buf->b_next; 2923 } 2924 eap->line1 = buf->b_fnum; 2925 buf = lastbuf; 2926 while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { 2927 buf = buf->b_prev; 2928 } 2929 eap->line2 = buf->b_fnum; 2930 break; 2931 } 2932 case ADDR_BUFFERS: 2933 eap->line1 = firstbuf->b_fnum; 2934 eap->line2 = lastbuf->b_fnum; 2935 break; 2936 case ADDR_WINDOWS: 2937 case ADDR_TABS: 2938 if (IS_USER_CMDIDX(eap->cmdidx)) { 2939 eap->line1 = 1; 2940 eap->line2 = eap->addr_type == ADDR_WINDOWS 2941 ? LAST_WIN_NR : LAST_TAB_NR; 2942 } else { 2943 // there is no Vim command which uses '%' and 2944 // ADDR_WINDOWS or ADDR_TABS 2945 *errormsg = _(e_invrange); 2946 goto theend; 2947 } 2948 break; 2949 case ADDR_TABS_RELATIVE: 2950 case ADDR_UNSIGNED: 2951 case ADDR_QUICKFIX: 2952 *errormsg = _(e_invrange); 2953 goto theend; 2954 case ADDR_ARGUMENTS: 2955 if (ARGCOUNT == 0) { 2956 eap->line1 = eap->line2 = 0; 2957 } else { 2958 eap->line1 = 1; 2959 eap->line2 = ARGCOUNT; 2960 } 2961 break; 2962 case ADDR_QUICKFIX_VALID: 2963 eap->line1 = 1; 2964 eap->line2 = (linenr_T)qf_get_valid_size(eap); 2965 if (eap->line2 == 0) { 2966 eap->line2 = 1; 2967 } 2968 break; 2969 case ADDR_NONE: 2970 // Will give an error later if a range is found. 2971 break; 2972 } 2973 eap->addr_count++; 2974 } else if (*eap->cmd == '*') { 2975 // '*' - visual area 2976 if (eap->addr_type != ADDR_LINES) { 2977 *errormsg = _(e_invrange); 2978 goto theend; 2979 } 2980 2981 eap->cmd++; 2982 if (!eap->skip) { 2983 fmark_T *fm = mark_get_visual(curbuf, '<'); 2984 if (!mark_check(fm, errormsg)) { 2985 goto theend; 2986 } 2987 assert(fm != NULL); 2988 eap->line1 = fm->mark.lnum; 2989 fm = mark_get_visual(curbuf, '>'); 2990 if (!mark_check(fm, errormsg)) { 2991 goto theend; 2992 } 2993 assert(fm != NULL); 2994 eap->line2 = fm->mark.lnum; 2995 eap->addr_count++; 2996 } 2997 } 2998 } else { 2999 eap->line2 = lnum; 3000 } 3001 eap->addr_count++; 3002 3003 if (*eap->cmd == ';') { 3004 if (!eap->skip) { 3005 curwin->w_cursor.lnum = eap->line2; 3006 3007 // Don't leave the cursor on an illegal line or column, but do 3008 // accept zero as address, so 0;/PATTERN/ works correctly 3009 // (where zero usually means to use the first line). 3010 // Check the cursor position before returning. 3011 if (eap->line2 > 0) { 3012 check_cursor(curwin); 3013 } else { 3014 check_cursor_col(curwin); 3015 } 3016 need_check_cursor = true; 3017 } 3018 } else if (*eap->cmd != ',') { 3019 break; 3020 } 3021 eap->cmd++; 3022 } 3023 3024 // One address given: set start and end lines. 3025 if (eap->addr_count == 1) { 3026 eap->line1 = eap->line2; 3027 // ... but only implicit: really no address given 3028 if (lnum == MAXLNUM) { 3029 eap->addr_count = 0; 3030 } 3031 } 3032 ret = OK; 3033 3034 theend: 3035 if (need_check_cursor) { 3036 check_cursor(curwin); 3037 } 3038 return ret; 3039 } 3040 3041 /// Check for an Ex command with optional tail. 3042 /// If there is a match advance "pp" to the argument and return true. 3043 /// 3044 /// @param pp start of command 3045 /// @param cmd name of command 3046 /// @param len required length 3047 bool checkforcmd(char **pp, const char *cmd, int len) 3048 { 3049 int i; 3050 3051 for (i = 0; cmd[i] != NUL; i++) { 3052 if ((cmd)[i] != (*pp)[i]) { 3053 break; 3054 } 3055 } 3056 if (i >= len && !ASCII_ISALPHA((*pp)[i])) { 3057 *pp = skipwhite(*pp + i); 3058 return true; 3059 } 3060 return false; 3061 } 3062 3063 /// Append "cmd" to the error message in IObuff. 3064 /// Takes care of limiting the length and handling 0xa0, which would be 3065 /// invisible otherwise. 3066 static void append_command(const char *cmd) 3067 { 3068 size_t len = strlen(IObuff); 3069 const char *s = cmd; 3070 char *d; 3071 3072 if (len > IOSIZE - 100) { 3073 // Not enough space, truncate and put in "...". 3074 d = IObuff + IOSIZE - 100; 3075 d -= utf_head_off(IObuff, d); 3076 STRCPY(d, "..."); 3077 } 3078 xstrlcat(IObuff, ": ", IOSIZE); 3079 d = IObuff + strlen(IObuff); 3080 while (*s != NUL && d - IObuff + 5 < IOSIZE) { 3081 if ((uint8_t)s[0] == 0xc2 && (uint8_t)s[1] == 0xa0) { 3082 s += 2; 3083 STRCPY(d, "<a0>"); 3084 d += 4; 3085 } else if (d - IObuff + utfc_ptr2len(s) + 1 >= IOSIZE) { 3086 break; 3087 } else { 3088 mb_copy_char(&s, &d); 3089 } 3090 } 3091 *d = NUL; 3092 } 3093 3094 /// Return true and set "*idx" if "p" points to a one letter command. 3095 /// - The 'k' command can directly be followed by any character 3096 /// but :keepa[lt] is another command, as are :keepj[umps], 3097 /// :kee[pmarks] and :keepp[atterns]. 3098 /// - The 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' 3099 /// but :sre[wind] is another command, as are :scr[iptnames], 3100 /// :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. 3101 static int one_letter_cmd(const char *p, cmdidx_T *idx) 3102 { 3103 if (p[0] == 'k' 3104 && (p[1] != 'e' || (p[1] == 'e' && p[2] != 'e'))) { 3105 *idx = CMD_k; 3106 return true; 3107 } 3108 if (p[0] == 's' 3109 && ((p[1] == 'c' 3110 && (p[2] == NUL 3111 || (p[2] != 's' && p[2] != 'r' 3112 && (p[3] == NUL 3113 || (p[3] != 'i' && p[4] != 'p'))))) 3114 || p[1] == 'g' 3115 || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g') 3116 || p[1] == 'I' 3117 || (p[1] == 'r' && p[2] != 'e'))) { 3118 *idx = CMD_substitute; 3119 return true; 3120 } 3121 return false; 3122 } 3123 3124 /// Find an Ex command by its name, either built-in or user. 3125 /// Start of the name can be found at eap->cmd. 3126 /// Sets eap->cmdidx and returns a pointer to char after the command name. 3127 /// "full" is set to true if the whole command name matched. 3128 /// 3129 /// @return NULL for an ambiguous user command. 3130 char *find_ex_command(exarg_T *eap, int *full) 3131 FUNC_ATTR_NONNULL_ARG(1) 3132 { 3133 // Isolate the command and search for it in the command table. 3134 char *p = eap->cmd; 3135 if (one_letter_cmd(p, &eap->cmdidx)) { 3136 p++; 3137 if (full != NULL) { 3138 *full = true; 3139 } 3140 } else { 3141 while (ASCII_ISALPHA(*p)) { 3142 p++; 3143 } 3144 // for python 3.x support ":py3", ":python3", ":py3file", etc. 3145 if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y') { 3146 while (ASCII_ISALNUM(*p)) { 3147 p++; 3148 } 3149 } 3150 3151 // check for non-alpha command 3152 if (p == eap->cmd && vim_strchr("@!=><&~#", (uint8_t)(*p)) != NULL) { 3153 p++; 3154 } 3155 int len = (int)(p - eap->cmd); 3156 // The "d" command can directly be followed by 'l' or 'p' flag. 3157 if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) { 3158 // Check for ":dl", ":dell", etc. to ":deletel": that's 3159 // :delete with the 'l' flag. Same for 'p'. 3160 int i; 3161 for (i = 0; i < len; i++) { 3162 if (eap->cmd[i] != ("delete")[i]) { 3163 break; 3164 } 3165 } 3166 if (i == len - 1) { 3167 len--; 3168 if (p[-1] == 'l') { 3169 eap->flags |= EXFLAG_LIST; 3170 } else { 3171 eap->flags |= EXFLAG_PRINT; 3172 } 3173 } 3174 } 3175 3176 if (ASCII_ISLOWER(eap->cmd[0])) { 3177 const int c1 = (uint8_t)eap->cmd[0]; 3178 const int c2 = len == 1 ? NUL : eap->cmd[1]; 3179 3180 if (command_count != CMD_SIZE) { 3181 iemsg(_("E943: Command table needs to be updated, run 'make'")); 3182 getout(1); 3183 } 3184 3185 // Use a precomputed index for fast look-up in cmdnames[] 3186 // taking into account the first 2 letters of eap->cmd. 3187 eap->cmdidx = cmdidxs1[CHAR_ORD_LOW(c1)]; 3188 if (ASCII_ISLOWER(c2)) { 3189 eap->cmdidx += cmdidxs2[CHAR_ORD_LOW(c1)][CHAR_ORD_LOW(c2)]; 3190 } 3191 } else if (ASCII_ISUPPER(eap->cmd[0])) { 3192 eap->cmdidx = CMD_Next; 3193 } else { 3194 eap->cmdidx = CMD_bang; 3195 } 3196 assert(eap->cmdidx >= 0); 3197 3198 if (len == 3 && strncmp("def", eap->cmd, 3) == 0) { 3199 // Make :def an unknown command to avoid confusing behavior. #23149 3200 eap->cmdidx = CMD_SIZE; 3201 } 3202 3203 for (; (int)eap->cmdidx < CMD_SIZE; 3204 eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) { 3205 if (strncmp(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd, 3206 (size_t)len) == 0) { 3207 if (full != NULL 3208 && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) { 3209 *full = true; 3210 } 3211 break; 3212 } 3213 } 3214 3215 // Look for a user defined command as a last resort. 3216 if ((eap->cmdidx == CMD_SIZE) 3217 && *eap->cmd >= 'A' && *eap->cmd <= 'Z') { 3218 // User defined commands may contain digits. 3219 while (ASCII_ISALNUM(*p)) { 3220 p++; 3221 } 3222 p = find_ucmd(eap, p, full, NULL, NULL); 3223 } 3224 if (p == eap->cmd) { 3225 eap->cmdidx = CMD_SIZE; 3226 } 3227 } 3228 3229 return p; 3230 } 3231 3232 static struct cmdmod { 3233 char *name; 3234 int minlen; 3235 int has_count; // :123verbose :3tab 3236 } cmdmods[] = { 3237 { "aboveleft", 3, false }, 3238 { "belowright", 3, false }, 3239 { "botright", 2, false }, 3240 { "browse", 3, false }, 3241 { "confirm", 4, false }, 3242 { "filter", 4, false }, 3243 { "hide", 3, false }, 3244 { "horizontal", 3, false }, 3245 { "keepalt", 5, false }, 3246 { "keepjumps", 5, false }, 3247 { "keepmarks", 3, false }, 3248 { "keeppatterns", 5, false }, 3249 { "leftabove", 5, false }, 3250 { "lockmarks", 3, false }, 3251 { "noautocmd", 3, false }, 3252 { "noswapfile", 3, false }, 3253 { "rightbelow", 6, false }, 3254 { "sandbox", 3, false }, 3255 { "silent", 3, false }, 3256 { "tab", 3, true }, 3257 { "topleft", 2, false }, 3258 { "unsilent", 3, false }, 3259 { "verbose", 4, true }, 3260 { "vertical", 4, false }, 3261 }; 3262 3263 /// @return length of a command modifier (including optional count) or, 3264 /// zero when it's not a modifier. 3265 int modifier_len(char *cmd) 3266 { 3267 char *p = cmd; 3268 3269 if (ascii_isdigit(*cmd)) { 3270 p = skipwhite(skipdigits(cmd + 1)); 3271 } 3272 for (int i = 0; i < (int)ARRAY_SIZE(cmdmods); i++) { 3273 int j; 3274 for (j = 0; p[j] != NUL; j++) { 3275 if (p[j] != cmdmods[i].name[j]) { 3276 break; 3277 } 3278 } 3279 if (j >= cmdmods[i].minlen 3280 && !ASCII_ISALPHA(p[j]) 3281 && (p == cmd || cmdmods[i].has_count)) { 3282 return j + (int)(p - cmd); 3283 } 3284 } 3285 return 0; 3286 } 3287 3288 /// @return > 0 if an Ex command "name" exists or, 3289 /// 2 if there is an exact match or, 3290 /// 3 if there is an ambiguous match. 3291 int cmd_exists(const char *const name) 3292 { 3293 // Check command modifiers. 3294 for (int i = 0; i < (int)ARRAY_SIZE(cmdmods); i++) { 3295 int j; 3296 for (j = 0; name[j] != NUL; j++) { 3297 if (name[j] != cmdmods[i].name[j]) { 3298 break; 3299 } 3300 } 3301 if (name[j] == NUL && j >= cmdmods[i].minlen) { 3302 return cmdmods[i].name[j] == NUL ? 2 : 1; 3303 } 3304 } 3305 3306 // Check built-in commands and user defined commands. 3307 // For ":2match" and ":3match" we need to skip the number. 3308 exarg_T ea; 3309 ea.cmd = (char *)((*name == '2' || *name == '3') ? name + 1 : name); 3310 ea.cmdidx = 0; 3311 ea.flags = 0; 3312 int full = false; 3313 char *p = find_ex_command(&ea, &full); 3314 if (p == NULL) { 3315 return 3; 3316 } 3317 if (ascii_isdigit(*name) && ea.cmdidx != CMD_match) { 3318 return 0; 3319 } 3320 if (*skipwhite(p) != NUL) { 3321 return 0; // trailing garbage 3322 } 3323 return ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1); 3324 } 3325 3326 /// "fullcommand" function 3327 void f_fullcommand(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3328 { 3329 char *name = (char *)tv_get_string(&argvars[0]); 3330 3331 rettv->v_type = VAR_STRING; 3332 rettv->vval.v_string = NULL; 3333 3334 while (*name == ':') { 3335 name++; 3336 } 3337 name = skip_range(name, NULL); 3338 3339 exarg_T ea; 3340 ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; 3341 ea.cmdidx = 0; 3342 ea.flags = 0; 3343 char *p = find_ex_command(&ea, NULL); 3344 if (p == NULL || ea.cmdidx == CMD_SIZE) { 3345 return; 3346 } 3347 3348 rettv->vval.v_string = xstrdup(IS_USER_CMDIDX(ea.cmdidx) 3349 ? get_user_command_name(ea.useridx, ea.cmdidx) 3350 : cmdnames[ea.cmdidx].cmd_name); 3351 } 3352 3353 cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len) 3354 { 3355 if (len == 3 && strncmp("def", cmd, 3) == 0) { 3356 // Make :def an unknown command to avoid confusing behavior. #23149 3357 return CMD_SIZE; 3358 } 3359 3360 cmdidx_T idx; 3361 3362 if (!one_letter_cmd(cmd, &idx)) { 3363 for (idx = 0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) { 3364 if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) { 3365 break; 3366 } 3367 } 3368 } 3369 3370 return idx; 3371 } 3372 3373 uint32_t excmd_get_argt(cmdidx_T idx) 3374 { 3375 return cmdnames[(int)idx].cmd_argt; 3376 } 3377 3378 /// Skip a range specifier of the form: addr [,addr] [;addr] .. 3379 /// 3380 /// Backslashed delimiters after / or ? will be skipped, and commands will 3381 /// not be expanded between /'s and ?'s or after "'". 3382 /// 3383 /// Also skip white space and ":" characters. 3384 /// 3385 /// @param ctx pointer to xp_context or NULL 3386 /// 3387 /// @return the "cmd" pointer advanced to beyond the range. 3388 char *skip_range(const char *cmd, int *ctx) 3389 { 3390 while (vim_strchr(" \t0123456789.$%'/?-+,;\\", (uint8_t)(*cmd)) != NULL) { 3391 if (*cmd == '\\') { 3392 if (cmd[1] == '?' || cmd[1] == '/' || cmd[1] == '&') { 3393 cmd++; 3394 } else { 3395 break; 3396 } 3397 } else if (*cmd == '\'') { 3398 if (*++cmd == NUL && ctx != NULL) { 3399 *ctx = EXPAND_NOTHING; 3400 } 3401 } else if (*cmd == '/' || *cmd == '?') { 3402 unsigned delim = (unsigned)(*cmd++); 3403 while (*cmd != NUL && *cmd != (char)delim) { 3404 if (*cmd++ == '\\' && *cmd != NUL) { 3405 cmd++; 3406 } 3407 } 3408 if (*cmd == NUL && ctx != NULL) { 3409 *ctx = EXPAND_NOTHING; 3410 } 3411 } 3412 if (*cmd != NUL) { 3413 cmd++; 3414 } 3415 } 3416 3417 // Skip ":" and white space. 3418 cmd = skip_colon_white(cmd, false); 3419 3420 // Skip "*" used for Visual range. 3421 if (*cmd == '*') { 3422 cmd = skipwhite(cmd + 1); 3423 } 3424 3425 return (char *)cmd; 3426 } 3427 3428 static const char *addr_error(cmd_addr_T addr_type) 3429 { 3430 if (addr_type == ADDR_NONE) { 3431 return _(e_norange); 3432 } else { 3433 return _(e_invrange); 3434 } 3435 } 3436 3437 /// Gets a single EX address. 3438 /// 3439 /// Sets ptr to the next character after the part that was interpreted. 3440 /// Sets ptr to NULL when an error is encountered (stored in `errormsg`). 3441 /// May set the last used search pattern. 3442 /// 3443 /// @param skip only skip the address, don't use it 3444 /// @param silent no errors or side effects 3445 /// @param to_other_file flag: may jump to other file 3446 /// @param address_count 1 for first, >1 after comma 3447 /// @param errormsg Error message, if any 3448 /// 3449 /// @return MAXLNUM when no Ex address was found. 3450 linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool skip, bool silent, 3451 int to_other_file, int address_count, const char **errormsg) 3452 FUNC_ATTR_NONNULL_ARG(2, 8) 3453 { 3454 int c; 3455 int i; 3456 linenr_T n; 3457 pos_T pos; 3458 buf_T *buf; 3459 3460 char *cmd = skipwhite(*ptr); 3461 linenr_T lnum = MAXLNUM; 3462 do { 3463 switch (*cmd) { 3464 case '.': // '.' - Cursor position 3465 cmd++; 3466 switch (addr_type) { 3467 case ADDR_LINES: 3468 case ADDR_OTHER: 3469 lnum = curwin->w_cursor.lnum; 3470 break; 3471 case ADDR_WINDOWS: 3472 lnum = CURRENT_WIN_NR; 3473 break; 3474 case ADDR_ARGUMENTS: 3475 lnum = curwin->w_arg_idx + 1; 3476 break; 3477 case ADDR_LOADED_BUFFERS: 3478 case ADDR_BUFFERS: 3479 lnum = curbuf->b_fnum; 3480 break; 3481 case ADDR_TABS: 3482 lnum = CURRENT_TAB_NR; 3483 break; 3484 case ADDR_NONE: 3485 case ADDR_TABS_RELATIVE: 3486 case ADDR_UNSIGNED: 3487 *errormsg = addr_error(addr_type); 3488 cmd = NULL; 3489 goto error; 3490 break; 3491 case ADDR_QUICKFIX: 3492 lnum = (linenr_T)qf_get_cur_idx(eap); 3493 break; 3494 case ADDR_QUICKFIX_VALID: 3495 lnum = qf_get_cur_valid_idx(eap); 3496 break; 3497 } 3498 break; 3499 3500 case '$': // '$' - last line 3501 cmd++; 3502 switch (addr_type) { 3503 case ADDR_LINES: 3504 case ADDR_OTHER: 3505 lnum = curbuf->b_ml.ml_line_count; 3506 break; 3507 case ADDR_WINDOWS: 3508 lnum = LAST_WIN_NR; 3509 break; 3510 case ADDR_ARGUMENTS: 3511 lnum = ARGCOUNT; 3512 break; 3513 case ADDR_LOADED_BUFFERS: 3514 buf = lastbuf; 3515 while (buf->b_ml.ml_mfp == NULL) { 3516 if (buf->b_prev == NULL) { 3517 break; 3518 } 3519 buf = buf->b_prev; 3520 } 3521 lnum = buf->b_fnum; 3522 break; 3523 case ADDR_BUFFERS: 3524 lnum = lastbuf->b_fnum; 3525 break; 3526 case ADDR_TABS: 3527 lnum = LAST_TAB_NR; 3528 break; 3529 case ADDR_NONE: 3530 case ADDR_TABS_RELATIVE: 3531 case ADDR_UNSIGNED: 3532 *errormsg = addr_error(addr_type); 3533 cmd = NULL; 3534 goto error; 3535 break; 3536 case ADDR_QUICKFIX: 3537 lnum = (linenr_T)qf_get_size(eap); 3538 if (lnum == 0) { 3539 lnum = 1; 3540 } 3541 break; 3542 case ADDR_QUICKFIX_VALID: 3543 lnum = (linenr_T)qf_get_valid_size(eap); 3544 if (lnum == 0) { 3545 lnum = 1; 3546 } 3547 break; 3548 } 3549 break; 3550 3551 case '\'': // ''' - mark 3552 if (*++cmd == NUL) { 3553 cmd = NULL; 3554 goto error; 3555 } 3556 if (addr_type != ADDR_LINES) { 3557 *errormsg = addr_error(addr_type); 3558 cmd = NULL; 3559 goto error; 3560 } 3561 if (skip) { 3562 cmd++; 3563 } else { 3564 // Only accept a mark in another file when it is 3565 // used by itself: ":'M". 3566 MarkGet flag = to_other_file && cmd[1] == NUL ? kMarkAll : kMarkBufLocal; 3567 fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd); 3568 cmd++; 3569 if (fm != NULL && fm->fnum != curbuf->handle) { 3570 mark_move_to(fm, 0); 3571 // Jumped to another file. 3572 lnum = curwin->w_cursor.lnum; 3573 } else { 3574 if (!mark_check(fm, errormsg)) { 3575 cmd = NULL; 3576 goto error; 3577 } 3578 assert(fm != NULL); 3579 lnum = fm->mark.lnum; 3580 } 3581 } 3582 break; 3583 3584 case '/': 3585 case '?': // '/' or '?' - search 3586 c = (uint8_t)(*cmd++); 3587 if (addr_type != ADDR_LINES) { 3588 *errormsg = addr_error(addr_type); 3589 cmd = NULL; 3590 goto error; 3591 } 3592 if (skip) { // skip "/pat/" 3593 cmd = skip_regexp(cmd, c, magic_isset()); 3594 if (*cmd == c) { 3595 cmd++; 3596 } 3597 } else { 3598 int flags; 3599 3600 pos = curwin->w_cursor; // save curwin->w_cursor 3601 3602 // When '/' or '?' follows another address, start from 3603 // there. 3604 if (lnum > 0 && lnum != MAXLNUM) { 3605 curwin->w_cursor.lnum 3606 = lnum > curbuf->b_ml.ml_line_count ? curbuf->b_ml.ml_line_count : lnum; 3607 } 3608 3609 // Start a forward search at the end of the line (unless 3610 // before the first line). 3611 // Start a backward search at the start of the line. 3612 // This makes sure we never match in the current 3613 // line, and can match anywhere in the 3614 // next/previous line. 3615 curwin->w_cursor.col = (c == '/' && curwin->w_cursor.lnum > 0) ? MAXCOL : 0; 3616 searchcmdlen = 0; 3617 flags = silent ? SEARCH_KEEP : SEARCH_HIS | SEARCH_MSG; 3618 if (!do_search(NULL, c, c, cmd, strlen(cmd), 1, flags, NULL)) { 3619 curwin->w_cursor = pos; 3620 cmd = NULL; 3621 goto error; 3622 } 3623 lnum = curwin->w_cursor.lnum; 3624 curwin->w_cursor = pos; 3625 // adjust command string pointer 3626 cmd += searchcmdlen; 3627 } 3628 break; 3629 3630 case '\\': // "\?", "\/" or "\&", repeat search 3631 cmd++; 3632 if (addr_type != ADDR_LINES) { 3633 *errormsg = addr_error(addr_type); 3634 cmd = NULL; 3635 goto error; 3636 } 3637 if (*cmd == '&') { 3638 i = RE_SUBST; 3639 } else if (*cmd == '?' || *cmd == '/') { 3640 i = RE_SEARCH; 3641 } else { 3642 *errormsg = _(e_backslash); 3643 cmd = NULL; 3644 goto error; 3645 } 3646 3647 if (!skip) { 3648 // When search follows another address, start from there. 3649 pos.lnum = (lnum != MAXLNUM) ? lnum : curwin->w_cursor.lnum; 3650 // Start the search just like for the above do_search(). 3651 pos.col = (*cmd != '?') ? MAXCOL : 0; 3652 pos.coladd = 0; 3653 if (searchit(curwin, curbuf, &pos, NULL, 3654 *cmd == '?' ? BACKWARD : FORWARD, 3655 "", 0, 1, SEARCH_MSG, i, NULL) != FAIL) { 3656 lnum = pos.lnum; 3657 } else { 3658 cmd = NULL; 3659 goto error; 3660 } 3661 } 3662 cmd++; 3663 break; 3664 3665 default: 3666 if (ascii_isdigit(*cmd)) { // absolute line number 3667 lnum = (linenr_T)getdigits(&cmd, false, 0); 3668 } 3669 } 3670 3671 while (true) { 3672 cmd = skipwhite(cmd); 3673 if (*cmd != '-' && *cmd != '+' && !ascii_isdigit(*cmd)) { 3674 break; 3675 } 3676 3677 if (lnum == MAXLNUM) { 3678 switch (addr_type) { 3679 case ADDR_LINES: 3680 case ADDR_OTHER: 3681 // "+1" is same as ".+1" 3682 lnum = curwin->w_cursor.lnum; 3683 break; 3684 case ADDR_WINDOWS: 3685 lnum = CURRENT_WIN_NR; 3686 break; 3687 case ADDR_ARGUMENTS: 3688 lnum = curwin->w_arg_idx + 1; 3689 break; 3690 case ADDR_LOADED_BUFFERS: 3691 case ADDR_BUFFERS: 3692 lnum = curbuf->b_fnum; 3693 break; 3694 case ADDR_TABS: 3695 lnum = CURRENT_TAB_NR; 3696 break; 3697 case ADDR_TABS_RELATIVE: 3698 lnum = 1; 3699 break; 3700 case ADDR_QUICKFIX: 3701 lnum = (linenr_T)qf_get_cur_idx(eap); 3702 break; 3703 case ADDR_QUICKFIX_VALID: 3704 lnum = qf_get_cur_valid_idx(eap); 3705 break; 3706 case ADDR_NONE: 3707 case ADDR_UNSIGNED: 3708 lnum = 0; 3709 break; 3710 } 3711 } 3712 3713 if (ascii_isdigit(*cmd)) { 3714 i = '+'; // "number" is same as "+number" 3715 } else { 3716 i = (uint8_t)(*cmd++); 3717 } 3718 if (!ascii_isdigit(*cmd)) { // '+' is '+1' 3719 n = 1; 3720 } else { 3721 // "number", "+number" or "-number" 3722 n = getdigits_int32(&cmd, false, MAXLNUM); 3723 if (n == MAXLNUM) { 3724 *errormsg = _(e_line_number_out_of_range); 3725 cmd = NULL; 3726 goto error; 3727 } 3728 } 3729 3730 if (addr_type == ADDR_TABS_RELATIVE) { 3731 *errormsg = _(e_invrange); 3732 cmd = NULL; 3733 goto error; 3734 } else if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) { 3735 lnum = compute_buffer_local_count(addr_type, lnum, (i == '-') ? -1 * n : n); 3736 } else { 3737 // Relative line addressing: need to adjust for lines in a 3738 // closed fold after the first address. 3739 if (addr_type == ADDR_LINES && (i == '-' || i == '+') 3740 && address_count >= 2) { 3741 hasFolding(curwin, lnum, NULL, &lnum); 3742 } 3743 if (i == '-') { 3744 lnum -= n; 3745 } else { 3746 if (lnum >= 0 && n >= INT32_MAX - lnum) { 3747 *errormsg = _(e_line_number_out_of_range); 3748 cmd = NULL; 3749 goto error; 3750 } 3751 lnum += n; 3752 } 3753 } 3754 } 3755 } while (*cmd == '/' || *cmd == '?'); 3756 3757 error: 3758 *ptr = cmd; 3759 return lnum; 3760 } 3761 3762 /// Get flags from an Ex command argument. 3763 static void get_flags(exarg_T *eap) 3764 { 3765 while (vim_strchr("lp#", (uint8_t)(*eap->arg)) != NULL) { 3766 if (*eap->arg == 'l') { 3767 eap->flags |= EXFLAG_LIST; 3768 } else if (*eap->arg == 'p') { 3769 eap->flags |= EXFLAG_PRINT; 3770 } else { 3771 eap->flags |= EXFLAG_NR; 3772 } 3773 eap->arg = skipwhite(eap->arg + 1); 3774 } 3775 } 3776 3777 /// Stub function for command which is Not Implemented. NI! 3778 void ex_ni(exarg_T *eap) 3779 { 3780 if (!eap->skip) { 3781 eap->errmsg = _("E319: The command is not available in this version"); 3782 } 3783 } 3784 3785 /// Stub function for script command which is Not Implemented. NI! 3786 /// Skips over ":perl <<EOF" constructs. 3787 static void ex_script_ni(exarg_T *eap) 3788 { 3789 if (!eap->skip) { 3790 ex_ni(eap); 3791 } else { 3792 size_t len; 3793 xfree(script_get(eap, &len)); 3794 } 3795 } 3796 3797 /// Check range in Ex command for validity. 3798 /// 3799 /// @return NULL when valid, error message when invalid. 3800 char *invalid_range(exarg_T *eap) 3801 { 3802 buf_T *buf; 3803 if (eap->line1 < 0 || eap->line2 < 0 || eap->line1 > eap->line2) { 3804 return _(e_invrange); 3805 } 3806 3807 if (eap->argt & EX_RANGE) { 3808 switch (eap->addr_type) { 3809 case ADDR_LINES: 3810 if (eap->line2 > 3811 (curbuf->b_ml.ml_line_count 3812 + (eap->cmdidx == CMD_diffget || eap->cmdidx == CMD_diffput))) { 3813 return _(e_invrange); 3814 } 3815 break; 3816 case ADDR_ARGUMENTS: 3817 // add 1 if ARGCOUNT is 0 3818 if (eap->line2 > ARGCOUNT + (!ARGCOUNT)) { 3819 return _(e_invrange); 3820 } 3821 break; 3822 case ADDR_BUFFERS: 3823 // Only a boundary check, not whether the buffers actually 3824 // exist. 3825 if (eap->line1 < 1 || eap->line2 > get_highest_fnum()) { 3826 return _(e_invrange); 3827 } 3828 break; 3829 case ADDR_LOADED_BUFFERS: 3830 buf = firstbuf; 3831 while (buf->b_ml.ml_mfp == NULL) { 3832 if (buf->b_next == NULL) { 3833 return _(e_invrange); 3834 } 3835 buf = buf->b_next; 3836 } 3837 if (eap->line1 < buf->b_fnum) { 3838 return _(e_invrange); 3839 } 3840 buf = lastbuf; 3841 while (buf->b_ml.ml_mfp == NULL) { 3842 if (buf->b_prev == NULL) { 3843 return _(e_invrange); 3844 } 3845 buf = buf->b_prev; 3846 } 3847 if (eap->line2 > buf->b_fnum) { 3848 return _(e_invrange); 3849 } 3850 break; 3851 case ADDR_WINDOWS: 3852 if (eap->line2 > LAST_WIN_NR) { 3853 return _(e_invrange); 3854 } 3855 break; 3856 case ADDR_TABS: 3857 if (eap->line2 > LAST_TAB_NR) { 3858 return _(e_invrange); 3859 } 3860 break; 3861 case ADDR_TABS_RELATIVE: 3862 case ADDR_OTHER: 3863 // Any range is OK. 3864 break; 3865 case ADDR_QUICKFIX: 3866 assert(eap->line2 >= 0); 3867 // No error for value that is too big, will use the last entry. 3868 if (eap->line2 <= 0) { 3869 if (eap->addr_count == 0) { 3870 return _(e_no_errors); 3871 } 3872 return _(e_invrange); 3873 } 3874 break; 3875 case ADDR_QUICKFIX_VALID: 3876 if ((eap->line2 != 1 && (size_t)eap->line2 > qf_get_valid_size(eap)) 3877 || eap->line2 < 0) { 3878 return _(e_invrange); 3879 } 3880 break; 3881 case ADDR_UNSIGNED: 3882 case ADDR_NONE: 3883 // Will give an error elsewhere. 3884 break; 3885 } 3886 } 3887 return NULL; 3888 } 3889 3890 /// Correct the range for zero line number, if required. 3891 static void correct_range(exarg_T *eap) 3892 { 3893 if (!(eap->argt & EX_ZEROR)) { // zero in range not allowed 3894 if (eap->line1 == 0) { 3895 eap->line1 = 1; 3896 } 3897 if (eap->line2 == 0) { 3898 eap->line2 = 1; 3899 } 3900 } 3901 } 3902 3903 /// For a ":vimgrep" or ":vimgrepadd" command return a pointer past the 3904 /// pattern. Otherwise return eap->arg. 3905 static char *skip_grep_pat(exarg_T *eap) 3906 { 3907 char *p = eap->arg; 3908 3909 if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep 3910 || eap->cmdidx == CMD_vimgrepadd 3911 || eap->cmdidx == CMD_lvimgrepadd 3912 || grep_internal(eap->cmdidx))) { 3913 p = skip_vimgrep_pat(p, NULL, NULL); 3914 if (p == NULL) { 3915 p = eap->arg; 3916 } 3917 } 3918 return p; 3919 } 3920 3921 /// For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option 3922 /// in the command line, so that things like % get expanded. 3923 char *replace_makeprg(exarg_T *eap, char *arg, char **cmdlinep) 3924 { 3925 bool isgrep = eap->cmdidx == CMD_grep 3926 || eap->cmdidx == CMD_lgrep 3927 || eap->cmdidx == CMD_grepadd 3928 || eap->cmdidx == CMD_lgrepadd; 3929 3930 // Don't do it when ":vimgrep" is used for ":grep". 3931 if ((eap->cmdidx == CMD_make || eap->cmdidx == CMD_lmake || isgrep) 3932 && !grep_internal(eap->cmdidx)) { 3933 const char *program = isgrep ? (*curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) 3934 : (*curbuf->b_p_mp == NUL ? p_mp : curbuf->b_p_mp); 3935 3936 arg = skipwhite(arg); 3937 3938 char *new_cmdline; 3939 // Replace $* by given arguments 3940 if ((new_cmdline = strrep(program, "$*", arg)) == NULL) { 3941 // No $* in arg, build "<makeprg> <arg>" instead 3942 new_cmdline = xmalloc(strlen(program) + strlen(arg) + 2); 3943 STRCPY(new_cmdline, program); 3944 strcat(new_cmdline, " "); 3945 strcat(new_cmdline, arg); 3946 } 3947 3948 msg_make(arg); 3949 3950 // 'eap->cmd' is not set here, because it is not used at CMD_make 3951 xfree(*cmdlinep); 3952 *cmdlinep = new_cmdline; 3953 arg = new_cmdline; 3954 } 3955 return arg; 3956 } 3957 3958 /// Expand file name in Ex command argument. 3959 /// When an error is detected, "errormsgp" is set to a non-NULL pointer. 3960 /// 3961 /// @return FAIL for failure, OK otherwise. 3962 int expand_filename(exarg_T *eap, char **cmdlinep, const char **errormsgp) 3963 { 3964 // Skip a regexp pattern for ":vimgrep[add] pat file..." 3965 char *p = skip_grep_pat(eap); 3966 3967 // Decide to expand wildcards *before* replacing '%', '#', etc. If 3968 // the file name contains a wildcard it should not cause expanding. 3969 // (it will be expanded anyway if there is a wildcard before replacing). 3970 bool has_wildcards = path_has_wildcard(p); 3971 while (*p != NUL) { 3972 // Skip over `=expr`, wildcards in it are not expanded. 3973 if (p[0] == '`' && p[1] == '=') { 3974 p += 2; 3975 skip_expr(&p, NULL); 3976 if (*p == '`') { 3977 p++; 3978 } 3979 continue; 3980 } 3981 // Quick check if this cannot be the start of a special string. 3982 // Also removes backslash before '%', '#' and '<'. 3983 if (vim_strchr("%#<", (uint8_t)(*p)) == NULL) { 3984 p++; 3985 continue; 3986 } 3987 3988 // Try to find a match at this position. 3989 size_t srclen; 3990 int escaped; 3991 char *repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum), 3992 errormsgp, &escaped, true); 3993 if (*errormsgp != NULL) { // error detected 3994 return FAIL; 3995 } 3996 if (repl == NULL) { // no match found 3997 p += srclen; 3998 continue; 3999 } 4000 4001 // Wildcards won't be expanded below, the replacement is taken 4002 // literally. But do expand "~/file", "~user/file" and "$HOME/file". 4003 if (vim_strchr(repl, '$') != NULL || vim_strchr(repl, '~') != NULL) { 4004 char *l = repl; 4005 4006 repl = expand_env_save(repl); 4007 xfree(l); 4008 } 4009 4010 // Need to escape white space et al. with a backslash. 4011 // Don't do this for: 4012 // - replacement that already has been escaped: "##" 4013 // - shell commands (may have to use quotes instead). 4014 if (!eap->usefilter 4015 && !escaped 4016 && eap->cmdidx != CMD_bang 4017 && eap->cmdidx != CMD_grep 4018 && eap->cmdidx != CMD_grepadd 4019 && eap->cmdidx != CMD_lgrep 4020 && eap->cmdidx != CMD_lgrepadd 4021 && eap->cmdidx != CMD_lmake 4022 && eap->cmdidx != CMD_make 4023 && eap->cmdidx != CMD_terminal 4024 && !(eap->argt & EX_NOSPC)) { 4025 char *l; 4026 #ifdef BACKSLASH_IN_FILENAME 4027 // Don't escape a backslash here, because rem_backslash() doesn't 4028 // remove it later. 4029 static char *nobslash = " \t\"|"; 4030 # define ESCAPE_CHARS nobslash 4031 #else 4032 # define ESCAPE_CHARS escape_chars 4033 #endif 4034 4035 for (l = repl; *l; l++) { 4036 if (vim_strchr(ESCAPE_CHARS, (uint8_t)(*l)) != NULL) { 4037 l = vim_strsave_escaped(repl, ESCAPE_CHARS); 4038 xfree(repl); 4039 repl = l; 4040 break; 4041 } 4042 } 4043 } 4044 4045 // For a shell command a '!' must be escaped. 4046 if ((eap->usefilter 4047 || eap->cmdidx == CMD_bang 4048 || eap->cmdidx == CMD_terminal) 4049 && strpbrk(repl, "!") != NULL) { 4050 char *l = vim_strsave_escaped(repl, "!"); 4051 xfree(repl); 4052 repl = l; 4053 } 4054 4055 p = repl_cmdline(eap, p, srclen, repl, cmdlinep); 4056 xfree(repl); 4057 } 4058 4059 // One file argument: Expand wildcards. 4060 // Don't do this with ":r !command" or ":w !command". 4061 if ((eap->argt & EX_NOSPC) && !eap->usefilter) { 4062 // Replace environment variables. 4063 if (has_wildcards) { 4064 // May expand environment variables. This 4065 // can be done much faster with expand_env() than with 4066 // something else (e.g., calling a shell). 4067 // After expanding environment variables, check again 4068 // if there are still wildcards present. 4069 if (vim_strchr(eap->arg, '$') != NULL 4070 || vim_strchr(eap->arg, '~') != NULL) { 4071 expand_env_esc(eap->arg, NameBuff, MAXPATHL, true, true, NULL); 4072 has_wildcards = path_has_wildcard(NameBuff); 4073 p = NameBuff; 4074 } else { 4075 p = NULL; 4076 } 4077 if (p != NULL) { 4078 repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); 4079 } 4080 } 4081 4082 // Halve the number of backslashes (this is Vi compatible). 4083 // For Unix, when wildcards are expanded, this is 4084 // done by ExpandOne() below. 4085 #ifdef UNIX 4086 if (!has_wildcards) { 4087 backslash_halve(eap->arg); 4088 } 4089 #else 4090 backslash_halve(eap->arg); 4091 #endif 4092 4093 if (has_wildcards) { 4094 expand_T xpc; 4095 int options = WILD_LIST_NOTFOUND | WILD_NOERROR | WILD_ADD_SLASH; 4096 4097 ExpandInit(&xpc); 4098 xpc.xp_context = EXPAND_FILES; 4099 if (p_wic) { 4100 options += WILD_ICASE; 4101 } 4102 p = ExpandOne(&xpc, eap->arg, NULL, options, WILD_EXPAND_FREE); 4103 if (p == NULL) { 4104 return FAIL; 4105 } 4106 repl_cmdline(eap, eap->arg, strlen(eap->arg), p, cmdlinep); 4107 xfree(p); 4108 } 4109 } 4110 return OK; 4111 } 4112 4113 /// Replace part of the command line, keeping eap->cmd, eap->arg, eap->args and 4114 /// eap->nextcmd correct. 4115 /// "src" points to the part that is to be replaced, of length "srclen". 4116 /// "repl" is the replacement string. 4117 /// 4118 /// @return a pointer to the character after the replaced string. 4119 static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, char **cmdlinep) 4120 { 4121 // The new command line is build in new_cmdline[]. 4122 // First allocate it. 4123 // Careful: a "+cmd" argument may have been NUL terminated. 4124 size_t len = strlen(repl); 4125 size_t i = (size_t)(src - *cmdlinep) + strlen(src + srclen) + len + 3; 4126 if (eap->nextcmd != NULL) { 4127 i += strlen(eap->nextcmd); // add space for next command 4128 } 4129 char *new_cmdline = xmalloc(i); 4130 size_t offset = (size_t)(src - *cmdlinep); 4131 4132 // Copy the stuff before the expanded part. 4133 // Copy the expanded stuff. 4134 // Copy what came after the expanded part. 4135 // Copy the next commands, if there are any. 4136 i = offset; // length of part before match 4137 memmove(new_cmdline, *cmdlinep, i); 4138 4139 memmove(new_cmdline + i, repl, len); 4140 i += len; // remember the end of the string 4141 STRCPY(new_cmdline + i, src + srclen); 4142 src = new_cmdline + i; // remember where to continue 4143 4144 if (eap->nextcmd != NULL) { // append next command 4145 i = strlen(new_cmdline) + 1; 4146 STRCPY(new_cmdline + i, eap->nextcmd); 4147 eap->nextcmd = new_cmdline + i; 4148 } 4149 eap->cmd = new_cmdline + (eap->cmd - *cmdlinep); 4150 eap->arg = new_cmdline + (eap->arg - *cmdlinep); 4151 4152 for (size_t j = 0; j < eap->argc; j++) { 4153 if (offset >= (size_t)(eap->args[j] - *cmdlinep)) { 4154 // If replaced text is after or in the same position as the argument, 4155 // the argument's position relative to the beginning of the cmdline stays the same. 4156 eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep); 4157 } else { 4158 // Otherwise, argument gets shifted alongside the replaced text. 4159 // The amount of the shift is equal to the difference of the old and new string length. 4160 eap->args[j] = new_cmdline + ((eap->args[j] - *cmdlinep) + (ptrdiff_t)(len - srclen)); 4161 } 4162 } 4163 4164 if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) { 4165 eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep); 4166 } 4167 xfree(*cmdlinep); 4168 *cmdlinep = new_cmdline; 4169 4170 return src; 4171 } 4172 4173 /// Check for '|' to separate commands and '"' to start comments. 4174 void separate_nextcmd(exarg_T *eap) 4175 { 4176 char *p = skip_grep_pat(eap); 4177 4178 for (; *p; MB_PTR_ADV(p)) { 4179 if (*p == Ctrl_V) { 4180 if (eap->argt & (EX_CTRLV | EX_XFILE)) { 4181 p++; // skip CTRL-V and next char 4182 } else { 4183 // remove CTRL-V and skip next char 4184 STRMOVE(p, p + 1); 4185 } 4186 if (*p == NUL) { // stop at NUL after CTRL-V 4187 break; 4188 } 4189 } else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) { 4190 // Skip over `=expr` when wildcards are expanded. 4191 p += 2; 4192 skip_expr(&p, NULL); 4193 if (*p == NUL) { // stop at NUL after CTRL-V 4194 break; 4195 } 4196 } else if ( 4197 // Check for '"': start of comment or '|': next command 4198 // :@" does not start a comment! 4199 // :redir @" doesn't either. 4200 (*p == '"' 4201 && !(eap->argt & EX_NOTRLCOM) 4202 && (eap->cmdidx != CMD_at || p != eap->arg) 4203 && (eap->cmdidx != CMD_redir 4204 || p != eap->arg + 1 || p[-1] != '@')) 4205 || (*p == '|' 4206 && eap->cmdidx != CMD_append 4207 && eap->cmdidx != CMD_change 4208 && eap->cmdidx != CMD_insert) 4209 || *p == '\n') { 4210 // We remove the '\' before the '|', unless EX_CTRLV is used 4211 // AND 'b' is present in 'cpoptions'. 4212 if ((vim_strchr(p_cpo, CPO_BAR) == NULL 4213 || !(eap->argt & EX_CTRLV)) && *(p - 1) == '\\') { 4214 STRMOVE(p - 1, p); // remove the '\' 4215 p--; 4216 } else { 4217 eap->nextcmd = check_nextcmd(p); 4218 *p = NUL; 4219 break; 4220 } 4221 } 4222 } 4223 4224 if (!(eap->argt & EX_NOTRLCOM)) { // remove trailing spaces 4225 del_trailing_spaces(eap->arg); 4226 } 4227 } 4228 4229 /// get + command from ex argument 4230 char *getargcmd(char **argp) 4231 { 4232 char *arg = *argp; 4233 char *command = NULL; 4234 4235 if (*arg == '+') { // +[command] 4236 arg++; 4237 if (ascii_isspace(*arg) || *arg == NUL) { 4238 command = dollar_command; 4239 } else { 4240 command = arg; 4241 arg = skip_cmd_arg(command, true); 4242 if (*arg != NUL) { 4243 *arg++ = NUL; // terminate command with NUL 4244 } 4245 } 4246 4247 arg = skipwhite(arg); // skip over spaces 4248 *argp = arg; 4249 } 4250 return command; 4251 } 4252 4253 /// Find end of "+command" argument. Skip over "\ " and "\\". 4254 /// 4255 /// @param rembs true to halve the number of backslashes 4256 char *skip_cmd_arg(char *p, bool rembs) 4257 { 4258 while (*p && !ascii_isspace(*p)) { 4259 if (*p == '\\' && p[1] != NUL) { 4260 if (rembs) { 4261 STRMOVE(p, p + 1); 4262 } else { 4263 p++; 4264 } 4265 } 4266 MB_PTR_ADV(p); 4267 } 4268 return p; 4269 } 4270 4271 int get_bad_opt(const char *p, exarg_T *eap) 4272 FUNC_ATTR_NONNULL_ALL 4273 { 4274 if (STRICMP(p, "keep") == 0) { 4275 eap->bad_char = BAD_KEEP; 4276 } else if (STRICMP(p, "drop") == 0) { 4277 eap->bad_char = BAD_DROP; 4278 } else if (MB_BYTE2LEN((uint8_t)(*p)) == 1 && p[1] == NUL) { 4279 eap->bad_char = (uint8_t)(*p); 4280 } else { 4281 return FAIL; 4282 } 4283 return OK; 4284 } 4285 4286 /// Function given to ExpandGeneric() to obtain the list of bad= names. 4287 static char *get_bad_name(expand_T *xp FUNC_ATTR_UNUSED, int idx) 4288 { 4289 // Note: Keep this in sync with get_bad_opt(). 4290 static char *(p_bad_values[]) = { 4291 "?", 4292 "keep", 4293 "drop", 4294 }; 4295 4296 if (idx < (int)ARRAY_SIZE(p_bad_values)) { 4297 return p_bad_values[idx]; 4298 } 4299 return NULL; 4300 } 4301 4302 /// Get "++opt=arg" argument. 4303 /// 4304 /// @return FAIL or OK. 4305 int getargopt(exarg_T *eap) 4306 { 4307 char *arg = eap->arg + 2; 4308 int *pp = NULL; 4309 int bad_char_idx; 4310 4311 // Note: Keep this in sync with get_argopt_name. 4312 4313 // ":edit ++[no]bin[ary] file" 4314 if (strncmp(arg, "bin", 3) == 0 || strncmp(arg, "nobin", 5) == 0) { 4315 if (*arg == 'n') { 4316 arg += 2; 4317 eap->force_bin = FORCE_NOBIN; 4318 } else { 4319 eap->force_bin = FORCE_BIN; 4320 } 4321 if (!checkforcmd(&arg, "binary", 3)) { 4322 return FAIL; 4323 } 4324 eap->arg = skipwhite(arg); 4325 return OK; 4326 } 4327 4328 // ":read ++edit file" 4329 if (strncmp(arg, "edit", 4) == 0) { 4330 eap->read_edit = true; 4331 eap->arg = skipwhite(arg + 4); 4332 return OK; 4333 } 4334 4335 // ":write ++p foo/bar/file 4336 if (strncmp(arg, "p", 1) == 0) { 4337 eap->mkdir_p = true; 4338 eap->arg = skipwhite(arg + 1); 4339 return OK; 4340 } 4341 4342 if (strncmp(arg, "ff", 2) == 0) { 4343 arg += 2; 4344 pp = &eap->force_ff; 4345 } else if (strncmp(arg, "fileformat", 10) == 0) { 4346 arg += 10; 4347 pp = &eap->force_ff; 4348 } else if (strncmp(arg, "enc", 3) == 0) { 4349 if (strncmp(arg, "encoding", 8) == 0) { 4350 arg += 8; 4351 } else { 4352 arg += 3; 4353 } 4354 pp = &eap->force_enc; 4355 } else if (strncmp(arg, "bad", 3) == 0) { 4356 arg += 3; 4357 pp = &bad_char_idx; 4358 } 4359 4360 if (pp == NULL || *arg != '=') { 4361 return FAIL; 4362 } 4363 4364 arg++; 4365 *pp = (int)(arg - eap->cmd); 4366 arg = skip_cmd_arg(arg, false); 4367 eap->arg = skipwhite(arg); 4368 *arg = NUL; 4369 4370 if (pp == &eap->force_ff) { 4371 if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) { 4372 return FAIL; 4373 } 4374 eap->force_ff = (uint8_t)eap->cmd[eap->force_ff]; 4375 } else if (pp == &eap->force_enc) { 4376 // Make 'fileencoding' lower case. 4377 for (char *p = eap->cmd + eap->force_enc; *p != NUL; p++) { 4378 *p = (char)TOLOWER_ASC(*p); 4379 } 4380 } else { 4381 // Check ++bad= argument. Must be a single-byte character, "keep" or 4382 // "drop". 4383 if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL) { 4384 return FAIL; 4385 } 4386 } 4387 4388 return OK; 4389 } 4390 4391 /// Function given to ExpandGeneric() to obtain the list of ++opt names. 4392 static char *get_argopt_name(expand_T *xp FUNC_ATTR_UNUSED, int idx) 4393 { 4394 // Note: Keep this in sync with getargopt(). 4395 static char *(p_opt_values[]) = { 4396 "fileformat=", 4397 "encoding=", 4398 "binary", 4399 "nobinary", 4400 "bad=", 4401 "edit", 4402 "p", 4403 }; 4404 4405 if (idx < (int)ARRAY_SIZE(p_opt_values)) { 4406 return p_opt_values[idx]; 4407 } 4408 return NULL; 4409 } 4410 4411 /// Command-line expansion for ++opt=name. 4412 int expand_argopt(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches, int *numMatches) 4413 { 4414 if (xp->xp_pattern > xp->xp_line && *(xp->xp_pattern - 1) == '=') { 4415 CompleteListItemGetter cb = NULL; 4416 4417 char *name_end = xp->xp_pattern - 1; 4418 if (name_end - xp->xp_line >= 2 4419 && strncmp(name_end - 2, "ff", 2) == 0) { 4420 cb = get_fileformat_name; 4421 } else if (name_end - xp->xp_line >= 10 4422 && strncmp(name_end - 10, "fileformat", 10) == 0) { 4423 cb = get_fileformat_name; 4424 } else if (name_end - xp->xp_line >= 3 4425 && strncmp(name_end - 3, "enc", 3) == 0) { 4426 cb = get_encoding_name; 4427 } else if (name_end - xp->xp_line >= 8 4428 && strncmp(name_end - 8, "encoding", 8) == 0) { 4429 cb = get_encoding_name; 4430 } else if (name_end - xp->xp_line >= 3 4431 && strncmp(name_end - 3, "bad", 3) == 0) { 4432 cb = get_bad_name; 4433 } 4434 4435 if (cb != NULL) { 4436 ExpandGeneric(pat, xp, rmp, matches, numMatches, cb, false); 4437 return OK; 4438 } 4439 return FAIL; 4440 } 4441 4442 // Special handling of "ff" which acts as a short form of 4443 // "fileformat", as "ff" is not a substring of it. 4444 if (xp->xp_pattern_len == 2 4445 && strncmp(xp->xp_pattern, "ff", xp->xp_pattern_len) == 0) { 4446 *matches = xmalloc(sizeof(char *)); 4447 *numMatches = 1; 4448 (*matches)[0] = xstrdup("fileformat="); 4449 return OK; 4450 } 4451 4452 ExpandGeneric(pat, xp, rmp, matches, numMatches, get_argopt_name, false); 4453 return OK; 4454 } 4455 4456 /// Handle the argument for a tabpage related ex command. 4457 /// When an error is encountered then eap->errmsg is set. 4458 /// 4459 /// @return a tabpage number. 4460 static int get_tabpage_arg(exarg_T *eap) 4461 { 4462 int tab_number = 0; 4463 int unaccept_arg0 = (eap->cmdidx == CMD_tabmove) ? 0 : 1; 4464 4465 if (eap->arg && *eap->arg != NUL) { 4466 char *p = eap->arg; 4467 int relative = 0; // argument +N/-N means: go to N places to the 4468 // right/left relative to the current position. 4469 4470 if (*p == '-') { 4471 relative = -1; 4472 p++; 4473 } else if (*p == '+') { 4474 relative = 1; 4475 p++; 4476 } 4477 4478 char *p_save = p; 4479 tab_number = (int)getdigits(&p, false, tab_number); 4480 4481 if (relative == 0) { 4482 if (strcmp(p, "$") == 0) { 4483 tab_number = LAST_TAB_NR; 4484 } else if (strcmp(p, "#") == 0) { 4485 if (valid_tabpage(lastused_tabpage)) { 4486 tab_number = tabpage_index(lastused_tabpage); 4487 } else { 4488 eap->errmsg = ex_errmsg(e_invargval, eap->arg); 4489 tab_number = 0; 4490 goto theend; 4491 } 4492 } else if (p == p_save || *p_save == '-' || *p != NUL 4493 || tab_number > LAST_TAB_NR) { 4494 // No numbers as argument. 4495 eap->errmsg = ex_errmsg(e_invarg2, eap->arg); 4496 goto theend; 4497 } 4498 } else { 4499 if (*p_save == NUL) { 4500 tab_number = 1; 4501 } else if (p == p_save || *p_save == '-' || *p != NUL || tab_number == 0) { 4502 // No numbers as argument. 4503 eap->errmsg = ex_errmsg(e_invarg2, eap->arg); 4504 goto theend; 4505 } 4506 tab_number = tab_number * relative + tabpage_index(curtab); 4507 if (!unaccept_arg0 && relative == -1) { 4508 tab_number--; 4509 } 4510 } 4511 if (tab_number < unaccept_arg0 || tab_number > LAST_TAB_NR) { 4512 eap->errmsg = ex_errmsg(e_invarg2, eap->arg); 4513 } 4514 } else if (eap->addr_count > 0) { 4515 if (unaccept_arg0 && eap->line2 == 0) { 4516 eap->errmsg = _(e_invrange); 4517 tab_number = 0; 4518 } else { 4519 tab_number = (int)eap->line2; 4520 if (!unaccept_arg0) { 4521 char *cmdp = eap->cmd; 4522 while (--cmdp > *eap->cmdlinep 4523 && (ascii_iswhite(*cmdp) || ascii_isdigit(*cmdp))) {} 4524 if (*cmdp == '-') { 4525 tab_number--; 4526 if (tab_number < unaccept_arg0) { 4527 eap->errmsg = _(e_invrange); 4528 } 4529 } 4530 } 4531 } 4532 } else { 4533 switch (eap->cmdidx) { 4534 case CMD_tabnext: 4535 tab_number = tabpage_index(curtab) + 1; 4536 if (tab_number > LAST_TAB_NR) { 4537 tab_number = 1; 4538 } 4539 break; 4540 case CMD_tabmove: 4541 tab_number = LAST_TAB_NR; 4542 break; 4543 default: 4544 tab_number = tabpage_index(curtab); 4545 } 4546 } 4547 4548 theend: 4549 return tab_number; 4550 } 4551 4552 static void ex_autocmd(exarg_T *eap) 4553 { 4554 // Disallow autocommands in secure mode. 4555 if (secure) { 4556 secure = 2; 4557 eap->errmsg = _(e_curdir); 4558 } else if (eap->cmdidx == CMD_autocmd) { 4559 do_autocmd(eap, eap->arg, eap->forceit); 4560 } else { 4561 do_augroup(eap->arg, eap->forceit); 4562 } 4563 } 4564 4565 /// ":doautocmd": Apply the automatic commands to the current buffer. 4566 static void ex_doautocmd(exarg_T *eap) 4567 { 4568 char *arg = eap->arg; 4569 int call_do_modelines = check_nomodeline(&arg); 4570 bool did_aucmd; 4571 4572 do_doautocmd(arg, false, &did_aucmd); 4573 // Only when there is no <nomodeline>. 4574 if (call_do_modelines && did_aucmd) { 4575 do_modelines(0); 4576 } 4577 } 4578 4579 /// :[N]bunload[!] [N] [bufname] unload buffer 4580 /// :[N]bdelete[!] [N] [bufname] delete buffer from buffer list 4581 /// :[N]bwipeout[!] [N] [bufname] delete buffer really 4582 static void ex_bunload(exarg_T *eap) 4583 { 4584 eap->errmsg = do_bufdel(eap->cmdidx == CMD_bdelete 4585 ? DOBUF_DEL 4586 : eap->cmdidx == CMD_bwipeout 4587 ? DOBUF_WIPE 4588 : DOBUF_UNLOAD, 4589 eap->arg, eap->addr_count, (int)eap->line1, (int)eap->line2, 4590 eap->forceit); 4591 } 4592 4593 /// :[N]buffer [N] to buffer N 4594 /// :[N]sbuffer [N] to buffer N 4595 static void ex_buffer(exarg_T *eap) 4596 { 4597 do_exbuffer(eap); 4598 } 4599 4600 /// ":buffer" command and alike. 4601 static void do_exbuffer(exarg_T *eap) 4602 { 4603 if (*eap->arg) { 4604 eap->errmsg = ex_errmsg(e_trailing_arg, eap->arg); 4605 } else { 4606 if (eap->addr_count == 0) { // default is current buffer 4607 goto_buffer(eap, DOBUF_CURRENT, FORWARD, 0); 4608 } else { 4609 goto_buffer(eap, DOBUF_FIRST, FORWARD, (int)eap->line2); 4610 } 4611 if (eap->do_ecmd_cmd != NULL) { 4612 do_cmdline_cmd(eap->do_ecmd_cmd); 4613 } 4614 } 4615 } 4616 4617 /// :[N]bmodified [N] to next mod. buffer 4618 /// :[N]sbmodified [N] to next mod. buffer 4619 static void ex_bmodified(exarg_T *eap) 4620 { 4621 goto_buffer(eap, DOBUF_MOD, FORWARD, (int)eap->line2); 4622 if (eap->do_ecmd_cmd != NULL) { 4623 do_cmdline_cmd(eap->do_ecmd_cmd); 4624 } 4625 } 4626 4627 /// :[N]bnext [N] to next buffer 4628 /// :[N]sbnext [N] split and to next buffer 4629 static void ex_bnext(exarg_T *eap) 4630 { 4631 goto_buffer(eap, DOBUF_CURRENT, FORWARD, (int)eap->line2); 4632 if (eap->do_ecmd_cmd != NULL) { 4633 do_cmdline_cmd(eap->do_ecmd_cmd); 4634 } 4635 } 4636 4637 /// :[N]bNext [N] to previous buffer 4638 /// :[N]bprevious [N] to previous buffer 4639 /// :[N]sbNext [N] split and to previous buffer 4640 /// :[N]sbprevious [N] split and to previous buffer 4641 static void ex_bprevious(exarg_T *eap) 4642 { 4643 goto_buffer(eap, DOBUF_CURRENT, BACKWARD, (int)eap->line2); 4644 if (eap->do_ecmd_cmd != NULL) { 4645 do_cmdline_cmd(eap->do_ecmd_cmd); 4646 } 4647 } 4648 4649 /// :brewind to first buffer 4650 /// :bfirst to first buffer 4651 /// :sbrewind split and to first buffer 4652 /// :sbfirst split and to first buffer 4653 static void ex_brewind(exarg_T *eap) 4654 { 4655 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); 4656 if (eap->do_ecmd_cmd != NULL) { 4657 do_cmdline_cmd(eap->do_ecmd_cmd); 4658 } 4659 } 4660 4661 /// :blast to last buffer 4662 /// :sblast split and to last buffer 4663 static void ex_blast(exarg_T *eap) 4664 { 4665 goto_buffer(eap, DOBUF_LAST, BACKWARD, 0); 4666 if (eap->do_ecmd_cmd != NULL) { 4667 do_cmdline_cmd(eap->do_ecmd_cmd); 4668 } 4669 } 4670 4671 int ends_excmd(int c) FUNC_ATTR_CONST 4672 { 4673 return c == NUL || c == '|' || c == '"' || c == '\n'; 4674 } 4675 4676 /// @return the next command, after the first '|' or '\n' or, 4677 /// NULL if not found. 4678 char *find_nextcmd(const char *p) 4679 { 4680 while (*p != '|' && *p != '\n') { 4681 if (*p == NUL) { 4682 return NULL; 4683 } 4684 p++; 4685 } 4686 return (char *)p + 1; 4687 } 4688 4689 /// Check if *p is a separator between Ex commands, skipping over white space. 4690 /// 4691 /// @return NULL if it isn't, the following character if it is. 4692 char *check_nextcmd(char *p) 4693 { 4694 char *s = skipwhite(p); 4695 4696 if (*s == '|' || *s == '\n') { 4697 return s + 1; 4698 } 4699 return NULL; 4700 } 4701 4702 /// - if there are more files to edit 4703 /// - and this is the last window 4704 /// - and forceit not used 4705 /// - and not repeated twice on a row 4706 /// 4707 /// @param message when false check only, no messages 4708 /// 4709 /// @return FAIL and give error message if 'message' true, return OK otherwise 4710 static int check_more(bool message, bool forceit) 4711 { 4712 int n = ARGCOUNT - curwin->w_arg_idx - 1; 4713 4714 if (!forceit && only_one_window() 4715 && ARGCOUNT > 1 && !arg_had_last && n > 0 && quitmore == 0) { 4716 if (message) { 4717 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && curbuf->b_fname != NULL) { 4718 char buff[DIALOG_MSG_SIZE]; 4719 4720 vim_snprintf(buff, DIALOG_MSG_SIZE, 4721 NGETTEXT("%d more file to edit. Quit anyway?", 4722 "%d more files to edit. Quit anyway?", n), n); 4723 if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) { 4724 return OK; 4725 } 4726 return FAIL; 4727 } 4728 semsg(NGETTEXT("E173: %d more file to edit", 4729 "E173: %d more files to edit", n), n); 4730 quitmore = 2; // next try to quit is allowed 4731 } 4732 return FAIL; 4733 } 4734 return OK; 4735 } 4736 4737 /// Function given to ExpandGeneric() to obtain the list of command names. 4738 char *get_command_name(expand_T *xp, int idx) 4739 { 4740 if (idx >= CMD_SIZE) { 4741 return expand_user_command_name(idx); 4742 } 4743 return cmdnames[idx].cmd_name; 4744 } 4745 4746 static void ex_colorscheme(exarg_T *eap) 4747 { 4748 if (*eap->arg == NUL) { 4749 char *expr = xstrdup("g:colors_name"); 4750 4751 emsg_off++; 4752 char *p = eval_to_string(expr, false, false); 4753 emsg_off--; 4754 xfree(expr); 4755 4756 msg_ext_set_kind("list_cmd"); 4757 if (p != NULL) { 4758 msg(p, 0); 4759 xfree(p); 4760 } else { 4761 msg("default", 0); 4762 } 4763 } else if (load_colors(eap->arg) == FAIL) { 4764 semsg(_("E185: Cannot find color scheme '%s'"), eap->arg); 4765 } 4766 } 4767 4768 static void ex_highlight(exarg_T *eap) 4769 { 4770 if (*eap->arg == NUL && eap->cmd[2] == '!') { 4771 msg(_("Greetings, Vim user!"), 0); 4772 } 4773 do_highlight(eap->arg, eap->forceit, false); 4774 } 4775 4776 /// Call this function if we thought we were going to exit, but we won't 4777 /// (because of an error). May need to restore the terminal mode. 4778 void not_exiting(bool save_exiting) 4779 { 4780 exiting = save_exiting; 4781 } 4782 4783 /// Call this function if we thought we were going to restart, but we won't 4784 /// (because of an error). 4785 void not_restarting(void) 4786 { 4787 restarting = false; 4788 } 4789 4790 bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit) 4791 { 4792 apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer); 4793 4794 // Bail out when autocommands closed the window. 4795 // Refuse to quit when the buffer in the last window is being closed (can 4796 // only happen in autocommands). 4797 if (!win_valid(wp) 4798 || curbuf_locked() 4799 || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0)) { 4800 return true; 4801 } 4802 4803 if (quit_all 4804 || (check_more(false, forceit) == OK && only_one_window())) { 4805 apply_autocmds(EVENT_EXITPRE, NULL, NULL, false, curbuf); 4806 // Refuse to quit when locked or when the window was closed or the 4807 // buffer in the last window is being closed (can only happen in 4808 // autocommands). 4809 if (!win_valid(wp) 4810 || curbuf_locked() 4811 || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) { 4812 return true; 4813 } 4814 } 4815 4816 return false; 4817 } 4818 4819 /// ":quit": quit current window, quit Vim if the last window is closed. 4820 /// ":{nr}quit": quit window {nr} 4821 static void ex_quit(exarg_T *eap) 4822 { 4823 if (cmdwin_type != 0) { 4824 cmdwin_result = Ctrl_C; 4825 return; 4826 } 4827 // Don't quit while editing the command line. 4828 if (text_locked()) { 4829 text_locked_msg(); 4830 return; 4831 } 4832 4833 win_T *wp; 4834 4835 if (eap->addr_count > 0) { 4836 linenr_T wnr = eap->line2; 4837 4838 for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next) { 4839 if (--wnr <= 0) { 4840 break; 4841 } 4842 } 4843 } else { 4844 wp = curwin; 4845 } 4846 4847 // Refuse to quit when locked. 4848 if (curbuf_locked()) { 4849 return; 4850 } 4851 4852 // Trigger QuitPre and maybe ExitPre 4853 if (before_quit_autocmds(wp, false, eap->forceit)) { 4854 return; 4855 } 4856 4857 bool save_exiting = exiting; 4858 // If there is only one relevant window we will exit. 4859 if (check_more(false, eap->forceit) == OK && only_one_window()) { 4860 exiting = true; 4861 } 4862 if ((!buf_hide(wp->w_buffer) 4863 && check_changed(wp->w_buffer, (p_awa ? CCGD_AW : 0) 4864 | (eap->forceit ? CCGD_FORCEIT : 0) 4865 | CCGD_EXCMD)) 4866 || check_more(true, eap->forceit) == FAIL 4867 || (only_one_window() && check_changed_any(eap->forceit, true))) { 4868 not_exiting(save_exiting); 4869 } else { 4870 // quit last window 4871 // Note: only_one_window() returns true, even so a help window is 4872 // still open. In that case only quit, if no address has been 4873 // specified. Example: 4874 // :h|wincmd w|1q - don't quit 4875 // :h|wincmd w|q - quit 4876 if (only_one_window() && (ONE_WINDOW || eap->addr_count == 0)) { 4877 getout(0); 4878 } 4879 not_exiting(save_exiting); 4880 // close window; may free buffer 4881 win_close(wp, !buf_hide(wp->w_buffer) || eap->forceit, eap->forceit); 4882 } 4883 } 4884 4885 /// ":cquit". 4886 static void ex_cquit(exarg_T *eap) 4887 FUNC_ATTR_NORETURN 4888 { 4889 // this does not always pass on the exit code to the Manx compiler. why? 4890 int status = eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE; 4891 ui_call_error_exit(status); 4892 getout(status); 4893 } 4894 4895 /// Do preparations for "qall" and "wqall". 4896 /// Returns FAIL when quitting should be aborted. 4897 int before_quit_all(exarg_T *eap) 4898 { 4899 if (cmdwin_type != 0) { 4900 cmdwin_result = eap->forceit 4901 ? K_XF1 // open_cmdwin() takes care of this 4902 : K_XF2; 4903 return FAIL; 4904 } 4905 4906 // Don't quit while editing the command line. 4907 if (text_locked()) { 4908 text_locked_msg(); 4909 return FAIL; 4910 } 4911 4912 if (before_quit_autocmds(curwin, true, eap->forceit)) { 4913 return FAIL; 4914 } 4915 4916 return OK; 4917 } 4918 4919 /// ":qall": try to quit all windows 4920 static void ex_quitall(exarg_T *eap) 4921 { 4922 if (before_quit_all(eap) == FAIL) { 4923 return; 4924 } 4925 bool save_exiting = exiting; 4926 exiting = true; 4927 if (eap->forceit || !check_changed_any(false, false)) { 4928 getout(0); 4929 } 4930 not_exiting(save_exiting); 4931 } 4932 4933 /// ":restart": restart the Nvim server (using ":qall!"). 4934 /// ":restart +cmd": restart the Nvim server using ":cmd". 4935 /// ":restart +cmd <command>": restart the Nvim server using ":cmd" and add -c <command> to the new server. 4936 static void ex_restart(exarg_T *eap) 4937 { 4938 const list_T *l = get_vim_var_list(VV_ARGV); 4939 int argc = tv_list_len(l); 4940 list_T *argv_cpy = tv_list_alloc(eap->arg ? argc + 2 : argc); 4941 4942 // Copy v:argv, skipping unwanted items. 4943 for (listitem_T *li = l != NULL ? l->lv_first : NULL; li != NULL; li = li->li_next) { 4944 const char *arg = tv_get_string(TV_LIST_ITEM_TV(li)); 4945 size_t arg_size = strlen(arg); 4946 assert(arg_size <= (size_t)SSIZE_MAX); 4947 4948 if (strequal(arg, "--embed") || strequal(arg, "--headless")) { 4949 continue; // Drop --embed/--headless: the client decides how to start+attach the server. 4950 } else if (strequal(arg, "-")) { 4951 continue; // Drop stdin ("-") argument. 4952 } else if (strequal(arg, "-s")) { 4953 // Drop "-s <scriptfile>": skip the scriptfile arg too. 4954 if (li->li_next != NULL) { 4955 li = li->li_next; 4956 } 4957 continue; 4958 } else if (strequal(arg, "+:::")) { 4959 // The special placeholder "+:::" marks a previous :restart command. 4960 // Drop the `"+:::", "-c", "…"` triplet, to avoid "stacking" commands from previous :restart(s). 4961 listitem_T *next1 = li->li_next; 4962 if (next1 != NULL && strequal(tv_get_string(TV_LIST_ITEM_TV(next1)), "-c")) { 4963 listitem_T *next2 = next1->li_next; 4964 if (next2 != NULL) { 4965 li = next2; 4966 continue; 4967 } 4968 } 4969 continue; // If the triplet is incomplete, just skip "+:::" 4970 } else if (strequal(arg, "--")) { 4971 break; // Drop "-- [files…]". Usually isn't wanted. User can :mksession instead. 4972 } 4973 4974 tv_list_append_string(argv_cpy, arg, (ssize_t)arg_size); 4975 } 4976 // Append `"+:::", "-c", "<command>"` to end of v:argv. 4977 // The "+:::" item is a no-op placeholder to mark the :restart "<command>". 4978 if (eap->arg && eap->arg[0] != '\0') { 4979 tv_list_append_string(argv_cpy, S_LEN("+:::")); 4980 tv_list_append_string(argv_cpy, S_LEN("-c")); 4981 tv_list_append_string(argv_cpy, eap->arg, (ssize_t)strlen(eap->arg)); 4982 } 4983 set_vim_var_list(VV_ARGV, argv_cpy); 4984 4985 char *quit_cmd = (eap->do_ecmd_cmd) ? eap->do_ecmd_cmd : "qall"; 4986 char *quit_cmd_copy = NULL; 4987 4988 // Prepend "confirm " to cmd if :confirm is used 4989 if (cmdmod.cmod_flags & CMOD_CONFIRM) { 4990 quit_cmd_copy = concat_str("confirm ", quit_cmd); 4991 quit_cmd = quit_cmd_copy; 4992 } 4993 4994 Error err = ERROR_INIT; 4995 restarting = true; 4996 nvim_command(cstr_as_string(quit_cmd), &err); 4997 xfree(quit_cmd_copy); 4998 if (ERROR_SET(&err)) { 4999 emsg(err.msg); // Could not exit 5000 api_clear_error(&err); 5001 not_restarting(); 5002 return; 5003 } 5004 if (!exiting) { 5005 emsg("restart failed: +cmd did not quit the server"); 5006 not_restarting(); 5007 } 5008 } 5009 5010 /// ":close": close current window, unless it is the last one 5011 static void ex_close(exarg_T *eap) 5012 { 5013 win_T *win = NULL; 5014 int winnr = 0; 5015 if (cmdwin_type != 0) { 5016 cmdwin_result = Ctrl_C; 5017 } else if (!text_locked() && !curbuf_locked()) { 5018 if (eap->addr_count == 0) { 5019 ex_win_close(eap->forceit, curwin, NULL); 5020 } else { 5021 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 5022 winnr++; 5023 if (winnr == eap->line2) { 5024 win = wp; 5025 break; 5026 } 5027 } 5028 if (win == NULL) { 5029 win = lastwin; 5030 } 5031 ex_win_close(eap->forceit, win, NULL); 5032 } 5033 } 5034 } 5035 5036 /// ":pclose": Close any preview window. 5037 static void ex_pclose(exarg_T *eap) 5038 { 5039 FOR_ALL_WINDOWS_IN_TAB(win, curtab) { 5040 if (win->w_p_pvw) { 5041 ex_win_close(eap->forceit, win, NULL); 5042 break; 5043 } 5044 } 5045 } 5046 5047 /// Close window "win" and take care of handling closing the last window for a 5048 /// modified buffer. 5049 /// 5050 /// @param tp NULL or the tab page "win" is in 5051 void ex_win_close(int forceit, win_T *win, tabpage_T *tp) 5052 { 5053 // Never close the autocommand window. 5054 if (is_aucmd_win(win)) { 5055 emsg(_(e_autocmd_close)); 5056 return; 5057 } 5058 if (!win->w_floating && window_layout_locked(CMD_close)) { 5059 return; 5060 } 5061 5062 buf_T *buf = win->w_buffer; 5063 5064 bool need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); 5065 if (need_hide && !buf_hide(buf) && !forceit) { 5066 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { 5067 bufref_T bufref; 5068 set_bufref(&bufref, buf); 5069 dialog_changed(buf, false); 5070 if (bufref_valid(&bufref) && bufIsChanged(buf)) { 5071 return; 5072 } 5073 need_hide = false; 5074 } else { 5075 no_write_message(); 5076 return; 5077 } 5078 } 5079 5080 // free buffer when not hiding it or when it's a scratch buffer 5081 if (tp == NULL) { 5082 win_close(win, !need_hide && !buf_hide(buf), forceit); 5083 } else { 5084 win_close_othertab(win, !need_hide && !buf_hide(buf), tp, forceit); 5085 } 5086 } 5087 5088 /// ":tabclose": close current tab page, unless it is the last one. 5089 /// ":tabclose N": close tab page N. 5090 static void ex_tabclose(exarg_T *eap) 5091 { 5092 if (cmdwin_type != 0) { 5093 cmdwin_result = K_IGNORE; 5094 return; 5095 } 5096 5097 if (first_tabpage->tp_next == NULL) { 5098 emsg(_("E784: Cannot close last tab page")); 5099 return; 5100 } 5101 5102 if (window_layout_locked(CMD_tabclose)) { 5103 return; 5104 } 5105 5106 int tab_number = get_tabpage_arg(eap); 5107 if (eap->errmsg != NULL) { 5108 return; 5109 } 5110 5111 tabpage_T *tp = find_tabpage(tab_number); 5112 if (tp == NULL) { 5113 beep_flush(); 5114 return; 5115 } 5116 if (tp != curtab) { 5117 tabpage_close_other(tp, eap->forceit); 5118 return; 5119 } else if (!text_locked() && !curbuf_locked()) { 5120 tabpage_close(eap->forceit); 5121 } 5122 } 5123 5124 /// ":tabonly": close all tab pages except the current one 5125 static void ex_tabonly(exarg_T *eap) 5126 { 5127 if (cmdwin_type != 0) { 5128 cmdwin_result = K_IGNORE; 5129 return; 5130 } 5131 5132 if (first_tabpage->tp_next == NULL) { 5133 msg(_("Already only one tab page"), 0); 5134 return; 5135 } 5136 5137 if (window_layout_locked(CMD_tabonly)) { 5138 return; 5139 } 5140 5141 int tab_number = get_tabpage_arg(eap); 5142 if (eap->errmsg != NULL) { 5143 return; 5144 } 5145 5146 goto_tabpage(tab_number); 5147 // Repeat this up to a 1000 times, because autocommands may 5148 // mess up the lists. 5149 for (int done = 0; done < 1000; done++) { 5150 FOR_ALL_TABS(tp) { 5151 if (tp->tp_topframe != topframe) { 5152 tabpage_close_other(tp, eap->forceit); 5153 // if we failed to close it quit 5154 if (valid_tabpage(tp)) { 5155 done = 1000; 5156 } 5157 // start over, "tp" is now invalid 5158 break; 5159 } 5160 } 5161 assert(first_tabpage); 5162 if (first_tabpage->tp_next == NULL) { 5163 break; 5164 } 5165 } 5166 } 5167 5168 /// Close the current tab page. 5169 void tabpage_close(int forceit) 5170 { 5171 if (window_layout_locked(CMD_tabclose)) { 5172 return; 5173 } 5174 5175 trigger_tabclosedpre(curtab); 5176 curtab->tp_did_tabclosedpre = true; 5177 tabpage_T *const save_curtab = curtab; 5178 5179 // First close all the windows but the current one. If that worked then 5180 // close the last window in this tab, that will close it. 5181 while (curwin->w_floating) { 5182 ex_win_close(forceit, curwin, NULL); 5183 } 5184 if (!ONE_WINDOW) { 5185 close_others(true, forceit); 5186 } 5187 if (ONE_WINDOW) { 5188 ex_win_close(forceit, curwin, NULL); 5189 } 5190 if (curtab == save_curtab) { 5191 // When closing the tab page failed, reset tp_did_tabclosedpre so that 5192 // TabClosedPre behaves consistently on next :close vs :tabclose. 5193 curtab->tp_did_tabclosedpre = false; 5194 } 5195 } 5196 5197 /// Close tab page "tp", which is not the current tab page. 5198 /// Note that autocommands may make "tp" invalid. 5199 /// Also takes care of the tab pages line disappearing when closing the 5200 /// last-but-one tab page. 5201 void tabpage_close_other(tabpage_T *tp, int forceit) 5202 { 5203 int done = 0; 5204 char prev_idx[NUMBUFLEN]; 5205 5206 if (window_layout_locked(CMD_SIZE)) { 5207 return; 5208 } 5209 5210 trigger_tabclosedpre(tp); 5211 tp->tp_did_tabclosedpre = true; 5212 5213 // Limit to 1000 windows, autocommands may add a window while we close 5214 // one. OK, so I'm paranoid... 5215 while (++done < 1000) { 5216 snprintf(prev_idx, sizeof(prev_idx), "%i", tabpage_index(tp)); 5217 win_T *wp = tp->tp_lastwin; 5218 ex_win_close(forceit, wp, tp); 5219 5220 // Autocommands may delete the tab page under our fingers. 5221 if (!valid_tabpage(tp)) { 5222 break; 5223 } 5224 // We may fail to close a window with a modified buffer. 5225 if (tp->tp_lastwin == wp) { 5226 done = 1000; 5227 break; 5228 } 5229 } 5230 if (done >= 1000) { 5231 // When closing the tab page failed, reset tp_did_tabclosedpre so that 5232 // TabClosedPre behaves consistently on next :close vs :tabclose. 5233 tp->tp_did_tabclosedpre = false; 5234 return; 5235 } 5236 } 5237 5238 /// ":only". 5239 static void ex_only(exarg_T *eap) 5240 { 5241 if (window_layout_locked(CMD_only)) { 5242 return; 5243 } 5244 5245 if (eap->addr_count > 0) { 5246 win_T *wp; 5247 linenr_T wnr = eap->line2; 5248 for (wp = firstwin; --wnr > 0;) { 5249 if (wp->w_next == NULL) { 5250 break; 5251 } 5252 wp = wp->w_next; 5253 } 5254 if (wp != curwin) { 5255 win_goto(wp); 5256 } 5257 } 5258 close_others(true, eap->forceit); 5259 } 5260 5261 static void ex_hide(exarg_T *eap) 5262 { 5263 // ":hide" or ":hide | cmd": hide current window 5264 if (eap->skip) { 5265 return; 5266 } 5267 5268 win_T *win = NULL; 5269 if (eap->addr_count == 0) { 5270 win = curwin; 5271 } else { 5272 int winnr = 0; 5273 5274 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 5275 winnr++; 5276 if (winnr == eap->line2) { 5277 win = wp; 5278 break; 5279 } 5280 } 5281 if (win == NULL) { 5282 win = lastwin; 5283 } 5284 } 5285 5286 if (!win->w_floating && window_layout_locked(CMD_hide)) { 5287 return; 5288 } 5289 5290 win_close(win, false, eap->forceit); // don't free buffer 5291 } 5292 5293 /// ":stop" and ":suspend": Suspend Vim. 5294 static void ex_stop(exarg_T *eap) 5295 { 5296 if (!eap->forceit) { 5297 autowrite_all(); 5298 } 5299 may_trigger_vim_suspend_resume(true); 5300 ui_call_suspend(); 5301 ui_flush(); 5302 } 5303 5304 /// ":exit", ":xit" and ":wq": Write file and quit the current window. 5305 static void ex_exit(exarg_T *eap) 5306 { 5307 if (cmdwin_type != 0) { 5308 cmdwin_result = Ctrl_C; 5309 return; 5310 } 5311 // Don't quit while editing the command line. 5312 if (text_locked()) { 5313 text_locked_msg(); 5314 return; 5315 } 5316 5317 bool save_exiting = exiting; 5318 // we plan to exit if there is only one relevant window 5319 if (check_more(false, eap->forceit) == OK && only_one_window()) { 5320 exiting = true; 5321 } 5322 // Write the buffer for ":wq" or when it was changed. 5323 // Trigger QuitPre and ExitPre. 5324 // Check if we can exit now, after autocommands have changed things. 5325 if (((eap->cmdidx == CMD_wq || curbufIsChanged()) && do_write(eap) == FAIL) 5326 || before_quit_autocmds(curwin, false, eap->forceit) 5327 || check_more(true, eap->forceit) == FAIL 5328 || (only_one_window() && check_changed_any(eap->forceit, false))) { 5329 not_exiting(save_exiting); 5330 } else { 5331 if (only_one_window()) { 5332 // quit last window, exit Vim 5333 getout(0); 5334 } 5335 not_exiting(save_exiting); 5336 // Quit current window, may free the buffer. 5337 win_close(curwin, !buf_hide(curwin->w_buffer), eap->forceit); 5338 } 5339 } 5340 5341 /// ":print", ":list", ":number". 5342 static void ex_print(exarg_T *eap) 5343 { 5344 if (curbuf->b_ml.ml_flags & ML_EMPTY) { 5345 emsg(_(e_empty_buffer)); 5346 } else { 5347 for (linenr_T line = eap->line1; line <= eap->line2 && !got_int; os_breakcheck()) { 5348 print_line(line, 5349 (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound 5350 || (eap->flags & EXFLAG_NR)), 5351 eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST), 5352 line == eap->line1); 5353 line++; 5354 } 5355 setpcmark(); 5356 // put cursor at last line 5357 curwin->w_cursor.lnum = eap->line2; 5358 beginline(BL_SOL | BL_FIX); 5359 } 5360 5361 ex_no_reprint = true; 5362 } 5363 5364 static void ex_goto(exarg_T *eap) 5365 { 5366 goto_byte(eap->line2); 5367 } 5368 5369 /// ":preserve". 5370 static void ex_preserve(exarg_T *eap) 5371 { 5372 ml_preserve(curbuf, true, true); 5373 } 5374 5375 /// ":recover". 5376 static void ex_recover(exarg_T *eap) 5377 { 5378 // Set recoverymode right away to avoid the ATTENTION prompt. 5379 recoverymode = true; 5380 if (!check_changed(curbuf, (p_awa ? CCGD_AW : 0) 5381 | CCGD_MULTWIN 5382 | (eap->forceit ? CCGD_FORCEIT : 0) 5383 | CCGD_EXCMD) 5384 5385 && (*eap->arg == NUL 5386 || setfname(curbuf, eap->arg, NULL, true) == OK)) { 5387 ml_recover(true); 5388 } 5389 recoverymode = false; 5390 } 5391 5392 /// Command modifier used in a wrong way. 5393 static void ex_wrongmodifier(exarg_T *eap) 5394 { 5395 eap->errmsg = _(e_invcmd); 5396 } 5397 5398 /// callback function for 'findfunc' 5399 static Callback ffu_cb; 5400 5401 static Callback *get_findfunc_callback(void) 5402 { 5403 return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb; 5404 } 5405 5406 /// Call 'findfunc' to obtain a list of file names. 5407 static list_T *call_findfunc(char *pat, BoolVarValue cmdcomplete) 5408 { 5409 const sctx_T saved_sctx = current_sctx; 5410 5411 typval_T args[3]; 5412 args[0].v_type = VAR_STRING; 5413 args[0].vval.v_string = pat; 5414 args[1].v_type = VAR_BOOL; 5415 args[1].vval.v_bool = cmdcomplete; 5416 args[2].v_type = VAR_UNKNOWN; 5417 5418 // Lock the text to prevent weird things from happening. Also disallow 5419 // switching to another window, it should not be needed and may end up in 5420 // Insert mode in another buffer. 5421 textlock++; 5422 5423 sctx_T *ctx = get_option_sctx(kOptFindfunc); 5424 if (ctx != NULL) { 5425 current_sctx = *ctx; 5426 } 5427 5428 Callback *cb = get_findfunc_callback(); 5429 typval_T rettv; 5430 int retval = callback_call(cb, 2, args, &rettv); 5431 5432 current_sctx = saved_sctx; 5433 5434 textlock--; 5435 5436 list_T *retlist = NULL; 5437 5438 if (retval == OK) { 5439 if (rettv.v_type == VAR_LIST) { 5440 retlist = tv_list_copy(NULL, rettv.vval.v_list, false, get_copyID()); 5441 } else { 5442 emsg(_(e_invalid_return_type_from_findfunc)); 5443 } 5444 5445 tv_clear(&rettv); 5446 } 5447 5448 return retlist; 5449 } 5450 5451 /// Find file names matching "pat" using 'findfunc' and return it in "files". 5452 /// Used for expanding the :find, :sfind and :tabfind command argument. 5453 /// Returns OK on success and FAIL otherwise. 5454 int expand_findfunc(char *pat, char ***files, int *numMatches) 5455 { 5456 *numMatches = 0; 5457 *files = NULL; 5458 5459 list_T *l = call_findfunc(pat, kBoolVarTrue); 5460 if (l == NULL) { 5461 return FAIL; 5462 } 5463 5464 int len = tv_list_len(l); 5465 if (len == 0) { // empty List 5466 return FAIL; 5467 } 5468 5469 *files = xmalloc(sizeof(char *) * (size_t)len); 5470 5471 // Copy all the List items 5472 int idx = 0; 5473 TV_LIST_ITER_CONST(l, li, { 5474 if (TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) { 5475 (*files)[idx] = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string); 5476 idx++; 5477 } 5478 }); 5479 5480 *numMatches = idx; 5481 tv_list_free(l); 5482 5483 return OK; 5484 } 5485 5486 /// Use 'findfunc' to find file 'findarg'. The 'count' argument is used to find 5487 /// the n'th matching file. 5488 static char *findfunc_find_file(char *findarg, size_t findarg_len, int count) 5489 { 5490 char *ret_fname = NULL; 5491 5492 const char cc = findarg[findarg_len]; 5493 findarg[findarg_len] = NUL; 5494 5495 list_T *fname_list = call_findfunc(findarg, kBoolVarFalse); 5496 int fname_count = tv_list_len(fname_list); 5497 5498 if (fname_count == 0) { 5499 semsg(_(e_cant_find_file_str_in_path), findarg); 5500 } else { 5501 if (count > fname_count) { 5502 semsg(_(e_no_more_file_str_found_in_path), findarg); 5503 } else { 5504 listitem_T *li = tv_list_find(fname_list, count - 1); 5505 if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) { 5506 ret_fname = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string); 5507 } 5508 } 5509 } 5510 5511 if (fname_list != NULL) { 5512 tv_list_free(fname_list); 5513 } 5514 5515 findarg[findarg_len] = cc; 5516 5517 return ret_fname; 5518 } 5519 5520 /// Process the 'findfunc' option value. 5521 /// Returns NULL on success and an error message on failure. 5522 const char *did_set_findfunc(optset_T *args) 5523 { 5524 buf_T *buf = (buf_T *)args->os_buf; 5525 int retval; 5526 5527 if (args->os_flags & OPT_LOCAL) { 5528 // buffer-local option set 5529 retval = option_set_callback_func(buf->b_p_ffu, &buf->b_ffu_cb); 5530 } else { 5531 // global option set 5532 retval = option_set_callback_func(p_ffu, &ffu_cb); 5533 // when using :set, free the local callback 5534 if (!(args->os_flags & OPT_GLOBAL)) { 5535 callback_free(&buf->b_ffu_cb); 5536 } 5537 } 5538 5539 if (retval == FAIL) { 5540 return e_invarg; 5541 } 5542 5543 // If the option value starts with <SID> or s:, then replace that with 5544 // the script identifier. 5545 char **varp = (char **)args->os_varp; 5546 char *name = get_scriptlocal_funcname(*varp); 5547 if (name != NULL) { 5548 free_string_option(*varp); 5549 *varp = name; 5550 } 5551 5552 return NULL; 5553 } 5554 5555 void free_findfunc_option(void) 5556 { 5557 callback_free(&ffu_cb); 5558 } 5559 5560 /// Mark the global 'findfunc' callback with "copyID" so that it is not 5561 /// garbage collected. 5562 bool set_ref_in_findfunc(int copyID) 5563 { 5564 bool abort = false; 5565 abort = set_ref_in_callback(&ffu_cb, copyID, NULL, NULL); 5566 return abort; 5567 } 5568 5569 /// :sview [+command] file split window with new file, read-only 5570 /// :split [[+command] file] split window with current or new file 5571 /// :vsplit [[+command] file] split window vertically with current or new file 5572 /// :new [[+command] file] split window with no or new file 5573 /// :vnew [[+command] file] split vertically window with no or new file 5574 /// :sfind [+command] file split window with file in 'path' 5575 /// 5576 /// :tabedit open new Tab page with empty window 5577 /// :tabedit [+command] file open new Tab page and edit "file" 5578 /// :tabnew [[+command] file] just like :tabedit 5579 /// :tabfind [+command] file open new Tab page and find "file" 5580 void ex_splitview(exarg_T *eap) 5581 { 5582 win_T *old_curwin = curwin; 5583 char *fname = NULL; 5584 const bool use_tab = eap->cmdidx == CMD_tabedit 5585 || eap->cmdidx == CMD_tabfind 5586 || eap->cmdidx == CMD_tabnew; 5587 5588 // A ":split" in the quickfix window works like ":new". Don't want two 5589 // quickfix windows. But it's OK when doing ":tab split". 5590 if (bt_quickfix(curbuf) && cmdmod.cmod_tab == 0) { 5591 if (eap->cmdidx == CMD_split) { 5592 eap->cmdidx = CMD_new; 5593 } 5594 if (eap->cmdidx == CMD_vsplit) { 5595 eap->cmdidx = CMD_vnew; 5596 } 5597 } 5598 5599 if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) { 5600 if (*get_findfunc() != NUL) { 5601 fname = findfunc_find_file(eap->arg, strlen(eap->arg), 5602 eap->addr_count > 0 ? eap->line2 : 1); 5603 } else { 5604 char *file_to_find = NULL; 5605 char *search_ctx = NULL; 5606 fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true, 5607 curbuf->b_ffname, &file_to_find, &search_ctx); 5608 xfree(file_to_find); 5609 vim_findfile_cleanup(search_ctx); 5610 } 5611 if (fname == NULL) { 5612 goto theend; 5613 } 5614 eap->arg = fname; 5615 } 5616 5617 // Either open new tab page or split the window. 5618 if (use_tab) { 5619 if (win_new_tabpage(cmdmod.cmod_tab != 0 ? cmdmod.cmod_tab : eap->addr_count == 0 5620 ? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) { 5621 do_exedit(eap, old_curwin); 5622 apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf); 5623 5624 // set the alternate buffer for the window we came from 5625 if (curwin != old_curwin 5626 && win_valid(old_curwin) 5627 && old_curwin->w_buffer != curbuf 5628 && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 5629 old_curwin->w_alt_fnum = curbuf->b_fnum; 5630 } 5631 } 5632 } else if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0, 5633 *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) { 5634 // Reset 'scrollbind' when editing another file, but keep it when 5635 // doing ":split" without arguments. 5636 if (*eap->arg != NUL) { 5637 RESET_BINDING(curwin); 5638 } else { 5639 do_check_scrollbind(false); 5640 } 5641 do_exedit(eap, old_curwin); 5642 } 5643 5644 theend: 5645 xfree(fname); 5646 } 5647 5648 /// Open a new tab page. 5649 void tabpage_new(void) 5650 { 5651 exarg_T ea = { 5652 .cmdidx = CMD_tabnew, 5653 .cmd = "tabn", 5654 .arg = "", 5655 }; 5656 ex_splitview(&ea); 5657 } 5658 5659 /// :tabnext command 5660 static void ex_tabnext(exarg_T *eap) 5661 { 5662 int tab_number; 5663 5664 switch (eap->cmdidx) { 5665 case CMD_tabfirst: 5666 case CMD_tabrewind: 5667 goto_tabpage(1); 5668 break; 5669 case CMD_tablast: 5670 goto_tabpage(9999); 5671 break; 5672 case CMD_tabprevious: 5673 case CMD_tabNext: 5674 if (eap->arg && *eap->arg != NUL) { 5675 char *p = eap->arg; 5676 char *p_save = p; 5677 tab_number = (int)getdigits(&p, false, 0); 5678 if (p == p_save || *p_save == '-' || *p_save == '+' || *p != NUL 5679 || tab_number == 0) { 5680 // No numbers as argument. 5681 eap->errmsg = ex_errmsg(e_invarg2, eap->arg); 5682 return; 5683 } 5684 } else { 5685 if (eap->addr_count == 0) { 5686 tab_number = 1; 5687 } else { 5688 tab_number = (int)eap->line2; 5689 if (tab_number < 1) { 5690 eap->errmsg = _(e_invrange); 5691 return; 5692 } 5693 } 5694 } 5695 goto_tabpage(-tab_number); 5696 break; 5697 default: // CMD_tabnext 5698 tab_number = get_tabpage_arg(eap); 5699 if (eap->errmsg == NULL) { 5700 goto_tabpage(tab_number); 5701 } 5702 break; 5703 } 5704 } 5705 5706 /// :tabmove command 5707 static void ex_tabmove(exarg_T *eap) 5708 { 5709 int tab_number = get_tabpage_arg(eap); 5710 if (eap->errmsg == NULL) { 5711 tabpage_move(tab_number); 5712 } 5713 } 5714 5715 /// :tabs command: List tabs and their contents. 5716 static void ex_tabs(exarg_T *eap) 5717 { 5718 int tabcount = 1; 5719 5720 msg_ext_set_kind("list_cmd"); 5721 msg_start(); 5722 msg_scroll = true; 5723 5724 win_T *lastused_win = valid_tabpage(lastused_tabpage) 5725 ? lastused_tabpage->tp_curwin 5726 : NULL; 5727 5728 FOR_ALL_TABS(tp) { 5729 if (got_int) { 5730 break; 5731 } 5732 5733 if (msg_col > 0) { 5734 msg_putchar('\n'); 5735 } 5736 vim_snprintf(IObuff, IOSIZE, _("Tab page %d"), tabcount++); 5737 msg_outtrans(IObuff, HLF_T, false); 5738 os_breakcheck(); 5739 5740 FOR_ALL_WINDOWS_IN_TAB(wp, tp) { 5741 if (got_int) { 5742 break; 5743 } else if (!wp->w_config.focusable || wp->w_config.hide) { 5744 continue; 5745 } 5746 5747 msg_putchar('\n'); 5748 msg_putchar(wp == curwin ? '>' : wp == lastused_win ? '#' : ' '); 5749 msg_putchar(' '); 5750 msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' '); 5751 msg_putchar(' '); 5752 if (buf_spname(wp->w_buffer) != NULL) { 5753 xstrlcpy(IObuff, buf_spname(wp->w_buffer), IOSIZE); 5754 } else { 5755 home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true); 5756 } 5757 msg_outtrans(IObuff, 0, false); 5758 os_breakcheck(); 5759 } 5760 } 5761 } 5762 5763 /// ":detach" 5764 /// 5765 /// Detaches the current UI. 5766 /// 5767 /// ":detach!" with bang (!) detaches all UIs _except_ the current UI. 5768 static void ex_detach(exarg_T *eap) 5769 { 5770 // come on pooky let's burn this mf down 5771 if (eap && eap->forceit) { 5772 emsg("bang (!) not supported yet"); 5773 } else { 5774 // 1. Send "error_exit" UI-event (notification only). 5775 // 2. Perform server-side UI detach. 5776 // 3. Close server-side channel without self-exit. 5777 5778 if (!current_ui) { 5779 emsg("UI not attached"); 5780 return; 5781 } 5782 5783 Channel *chan = find_channel(current_ui); 5784 if (!chan) { 5785 emsg(e_invchan); 5786 return; 5787 } 5788 chan->detach = true; // Prevent self-exit on channel-close. 5789 5790 // Server-side UI detach. Doesn't close the channel. 5791 Error err2 = ERROR_INIT; 5792 remote_ui_disconnect(chan->id, &err2, true); 5793 if (ERROR_SET(&err2)) { 5794 emsg(err2.msg); // UI disappeared already? 5795 api_clear_error(&err2); 5796 return; 5797 } 5798 5799 // Server-side channel close. 5800 const char *err = NULL; 5801 bool rv = channel_close(chan->id, kChannelPartAll, &err); 5802 if (!rv && err) { 5803 emsg(err); // UI disappeared already? 5804 return; 5805 } 5806 // XXX: Can't do this, channel_decref() is async... 5807 // assert(!find_channel(chan->id)); 5808 5809 ILOG("detach current_ui=%" PRId64, chan->id); 5810 } 5811 } 5812 5813 /// ":connect" 5814 /// 5815 /// Connects the current UI to a different server 5816 /// 5817 /// ":connect <address>" detaches the current UI and connects to the given server. 5818 /// ":connect! <address>" stops the current server if no other UIs are attached, then connects to the given server. 5819 static void ex_connect(exarg_T *eap) 5820 { 5821 bool stop_server = eap->forceit ? (ui_active() == 1) : false; 5822 5823 Error err = ERROR_INIT; 5824 remote_ui_connect(current_ui, eap->arg, &err); 5825 5826 if (ERROR_SET(&err)) { 5827 emsg(err.msg); 5828 api_clear_error(&err); 5829 return; 5830 } 5831 5832 ex_detach(NULL); 5833 if (stop_server) { 5834 exiting = true; 5835 getout(0); 5836 } 5837 } 5838 5839 /// ":mode": 5840 /// If no argument given, get the screen size and redraw. 5841 static void ex_mode(exarg_T *eap) 5842 { 5843 if (*eap->arg == NUL) { 5844 must_redraw = UPD_CLEAR; 5845 ex_redraw(eap); 5846 } else { 5847 emsg(_(e_screenmode)); 5848 } 5849 } 5850 5851 /// ":resize". 5852 /// set, increment or decrement current window height 5853 static void ex_resize(exarg_T *eap) 5854 { 5855 win_T *wp = curwin; 5856 5857 if (eap->addr_count > 0) { 5858 int n = (int)eap->line2; 5859 for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) {} 5860 } 5861 5862 int n = (int)atol(eap->arg); 5863 if (cmdmod.cmod_split & WSP_VERT) { 5864 if (*eap->arg == '-' || *eap->arg == '+') { 5865 n += wp->w_width; 5866 } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide 5867 n = Columns; 5868 } 5869 win_setwidth_win(n, wp); 5870 } else { 5871 if (*eap->arg == '-' || *eap->arg == '+') { 5872 n += wp->w_height; 5873 } else if (n == 0 && eap->arg[0] == NUL) { // default is very high 5874 n = Rows - 1; 5875 } 5876 win_setheight_win(n, wp); 5877 } 5878 } 5879 5880 /// ":find [+command] <file>" command. 5881 static void ex_find(exarg_T *eap) 5882 { 5883 if (!check_can_set_curbuf_forceit(eap->forceit)) { 5884 return; 5885 } 5886 5887 char *fname = NULL; 5888 if (*get_findfunc() != NUL) { 5889 fname = findfunc_find_file(eap->arg, strlen(eap->arg), 5890 eap->addr_count > 0 ? eap->line2 : 1); 5891 } else { 5892 char *file_to_find = NULL; 5893 char *search_ctx = NULL; 5894 fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true, 5895 curbuf->b_ffname, &file_to_find, &search_ctx); 5896 if (eap->addr_count > 0) { 5897 // Repeat finding the file "count" times. This matters when it appears 5898 // several times in the path. 5899 linenr_T count = eap->line2; 5900 while (fname != NULL && --count > 0) { 5901 xfree(fname); 5902 fname = find_file_in_path(NULL, 0, FNAME_MESS, false, 5903 curbuf->b_ffname, &file_to_find, &search_ctx); 5904 } 5905 } 5906 xfree(file_to_find); 5907 vim_findfile_cleanup(search_ctx); 5908 } 5909 5910 if (fname == NULL) { 5911 return; 5912 } 5913 5914 eap->arg = fname; 5915 do_exedit(eap, NULL); 5916 xfree(fname); 5917 } 5918 5919 /// ":edit", ":badd", ":balt", ":visual". 5920 static void ex_edit(exarg_T *eap) 5921 { 5922 char *ffname = eap->cmdidx == CMD_enew ? NULL : eap->arg; 5923 5924 // Exclude commands which keep the window's current buffer 5925 if (eap->cmdidx != CMD_badd 5926 && eap->cmdidx != CMD_balt 5927 // All other commands must obey 'winfixbuf' / ! rules 5928 && (is_other_file(0, ffname) && !check_can_set_curbuf_forceit(eap->forceit))) { 5929 return; 5930 } 5931 5932 // prevent use of :edit on prompt-buffers 5933 if (bt_prompt(curbuf) && eap->cmdidx == CMD_edit && *eap->arg == NUL) { 5934 emsg("cannot :edit a prompt buffer"); 5935 return; 5936 } 5937 5938 do_exedit(eap, NULL); 5939 } 5940 5941 /// ":edit <file>" command and alike. 5942 /// 5943 /// @param old_curwin curwin before doing a split or NULL 5944 void do_exedit(exarg_T *eap, win_T *old_curwin) 5945 { 5946 // ":vi" command ends Ex mode. 5947 if (exmode_active && (eap->cmdidx == CMD_visual 5948 || eap->cmdidx == CMD_view)) { 5949 exmode_active = false; 5950 ex_pressedreturn = false; 5951 if (ui_has(kUICmdline)) { 5952 ui_ext_cmdline_block_leave(); 5953 } 5954 if (*eap->arg == NUL) { 5955 // Special case: ":global/pat/visual\NLvi-commands" 5956 if (global_busy) { 5957 if (eap->nextcmd != NULL) { 5958 stuffReadbuff(eap->nextcmd); 5959 eap->nextcmd = NULL; 5960 } 5961 5962 const int save_rd = RedrawingDisabled; 5963 RedrawingDisabled = 0; 5964 const int save_nwr = no_wait_return; 5965 no_wait_return = 0; 5966 need_wait_return = false; 5967 const int save_ms = msg_scroll; 5968 msg_scroll = 0; 5969 redraw_all_later(UPD_NOT_VALID); 5970 pending_exmode_active = true; 5971 5972 normal_enter(false, true); 5973 5974 pending_exmode_active = false; 5975 RedrawingDisabled = save_rd; 5976 no_wait_return = save_nwr; 5977 msg_scroll = save_ms; 5978 } 5979 return; 5980 } 5981 } 5982 5983 if ((eap->cmdidx == CMD_new 5984 || eap->cmdidx == CMD_tabnew 5985 || eap->cmdidx == CMD_tabedit 5986 || eap->cmdidx == CMD_vnew) && *eap->arg == NUL) { 5987 // ":new" or ":tabnew" without argument: edit a new empty buffer 5988 setpcmark(); 5989 do_ecmd(0, NULL, NULL, eap, ECMD_ONE, 5990 ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0), 5991 old_curwin == NULL ? curwin : NULL); 5992 } else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit) 5993 || *eap->arg != NUL) { 5994 // Can't edit another file when "textlock" or "curbuf->b_ro_locked" is set. 5995 // Only ":edit" or ":script" can bring us here, others are stopped earlier. 5996 if (*eap->arg != NUL && text_or_buf_locked()) { 5997 return; 5998 } 5999 int n = readonlymode; 6000 if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) { 6001 readonlymode = true; 6002 } else if (eap->cmdidx == CMD_enew) { 6003 readonlymode = false; // 'readonly' doesn't make sense 6004 // in an empty buffer 6005 } 6006 if (eap->cmdidx != CMD_balt && eap->cmdidx != CMD_badd) { 6007 setpcmark(); 6008 } 6009 if (do_ecmd(0, eap->cmdidx == CMD_enew ? NULL : eap->arg, 6010 NULL, eap, eap->do_ecmd_lnum, 6011 (buf_hide(curbuf) ? ECMD_HIDE : 0) 6012 + (eap->forceit ? ECMD_FORCEIT : 0) 6013 // After a split we can use an existing buffer. 6014 + (old_curwin != NULL ? ECMD_OLDBUF : 0) 6015 + (eap->cmdidx == CMD_badd ? ECMD_ADDBUF : 0) 6016 + (eap->cmdidx == CMD_balt ? ECMD_ALTBUF : 0), 6017 old_curwin == NULL ? curwin : NULL) == FAIL) { 6018 // Editing the file failed. If the window was split, close it. 6019 if (old_curwin != NULL) { 6020 bool need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1); 6021 if (!need_hide || buf_hide(curbuf)) { 6022 cleanup_T cs; 6023 6024 // Reset the error/interrupt/exception state here so that 6025 // aborting() returns false when closing a window. 6026 enter_cleanup(&cs); 6027 win_close(curwin, !need_hide && !buf_hide(curbuf), false); 6028 6029 // Restore the error/interrupt/exception state if not 6030 // discarded by a new aborting error, interrupt, or 6031 // uncaught exception. 6032 leave_cleanup(&cs); 6033 } 6034 } 6035 } else if (readonlymode && curbuf->b_nwindows == 1) { 6036 // When editing an already visited buffer, 'readonly' won't be set 6037 // but the previous value is kept. With ":view" and ":sview" we 6038 // want the file to be readonly, except when another window is 6039 // editing the same buffer. 6040 curbuf->b_p_ro = true; 6041 } 6042 readonlymode = n; 6043 } else { 6044 if (eap->do_ecmd_cmd != NULL) { 6045 do_cmdline_cmd(eap->do_ecmd_cmd); 6046 } 6047 int n = curwin->w_arg_idx_invalid; 6048 check_arg_idx(curwin); 6049 if (n != curwin->w_arg_idx_invalid) { 6050 maketitle(); 6051 } 6052 } 6053 6054 // if ":split file" worked, set alternate file name in old window to new 6055 // file 6056 if (old_curwin != NULL 6057 && *eap->arg != NUL 6058 && curwin != old_curwin 6059 && win_valid(old_curwin) 6060 && old_curwin->w_buffer != curbuf 6061 && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 6062 old_curwin->w_alt_fnum = curbuf->b_fnum; 6063 } 6064 6065 ex_no_reprint = true; 6066 } 6067 6068 /// ":gui" and ":gvim" when there is no GUI. 6069 static void ex_nogui(exarg_T *eap) 6070 { 6071 eap->errmsg = _("E25: Nvim does not have a built-in GUI"); 6072 } 6073 6074 static void ex_popup(exarg_T *eap) 6075 { 6076 pum_make_popup(eap->arg, eap->forceit); 6077 } 6078 6079 static void ex_swapname(exarg_T *eap) 6080 { 6081 if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) { 6082 msg(_("No swap file"), 0); 6083 } else { 6084 msg(curbuf->b_ml.ml_mfp->mf_fname, 0); 6085 } 6086 } 6087 6088 /// ":syncbind" forces all 'scrollbind' windows to have the same relative 6089 /// offset. 6090 /// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) 6091 static void ex_syncbind(exarg_T *eap) 6092 { 6093 linenr_T vtopline; // Target topline (including fill) 6094 6095 linenr_T old_linenr = curwin->w_cursor.lnum; 6096 6097 setpcmark(); 6098 6099 // determine max (virtual) topline 6100 if (curwin->w_p_scb) { 6101 vtopline = get_vtopline(curwin); 6102 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 6103 if (wp->w_p_scb && wp->w_buffer) { 6104 linenr_T y = plines_m_win_fill(wp, 1, wp->w_buffer->b_ml.ml_line_count) 6105 - get_scrolloff_value(curwin); 6106 vtopline = MIN(vtopline, y); 6107 } 6108 } 6109 vtopline = MAX(vtopline, 1); 6110 } else { 6111 vtopline = 1; 6112 } 6113 6114 // Set all scrollbind windows to the same topline. 6115 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 6116 if (wp->w_p_scb) { 6117 int y = vtopline - get_vtopline(wp); 6118 if (y > 0) { 6119 scrollup(wp, y, true); 6120 } else { 6121 scrolldown(wp, -y, true); 6122 } 6123 wp->w_scbind_pos = vtopline; 6124 redraw_later(wp, UPD_VALID); 6125 cursor_correct(wp); 6126 wp->w_redr_status = true; 6127 } 6128 } 6129 6130 if (curwin->w_p_scb) { 6131 did_syncbind = true; 6132 checkpcmark(); 6133 if (old_linenr != curwin->w_cursor.lnum) { 6134 char ctrl_o[2]; 6135 6136 ctrl_o[0] = Ctrl_O; 6137 ctrl_o[1] = 0; 6138 ins_typebuf(ctrl_o, REMAP_NONE, 0, true, false); 6139 } 6140 } 6141 } 6142 6143 static void ex_read(exarg_T *eap) 6144 { 6145 int empty = (curbuf->b_ml.ml_flags & ML_EMPTY); 6146 6147 if (eap->usefilter) { // :r!cmd 6148 do_bang(1, eap, false, false, true); 6149 return; 6150 } 6151 6152 if (u_save(eap->line2, (linenr_T)(eap->line2 + 1)) == FAIL) { 6153 return; 6154 } 6155 6156 int i; 6157 if (*eap->arg == NUL) { 6158 if (check_fname() == FAIL) { // check for no file name 6159 return; 6160 } 6161 i = readfile(curbuf->b_ffname, curbuf->b_fname, 6162 eap->line2, 0, (linenr_T)MAXLNUM, eap, 0, false); 6163 } else { 6164 if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) { 6165 setaltfname(eap->arg, eap->arg, 1); 6166 } 6167 i = readfile(eap->arg, NULL, 6168 eap->line2, 0, (linenr_T)MAXLNUM, eap, 0, false); 6169 } 6170 if (i != OK) { 6171 if (!aborting()) { 6172 semsg(_(e_notopen), eap->arg); 6173 } 6174 } else { 6175 if (empty && exmode_active) { 6176 // Delete the empty line that remains. Historically ex does 6177 // this but vi doesn't. 6178 linenr_T lnum; 6179 if (eap->line2 == 0) { 6180 lnum = curbuf->b_ml.ml_line_count; 6181 } else { 6182 lnum = 1; 6183 } 6184 if (*ml_get(lnum) == NUL && u_savedel(lnum, 1) == OK) { 6185 ml_delete(lnum); 6186 if (curwin->w_cursor.lnum > 1 6187 && curwin->w_cursor.lnum >= lnum) { 6188 curwin->w_cursor.lnum--; 6189 } 6190 deleted_lines_mark(lnum, 1); 6191 } 6192 } 6193 redraw_curbuf_later(UPD_VALID); 6194 } 6195 } 6196 6197 static char *prev_dir = NULL; 6198 6199 #if defined(EXITFREE) 6200 void free_cd_dir(void) 6201 { 6202 XFREE_CLEAR(prev_dir); 6203 XFREE_CLEAR(globaldir); 6204 } 6205 6206 #endif 6207 6208 /// Get the previous directory for the given chdir scope. 6209 static char *get_prevdir(CdScope scope) 6210 { 6211 switch (scope) { 6212 case kCdScopeTabpage: 6213 return curtab->tp_prevdir; 6214 break; 6215 case kCdScopeWindow: 6216 return curwin->w_prevdir; 6217 break; 6218 default: 6219 return prev_dir; 6220 } 6221 } 6222 6223 /// Deal with the side effects of changing the current directory. 6224 /// 6225 /// @param scope Scope of the function call (global, tab or window). 6226 static void post_chdir(CdScope scope, bool trigger_dirchanged) 6227 { 6228 // Always overwrite the window-local CWD. 6229 XFREE_CLEAR(curwin->w_localdir); 6230 6231 // Overwrite the tab-local CWD for :cd, :tcd. 6232 if (scope >= kCdScopeTabpage) { 6233 XFREE_CLEAR(curtab->tp_localdir); 6234 } 6235 6236 if (scope < kCdScopeGlobal) { 6237 char *pdir = get_prevdir(scope); 6238 // If still in global directory, set CWD as the global directory. 6239 if (globaldir == NULL && pdir != NULL) { 6240 globaldir = xstrdup(pdir); 6241 } 6242 } 6243 6244 char cwd[MAXPATHL]; 6245 if (os_dirname(cwd, MAXPATHL) != OK) { 6246 return; 6247 } 6248 switch (scope) { 6249 case kCdScopeGlobal: 6250 // We are now in the global directory, no need to remember its name. 6251 XFREE_CLEAR(globaldir); 6252 break; 6253 case kCdScopeTabpage: 6254 curtab->tp_localdir = xstrdup(cwd); 6255 break; 6256 case kCdScopeWindow: 6257 curwin->w_localdir = xstrdup(cwd); 6258 break; 6259 case kCdScopeInvalid: 6260 abort(); 6261 } 6262 6263 last_chdir_reason = NULL; 6264 shorten_fnames(vim_strchr(p_cpo, CPO_NOSYMLINKS) == NULL); 6265 6266 if (trigger_dirchanged) { 6267 do_autocmd_dirchanged(cwd, scope, kCdCauseManual, false); 6268 } 6269 } 6270 6271 /// Change directory function used by :cd/:tcd/:lcd Ex commands and the chdir() function. 6272 /// @param new_dir The directory to change to. 6273 /// @param scope Scope of the function call (global, tab or window). 6274 /// @return true if the directory is successfully changed. 6275 bool changedir_func(char *new_dir, CdScope scope) 6276 { 6277 if (new_dir == NULL || allbuf_locked()) { 6278 return false; 6279 } 6280 6281 char *pdir = NULL; 6282 // ":cd -": Change to previous directory 6283 if (strcmp(new_dir, "-") == 0) { 6284 pdir = get_prevdir(scope); 6285 if (pdir == NULL) { 6286 emsg(_("E186: No previous directory")); 6287 return false; 6288 } 6289 new_dir = pdir; 6290 } 6291 6292 if (os_dirname(NameBuff, MAXPATHL) == OK) { 6293 pdir = xstrdup(NameBuff); 6294 } else { 6295 pdir = NULL; 6296 } 6297 6298 // For UNIX ":cd" means: go to home directory. 6299 // On other systems too if 'cdhome' is set. 6300 if (*new_dir == NUL && p_cdh) { 6301 // Use NameBuff for home directory name. 6302 expand_env("$HOME", NameBuff, MAXPATHL); 6303 new_dir = NameBuff; 6304 } 6305 6306 bool dir_differs = pdir == NULL || pathcmp(pdir, new_dir, -1) != 0; 6307 if (dir_differs) { 6308 do_autocmd_dirchanged(new_dir, scope, kCdCauseManual, true); 6309 if (vim_chdir(new_dir) != 0) { 6310 emsg(_(e_failed)); 6311 xfree(pdir); 6312 return false; 6313 } 6314 } 6315 6316 char **pp; 6317 switch (scope) { 6318 case kCdScopeTabpage: 6319 pp = &curtab->tp_prevdir; 6320 break; 6321 case kCdScopeWindow: 6322 pp = &curwin->w_prevdir; 6323 break; 6324 default: 6325 pp = &prev_dir; 6326 } 6327 xfree(*pp); 6328 *pp = pdir; 6329 6330 post_chdir(scope, dir_differs); 6331 6332 return true; 6333 } 6334 6335 /// ":cd", ":tcd", ":lcd", ":chdir", "tchdir" and ":lchdir". 6336 void ex_cd(exarg_T *eap) 6337 { 6338 char *new_dir = eap->arg; 6339 // for non-UNIX ":cd" means: print current directory unless 'cdhome' is set 6340 if (*new_dir == NUL && !p_cdh) { 6341 ex_pwd(NULL); 6342 return; 6343 } 6344 6345 CdScope scope = kCdScopeGlobal; 6346 switch (eap->cmdidx) { 6347 case CMD_tcd: 6348 case CMD_tchdir: 6349 scope = kCdScopeTabpage; 6350 break; 6351 case CMD_lcd: 6352 case CMD_lchdir: 6353 scope = kCdScopeWindow; 6354 break; 6355 default: 6356 break; 6357 } 6358 if (changedir_func(new_dir, scope)) { 6359 // Echo the new current directory if the command was typed. 6360 if (KeyTyped || p_verbose >= 5) { 6361 ex_pwd(eap); 6362 } 6363 } 6364 } 6365 6366 /// ":pwd". 6367 static void ex_pwd(exarg_T *eap) 6368 { 6369 if (os_dirname(NameBuff, MAXPATHL) == OK) { 6370 #ifdef BACKSLASH_IN_FILENAME 6371 slash_adjust(NameBuff); 6372 #endif 6373 if (p_verbose > 0) { 6374 char *context = "global"; 6375 if (last_chdir_reason != NULL) { 6376 context = last_chdir_reason; 6377 } else if (curwin->w_localdir != NULL) { 6378 context = "window"; 6379 } else if (curtab->tp_localdir != NULL) { 6380 context = "tabpage"; 6381 } 6382 smsg(0, "[%s] %s", context, NameBuff); 6383 } else { 6384 msg(NameBuff, 0); 6385 } 6386 } else { 6387 emsg(_("E187: Unknown")); 6388 } 6389 } 6390 6391 /// ":=". 6392 static void ex_equal(exarg_T *eap) 6393 { 6394 if (*eap->arg != NUL && *eap->arg != '|') { 6395 // equivalent to :lua= expr 6396 ex_lua(eap); 6397 } else { 6398 eap->nextcmd = find_nextcmd(eap->arg); 6399 smsg(0, "%" PRId64, (int64_t)eap->line2); 6400 } 6401 } 6402 6403 static void ex_sleep(exarg_T *eap) 6404 { 6405 if (cursor_valid(curwin)) { 6406 setcursor_mayforce(curwin, true); 6407 } 6408 6409 int64_t len = eap->line2; 6410 switch (*eap->arg) { 6411 case 'm': 6412 break; 6413 case NUL: 6414 len *= 1000; break; 6415 default: 6416 semsg(_(e_invarg2), eap->arg); return; 6417 } 6418 6419 // Hide the cursor if invoked with ! 6420 do_sleep(len, eap->forceit); 6421 } 6422 6423 /// Sleep for "msec" milliseconds, but return early on CTRL-C. 6424 /// 6425 /// @param hide_cursor hide the cursor if true 6426 void do_sleep(int64_t msec, bool hide_cursor) 6427 { 6428 if (hide_cursor) { 6429 ui_busy_start(); 6430 } 6431 6432 ui_flush(); // flush before waiting 6433 LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, msec, got_int); 6434 6435 // If CTRL-C was typed to interrupt the sleep, drop the CTRL-C from the 6436 // input buffer, otherwise a following call to input() fails. 6437 if (got_int) { 6438 vpeekc(); 6439 } 6440 6441 if (hide_cursor) { 6442 ui_busy_stop(); 6443 } 6444 } 6445 6446 /// ":winsize" command (obsolete). 6447 static void ex_winsize(exarg_T *eap) 6448 { 6449 char *arg = eap->arg; 6450 6451 if (!ascii_isdigit(*arg)) { 6452 semsg(_(e_invarg2), arg); 6453 return; 6454 } 6455 int w = getdigits_int(&arg, false, 10); 6456 arg = skipwhite(arg); 6457 char *p = arg; 6458 int h = getdigits_int(&arg, false, 10); 6459 if (*p != NUL && *arg == NUL) { 6460 screen_resize(w, h); 6461 } else { 6462 emsg(_("E465: :winsize requires two number arguments")); 6463 } 6464 } 6465 6466 static void ex_wincmd(exarg_T *eap) 6467 { 6468 int xchar = NUL; 6469 char *p; 6470 6471 if (*eap->arg == 'g' || *eap->arg == Ctrl_G) { 6472 // CTRL-W g and CTRL-W CTRL-G have an extra command character 6473 if (eap->arg[1] == NUL) { 6474 emsg(_(e_invarg)); 6475 return; 6476 } 6477 xchar = (uint8_t)eap->arg[1]; 6478 p = eap->arg + 2; 6479 } else { 6480 p = eap->arg + 1; 6481 } 6482 6483 eap->nextcmd = check_nextcmd(p); 6484 p = skipwhite(p); 6485 if (*p != NUL && *p != '"' && eap->nextcmd == NULL) { 6486 emsg(_(e_invarg)); 6487 } else if (!eap->skip) { 6488 // Pass flags on for ":vertical wincmd ]". 6489 postponed_split_flags = cmdmod.cmod_split; 6490 postponed_split_tab = cmdmod.cmod_tab; 6491 do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0, xchar); 6492 postponed_split_flags = 0; 6493 postponed_split_tab = 0; 6494 } 6495 } 6496 6497 /// Handle command that work like operators: ":delete", ":yank", ":>" and ":<". 6498 static void ex_operators(exarg_T *eap) 6499 { 6500 oparg_T oa; 6501 6502 clear_oparg(&oa); 6503 oa.regname = eap->regname; 6504 oa.start.lnum = eap->line1; 6505 oa.end.lnum = eap->line2; 6506 oa.line_count = eap->line2 - eap->line1 + 1; 6507 oa.motion_type = kMTLineWise; 6508 virtual_op = kFalse; 6509 if (eap->cmdidx != CMD_yank) { // position cursor for undo 6510 setpcmark(); 6511 curwin->w_cursor.lnum = eap->line1; 6512 beginline(BL_SOL | BL_FIX); 6513 } 6514 6515 if (VIsual_active) { 6516 end_visual_mode(); 6517 } 6518 6519 switch (eap->cmdidx) { 6520 case CMD_delete: 6521 oa.op_type = OP_DELETE; 6522 op_delete(&oa); 6523 break; 6524 6525 case CMD_yank: 6526 oa.op_type = OP_YANK; 6527 op_yank(&oa, true); 6528 break; 6529 6530 default: // CMD_rshift or CMD_lshift 6531 if ( 6532 (eap->cmdidx == CMD_rshift) ^ curwin->w_p_rl) { 6533 oa.op_type = OP_RSHIFT; 6534 } else { 6535 oa.op_type = OP_LSHIFT; 6536 } 6537 op_shift(&oa, false, eap->amount); 6538 break; 6539 } 6540 virtual_op = kNone; 6541 ex_may_print(eap); 6542 } 6543 6544 /// ":put". 6545 static void ex_put(exarg_T *eap) 6546 { 6547 // ":0put" works like ":1put!". 6548 if (eap->line2 == 0) { 6549 eap->line2 = 1; 6550 eap->forceit = true; 6551 } 6552 curwin->w_cursor.lnum = eap->line2; 6553 check_cursor_col(curwin); 6554 do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1, 6555 PUT_LINE|PUT_CURSLINE); 6556 } 6557 6558 /// ":iput". 6559 static void ex_iput(exarg_T *eap) 6560 { 6561 // ":0iput" works like ":1iput!". 6562 if (eap->line2 == 0) { 6563 eap->line2 = 1; 6564 eap->forceit = true; 6565 } 6566 curwin->w_cursor.lnum = eap->line2; 6567 check_cursor_col(curwin); 6568 do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L, 6569 PUT_LINE|PUT_CURSLINE|PUT_FIXINDENT); 6570 } 6571 6572 /// Handle ":copy" and ":move". 6573 static void ex_copymove(exarg_T *eap) 6574 { 6575 const char *errormsg = NULL; 6576 linenr_T n = get_address(eap, &eap->arg, eap->addr_type, false, false, false, 1, &errormsg); 6577 if (eap->arg == NULL) { // error detected 6578 if (errormsg != NULL) { 6579 emsg(errormsg); 6580 } 6581 eap->nextcmd = NULL; 6582 return; 6583 } 6584 get_flags(eap); 6585 6586 // move or copy lines from 'eap->line1'-'eap->line2' to below line 'n' 6587 if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count) { 6588 emsg(_(e_invrange)); 6589 return; 6590 } 6591 6592 if (eap->cmdidx == CMD_move) { 6593 if (do_move(eap->line1, eap->line2, n) == FAIL) { 6594 return; 6595 } 6596 } else { 6597 ex_copy(eap->line1, eap->line2, n); 6598 } 6599 u_clearline(curbuf); 6600 beginline(BL_SOL | BL_FIX); 6601 ex_may_print(eap); 6602 } 6603 6604 /// Print the current line if flags were given to the Ex command. 6605 void ex_may_print(exarg_T *eap) 6606 { 6607 if (eap->flags != 0) { 6608 print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR), 6609 (eap->flags & EXFLAG_LIST), true); 6610 ex_no_reprint = true; 6611 } 6612 } 6613 6614 /// ":smagic" and ":snomagic". 6615 static void ex_submagic(exarg_T *eap) 6616 { 6617 const optmagic_T saved = magic_overruled; 6618 6619 magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF; 6620 ex_substitute(eap); 6621 magic_overruled = saved; 6622 } 6623 6624 /// ":smagic" and ":snomagic" preview callback. 6625 static int ex_submagic_preview(exarg_T *eap, int cmdpreview_ns, handle_T cmdpreview_bufnr) 6626 { 6627 const optmagic_T saved = magic_overruled; 6628 6629 magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF; 6630 int retv = ex_substitute_preview(eap, cmdpreview_ns, cmdpreview_bufnr); 6631 magic_overruled = saved; 6632 6633 return retv; 6634 } 6635 6636 /// ":join". 6637 static void ex_join(exarg_T *eap) 6638 { 6639 curwin->w_cursor.lnum = eap->line1; 6640 if (eap->line1 == eap->line2) { 6641 if (eap->addr_count >= 2) { // :2,2join does nothing 6642 return; 6643 } 6644 if (eap->line2 == curbuf->b_ml.ml_line_count) { 6645 beep_flush(); 6646 return; 6647 } 6648 eap->line2++; 6649 } 6650 do_join((size_t)((ssize_t)eap->line2 - eap->line1 + 1), !eap->forceit, true, true, true); 6651 beginline(BL_WHITE | BL_FIX); 6652 ex_may_print(eap); 6653 } 6654 6655 /// ":[addr]@r": execute register 6656 static void ex_at(exarg_T *eap) 6657 { 6658 int prev_len = typebuf.tb_len; 6659 6660 curwin->w_cursor.lnum = eap->line2; 6661 check_cursor_col(curwin); 6662 6663 // Get the register name. No name means use the previous one. 6664 int c = (uint8_t)(*eap->arg); 6665 if (c == NUL) { 6666 c = '@'; 6667 } 6668 6669 // Put the register in the typeahead buffer with the "silent" flag. 6670 if (do_execreg(c, true, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, true) == FAIL) { 6671 beep_flush(); 6672 return; 6673 } 6674 6675 const bool save_efr = exec_from_reg; 6676 6677 exec_from_reg = true; 6678 6679 // Execute from the typeahead buffer. 6680 // Continue until the stuff buffer is empty and all added characters 6681 // have been consumed. 6682 while (!stuff_empty() || typebuf.tb_len > prev_len) { 6683 do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE); 6684 } 6685 6686 exec_from_reg = save_efr; 6687 } 6688 6689 /// ":!". 6690 static void ex_bang(exarg_T *eap) 6691 { 6692 do_bang(eap->addr_count, eap, eap->forceit, true, true); 6693 } 6694 6695 /// ":undo". 6696 static void ex_undo(exarg_T *eap) 6697 { 6698 if (eap->addr_count != 1) { 6699 if (eap->forceit) { 6700 u_undo_and_forget(1, true); // :undo! 6701 } else { 6702 u_undo(1); // :undo 6703 } 6704 return; 6705 } 6706 6707 linenr_T step = eap->line2; 6708 6709 if (eap->forceit) { // undo! 123 6710 // change number for "undo!" must be lesser than current change number 6711 if (step >= curbuf->b_u_seq_cur) { 6712 emsg(_(e_undobang_cannot_redo_or_move_branch)); 6713 return; 6714 } 6715 // ensure that target change number is in same branch 6716 // while also counting the amount of undoes it'd take to reach target 6717 u_header_T *uhp; 6718 int count = 0; 6719 6720 for (uhp = curbuf->b_u_curhead ? curbuf->b_u_curhead : curbuf->b_u_newhead; 6721 uhp != NULL && uhp->uh_seq > step; 6722 uhp = uhp->uh_next.ptr, ++count) {} 6723 if (step != 0 && (uhp == NULL || uhp->uh_seq < step)) { 6724 emsg(_(e_undobang_cannot_redo_or_move_branch)); 6725 return; 6726 } 6727 u_undo_and_forget(count, true); 6728 } else { // :undo 123 6729 undo_time(step, false, false, true); 6730 } 6731 } 6732 6733 static void ex_wundo(exarg_T *eap) 6734 { 6735 uint8_t hash[UNDO_HASH_SIZE]; 6736 6737 u_compute_hash(curbuf, hash); 6738 u_write_undo(eap->arg, eap->forceit, curbuf, hash); 6739 } 6740 6741 static void ex_rundo(exarg_T *eap) 6742 { 6743 uint8_t hash[UNDO_HASH_SIZE]; 6744 6745 u_compute_hash(curbuf, hash); 6746 u_read_undo(eap->arg, hash, NULL); 6747 } 6748 6749 /// ":redo". 6750 static void ex_redo(exarg_T *eap) 6751 { 6752 u_redo(1); 6753 } 6754 6755 /// ":earlier" and ":later". 6756 static void ex_later(exarg_T *eap) 6757 { 6758 int count = 0; 6759 bool sec = false; 6760 bool file = false; 6761 char *p = eap->arg; 6762 6763 if (*p == NUL) { 6764 count = 1; 6765 } else if (isdigit((uint8_t)(*p))) { 6766 count = getdigits_int(&p, false, 0); 6767 switch (*p) { 6768 case 's': 6769 p++; sec = true; break; 6770 case 'm': 6771 p++; sec = true; count *= 60; break; 6772 case 'h': 6773 p++; sec = true; count *= 60 * 60; break; 6774 case 'd': 6775 p++; sec = true; count *= 24 * 60 * 60; break; 6776 case 'f': 6777 p++; file = true; break; 6778 } 6779 } 6780 6781 if (*p != NUL) { 6782 semsg(_(e_invarg2), eap->arg); 6783 } else { 6784 undo_time(eap->cmdidx == CMD_earlier ? -count : count, 6785 sec, file, false); 6786 } 6787 } 6788 6789 /// ":redir": start/stop redirection. 6790 static void ex_redir(exarg_T *eap) 6791 { 6792 char *arg = eap->arg; 6793 6794 if (STRICMP(eap->arg, "END") == 0) { 6795 close_redir(); 6796 } else { 6797 if (*arg == '>') { 6798 arg++; 6799 char *mode; 6800 if (*arg == '>') { 6801 arg++; 6802 mode = "a"; 6803 } else { 6804 mode = "w"; 6805 } 6806 arg = skipwhite(arg); 6807 6808 close_redir(); 6809 6810 // Expand environment variables and "~/". 6811 char *fname = expand_env_save(arg); 6812 if (fname == NULL) { 6813 return; 6814 } 6815 6816 redir_fd = open_exfile(fname, eap->forceit, mode); 6817 xfree(fname); 6818 } else if (*arg == '@') { 6819 // redirect to a register a-z (resp. A-Z for appending) 6820 close_redir(); 6821 arg++; 6822 if (valid_yank_reg(*arg, true) && *arg != '_') { 6823 redir_reg = (uint8_t)(*arg++); 6824 if (*arg == '>' && arg[1] == '>') { // append 6825 arg += 2; 6826 } else { 6827 // Can use both "@a" and "@a>". 6828 if (*arg == '>') { 6829 arg++; 6830 } 6831 // Make register empty when not using @A-@Z and the 6832 // command is valid. 6833 if (*arg == NUL && !isupper(redir_reg)) { 6834 write_reg_contents(redir_reg, "", 0, false); 6835 } 6836 } 6837 } 6838 if (*arg != NUL) { 6839 redir_reg = 0; 6840 semsg(_(e_invarg2), eap->arg); 6841 } 6842 } else if (*arg == '=' && arg[1] == '>') { 6843 bool append; 6844 6845 // redirect to a variable 6846 close_redir(); 6847 arg += 2; 6848 6849 if (*arg == '>') { 6850 arg++; 6851 append = true; 6852 } else { 6853 append = false; 6854 } 6855 6856 if (var_redir_start(skipwhite(arg), append) == OK) { 6857 redir_vname = true; 6858 } 6859 } else { // TODO(vim): redirect to a buffer 6860 semsg(_(e_invarg2), eap->arg); 6861 } 6862 } 6863 6864 // Make sure redirection is not off. Can happen for cmdline completion 6865 // that indirectly invokes a command to catch its output. 6866 if (redir_fd != NULL 6867 || redir_reg || redir_vname) { 6868 redir_off = false; 6869 } 6870 } 6871 6872 /// ":redraw": force redraw 6873 static void ex_redraw(exarg_T *eap) 6874 { 6875 if (cmdpreview) { 6876 return; // Ignore :redraw during 'inccommand' preview. #9777 6877 } 6878 int r = RedrawingDisabled; 6879 int p = p_lz; 6880 6881 RedrawingDisabled = 0; 6882 p_lz = false; 6883 validate_cursor(curwin); 6884 update_topline(curwin); 6885 if (eap->forceit) { 6886 redraw_all_later(UPD_NOT_VALID); 6887 redraw_cmdline = true; 6888 } else if (VIsual_active) { 6889 redraw_curbuf_later(UPD_INVERTED); 6890 } 6891 update_screen(); 6892 if (need_maketitle) { 6893 maketitle(); 6894 } 6895 RedrawingDisabled = r; 6896 p_lz = p; 6897 6898 // Reset msg_didout, so that a message that's there is overwritten. 6899 msg_didout = false; 6900 msg_col = 0; 6901 6902 // No need to wait after an intentional redraw. 6903 need_wait_return = false; 6904 6905 ui_flush(); 6906 } 6907 6908 /// ":redrawstatus": force redraw of status line(s) and window bar(s) 6909 static void ex_redrawstatus(exarg_T *eap) 6910 { 6911 if (cmdpreview) { 6912 return; // Ignore :redrawstatus during 'inccommand' preview. #9777 6913 } 6914 int r = RedrawingDisabled; 6915 int p = p_lz; 6916 6917 if (eap->forceit) { 6918 status_redraw_all(); 6919 } else { 6920 status_redraw_curbuf(); 6921 } 6922 6923 RedrawingDisabled = 0; 6924 p_lz = false; 6925 if (State & MODE_CMDLINE) { 6926 redraw_statuslines(); 6927 } else { 6928 if (VIsual_active) { 6929 redraw_curbuf_later(UPD_INVERTED); 6930 } 6931 update_screen(); 6932 } 6933 RedrawingDisabled = r; 6934 p_lz = p; 6935 ui_flush(); 6936 } 6937 6938 /// ":redrawtabline": force redraw of the tabline 6939 static void ex_redrawtabline(exarg_T *eap FUNC_ATTR_UNUSED) 6940 { 6941 const int r = RedrawingDisabled; 6942 const int p = p_lz; 6943 6944 RedrawingDisabled = 0; 6945 p_lz = false; 6946 6947 draw_tabline(); 6948 6949 RedrawingDisabled = r; 6950 p_lz = p; 6951 ui_flush(); 6952 } 6953 6954 static void close_redir(void) 6955 { 6956 if (redir_fd != NULL) { 6957 fclose(redir_fd); 6958 redir_fd = NULL; 6959 } 6960 redir_reg = 0; 6961 if (redir_vname) { 6962 var_redir_stop(); 6963 redir_vname = false; 6964 } 6965 } 6966 6967 /// Try creating a directory, give error message on failure 6968 /// 6969 /// @param[in] name Directory to create. 6970 /// @param[in] prot Directory permissions. 6971 /// 6972 /// @return OK in case of success, FAIL otherwise. 6973 int vim_mkdir_emsg(const char *const name, const int prot) 6974 FUNC_ATTR_NONNULL_ALL 6975 { 6976 int ret; 6977 if ((ret = os_mkdir(name, prot)) != 0) { 6978 semsg(_(e_mkdir), name, os_strerror(ret)); 6979 return FAIL; 6980 } 6981 return OK; 6982 } 6983 6984 /// Open a file for writing for an Ex command, with some checks. 6985 /// 6986 /// @param mode "w" for create new file or "a" for append 6987 /// 6988 /// @return file descriptor, or NULL on failure. 6989 FILE *open_exfile(char *fname, int forceit, char *mode) 6990 { 6991 #ifdef UNIX 6992 // with Unix it is possible to open a directory 6993 if (os_isdir(fname)) { 6994 semsg(_(e_isadir2), fname); 6995 return NULL; 6996 } 6997 #endif 6998 if (!forceit && *mode != 'a' && os_path_exists(fname)) { 6999 semsg(_("E189: \"%s\" exists (add ! to override)"), fname); 7000 return NULL; 7001 } 7002 7003 FILE *fd; 7004 if ((fd = os_fopen(fname, mode)) == NULL) { 7005 semsg(_("E190: Cannot open \"%s\" for writing"), fname); 7006 } 7007 7008 return fd; 7009 } 7010 7011 /// ":mark" and ":k". 7012 static void ex_mark(exarg_T *eap) 7013 { 7014 if (*eap->arg == NUL) { // No argument? 7015 emsg(_(e_argreq)); 7016 return; 7017 } 7018 7019 if (eap->arg[1] != NUL) { // more than one character? 7020 semsg(_(e_trailing_arg), eap->arg); 7021 return; 7022 } 7023 7024 pos_T pos = curwin->w_cursor; // save curwin->w_cursor 7025 curwin->w_cursor.lnum = eap->line2; 7026 beginline(BL_WHITE | BL_FIX); 7027 if (setmark(*eap->arg) == FAIL) { // set mark 7028 emsg(_("E191: Argument must be a letter or forward/backward quote")); 7029 } 7030 curwin->w_cursor = pos; // restore curwin->w_cursor 7031 } 7032 7033 /// Update w_topline, w_leftcol and the cursor position. 7034 void update_topline_cursor(void) 7035 { 7036 check_cursor(curwin); // put cursor on valid line 7037 update_topline(curwin); 7038 if (!curwin->w_p_wrap) { 7039 validate_cursor(curwin); 7040 } 7041 update_curswant(); 7042 } 7043 7044 /// Save the current State and go to Normal mode. 7045 /// 7046 /// @return true if the typeahead could be saved. 7047 bool save_current_state(save_state_T *sst) 7048 FUNC_ATTR_NONNULL_ALL 7049 { 7050 sst->save_msg_scroll = msg_scroll; 7051 sst->save_restart_edit = restart_edit; 7052 sst->save_msg_didout = msg_didout; 7053 sst->save_State = State; 7054 sst->save_finish_op = finish_op; 7055 sst->save_opcount = opcount; 7056 sst->save_reg_executing = reg_executing; 7057 sst->save_pending_end_reg_executing = pending_end_reg_executing; 7058 7059 msg_scroll = false; // no msg scrolling in Normal mode 7060 restart_edit = 0; // don't go to Insert mode 7061 7062 // Save the current typeahead. This is required to allow using ":normal" 7063 // from an event handler and makes sure we don't hang when the argument 7064 // ends with half a command. 7065 save_typeahead(&sst->tabuf); 7066 return sst->tabuf.typebuf_valid; 7067 } 7068 7069 void restore_current_state(save_state_T *sst) 7070 FUNC_ATTR_NONNULL_ALL 7071 { 7072 // Restore the previous typeahead. 7073 restore_typeahead(&sst->tabuf); 7074 7075 msg_scroll = sst->save_msg_scroll; 7076 if (force_restart_edit) { 7077 force_restart_edit = false; 7078 } else { 7079 // Some function (terminal_enter()) was aware of ex_normal and decided to 7080 // override the value of restart_edit anyway. 7081 restart_edit = sst->save_restart_edit; 7082 } 7083 finish_op = sst->save_finish_op; 7084 opcount = sst->save_opcount; 7085 reg_executing = sst->save_reg_executing; 7086 pending_end_reg_executing = sst->save_pending_end_reg_executing; 7087 7088 // don't reset msg_didout now 7089 msg_didout |= sst->save_msg_didout; 7090 7091 // Restore the state (needed when called from a function executed for 7092 // 'indentexpr'). Update the mouse and cursor, they may have changed. 7093 State = sst->save_State; 7094 ui_cursor_shape(); // may show different cursor shape 7095 } 7096 7097 bool expr_map_locked(void) 7098 { 7099 return expr_map_lock > 0 && !(curbuf->b_flags & BF_DUMMY); 7100 } 7101 7102 /// ":normal[!] {commands}": Execute normal mode commands. 7103 static void ex_normal(exarg_T *eap) 7104 { 7105 if (curbuf->terminal && State & MODE_TERMINAL) { 7106 emsg("Can't re-enter normal mode from terminal mode"); 7107 return; 7108 } 7109 char *arg = NULL; 7110 7111 if (expr_map_locked()) { 7112 emsg(_(e_secure)); 7113 return; 7114 } 7115 7116 if (ex_normal_busy >= p_mmd) { 7117 emsg(_("E192: Recursive use of :normal too deep")); 7118 return; 7119 } 7120 7121 // vgetc() expects K_SPECIAL to have been escaped. Don't do 7122 // this for the K_SPECIAL leading byte, otherwise special keys will not 7123 // work. 7124 { 7125 int len = 0; 7126 7127 // Count the number of characters to be escaped. 7128 int l; 7129 for (char *p = eap->arg; *p != NUL; p++) { 7130 for (l = utfc_ptr2len(p) - 1; l > 0; l--) { 7131 if (*++p == (char)K_SPECIAL) { // trailbyte K_SPECIAL 7132 len += 2; 7133 } 7134 } 7135 } 7136 if (len > 0) { 7137 arg = xmalloc(strlen(eap->arg) + (size_t)len + 1); 7138 len = 0; 7139 for (char *p = eap->arg; *p != NUL; p++) { 7140 arg[len++] = *p; 7141 for (l = utfc_ptr2len(p) - 1; l > 0; l--) { 7142 arg[len++] = *++p; 7143 if (*p == (char)K_SPECIAL) { 7144 arg[len++] = (char)KS_SPECIAL; 7145 arg[len++] = KE_FILLER; 7146 } 7147 } 7148 arg[len] = NUL; 7149 } 7150 } 7151 } 7152 7153 ex_normal_busy++; 7154 save_state_T save_state; 7155 if (save_current_state(&save_state)) { 7156 // Repeat the :normal command for each line in the range. When no 7157 // range given, execute it just once, without positioning the cursor 7158 // first. 7159 do { 7160 if (eap->addr_count != 0) { 7161 curwin->w_cursor.lnum = eap->line1++; 7162 curwin->w_cursor.col = 0; 7163 check_cursor_moved(curwin); 7164 } 7165 7166 exec_normal_cmd((arg != NULL ? arg : eap->arg), 7167 eap->forceit ? REMAP_NONE : REMAP_YES, false); 7168 } while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int); 7169 } 7170 7171 // Might not return to the main loop when in an event handler. 7172 update_topline_cursor(); 7173 7174 restore_current_state(&save_state); 7175 7176 ex_normal_busy--; 7177 7178 setmouse(); 7179 ui_cursor_shape(); // may show different cursor shape 7180 xfree(arg); 7181 } 7182 7183 /// ":startinsert", ":startreplace" and ":startgreplace" 7184 static void ex_startinsert(exarg_T *eap) 7185 { 7186 if (eap->forceit) { 7187 // cursor line can be zero on startup 7188 if (!curwin->w_cursor.lnum) { 7189 curwin->w_cursor.lnum = 1; 7190 } 7191 set_cursor_for_append_to_line(); 7192 } 7193 7194 // Ignore the command when already in Insert mode. Inserting an 7195 // expression register that invokes a function can do this. 7196 if (State & MODE_INSERT) { 7197 return; 7198 } 7199 7200 if (eap->cmdidx == CMD_startinsert) { 7201 restart_edit = 'a'; 7202 } else if (eap->cmdidx == CMD_startreplace) { 7203 restart_edit = 'R'; 7204 } else { 7205 restart_edit = 'V'; 7206 } 7207 7208 if (!eap->forceit) { 7209 if (eap->cmdidx == CMD_startinsert) { 7210 restart_edit = 'i'; 7211 } 7212 curwin->w_curswant = 0; // avoid MAXCOL 7213 } 7214 7215 if (VIsual_active) { 7216 showmode(); 7217 } 7218 } 7219 7220 /// ":stopinsert" 7221 static void ex_stopinsert(exarg_T *eap) 7222 { 7223 restart_edit = 0; 7224 stop_insert_mode = true; 7225 clearmode(); 7226 } 7227 7228 /// Execute normal mode command "cmd". 7229 /// "remap" can be REMAP_NONE or REMAP_YES. 7230 void exec_normal_cmd(char *cmd, int remap, bool silent) 7231 { 7232 // Stuff the argument into the typeahead buffer. 7233 ins_typebuf(cmd, remap, 0, true, silent); 7234 exec_normal(false, false); 7235 } 7236 7237 /// Execute normal_cmd() until there is no typeahead left. 7238 /// 7239 /// @param was_typed whether or not something was typed 7240 /// @param use_vpeekc true to use vpeekc() to check for available chars 7241 void exec_normal(bool was_typed, bool use_vpeekc) 7242 { 7243 oparg_T oa; 7244 int c; 7245 7246 // When calling vpeekc() from feedkeys() it will return Ctrl_C when there 7247 // is nothing to get, so also check for Ctrl_C. 7248 clear_oparg(&oa); 7249 finish_op = false; 7250 while ((!stuff_empty() 7251 || ((was_typed || !typebuf_typed()) 7252 && typebuf.tb_len > 0) 7253 || (use_vpeekc && (c = vpeekc()) != NUL && c != Ctrl_C)) 7254 && !got_int) { 7255 update_topline_cursor(); 7256 normal_cmd(&oa, true); // execute a Normal mode cmd 7257 } 7258 } 7259 7260 static void ex_checkpath(exarg_T *eap) 7261 { 7262 find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1, 7263 eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, 7264 1, (linenr_T)MAXLNUM, eap->forceit, false); 7265 } 7266 7267 /// ":psearch" 7268 static void ex_psearch(exarg_T *eap) 7269 { 7270 g_do_tagpreview = (int)p_pvh; 7271 ex_findpat(eap); 7272 g_do_tagpreview = 0; 7273 } 7274 7275 static void ex_findpat(exarg_T *eap) 7276 { 7277 bool whole = true; 7278 int action; 7279 7280 switch (cmdnames[eap->cmdidx].cmd_name[2]) { 7281 case 'e': // ":psearch", ":isearch" and ":dsearch" 7282 if (cmdnames[eap->cmdidx].cmd_name[0] == 'p') { 7283 action = ACTION_GOTO; 7284 } else { 7285 action = ACTION_SHOW; 7286 } 7287 break; 7288 case 'i': // ":ilist" and ":dlist" 7289 action = ACTION_SHOW_ALL; 7290 break; 7291 case 'u': // ":ijump" and ":djump" 7292 action = ACTION_GOTO; 7293 break; 7294 default: // ":isplit" and ":dsplit" 7295 action = ACTION_SPLIT; 7296 break; 7297 } 7298 7299 int n = 1; 7300 if (ascii_isdigit(*eap->arg)) { // get count 7301 n = getdigits_int(&eap->arg, false, 0); 7302 eap->arg = skipwhite(eap->arg); 7303 } 7304 if (*eap->arg == '/') { // Match regexp, not just whole words 7305 whole = false; 7306 eap->arg++; 7307 char *p = skip_regexp(eap->arg, '/', magic_isset()); 7308 if (*p) { 7309 *p++ = NUL; 7310 p = skipwhite(p); 7311 7312 // Check for trailing illegal characters. 7313 if (!ends_excmd(*p)) { 7314 eap->errmsg = ex_errmsg(e_trailing_arg, p); 7315 } else { 7316 eap->nextcmd = check_nextcmd(p); 7317 } 7318 } 7319 } 7320 if (!eap->skip) { 7321 find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, 7322 *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, n, action, 7323 eap->line1, eap->line2, eap->forceit, false); 7324 } 7325 } 7326 7327 /// ":ptag", ":ptselect", ":ptjump", ":ptnext", etc. 7328 static void ex_ptag(exarg_T *eap) 7329 { 7330 g_do_tagpreview = (int)p_pvh; // will be reset to 0 in ex_tag_cmd() 7331 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); 7332 } 7333 7334 /// ":pedit" 7335 static void ex_pedit(exarg_T *eap) 7336 { 7337 win_T *curwin_save = curwin; 7338 prepare_preview_window(); 7339 7340 // Edit the file. 7341 do_exedit(eap, NULL); 7342 7343 back_to_current_window(curwin_save); 7344 } 7345 7346 /// ":pbuffer" 7347 static void ex_pbuffer(exarg_T *eap) 7348 { 7349 win_T *curwin_save = curwin; 7350 prepare_preview_window(); 7351 7352 // Go to the buffer. 7353 do_exbuffer(eap); 7354 7355 back_to_current_window(curwin_save); 7356 } 7357 7358 static void prepare_preview_window(void) 7359 { 7360 // Open the preview window or popup and make it the current window. 7361 g_do_tagpreview = (int)p_pvh; 7362 prepare_tagpreview(true); 7363 } 7364 7365 static void back_to_current_window(win_T *curwin_save) 7366 { 7367 if (curwin != curwin_save && win_valid(curwin_save)) { 7368 // Return cursor to where we were 7369 validate_cursor(curwin); 7370 redraw_later(curwin, UPD_VALID); 7371 win_enter(curwin_save, true); 7372 } 7373 g_do_tagpreview = 0; 7374 } 7375 7376 /// ":stag", ":stselect" and ":stjump". 7377 static void ex_stag(exarg_T *eap) 7378 { 7379 postponed_split = -1; 7380 postponed_split_flags = cmdmod.cmod_split; 7381 postponed_split_tab = cmdmod.cmod_tab; 7382 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1); 7383 postponed_split_flags = 0; 7384 postponed_split_tab = 0; 7385 } 7386 7387 /// ":tag", ":tselect", ":tjump", ":tnext", etc. 7388 static void ex_tag(exarg_T *eap) 7389 { 7390 ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name); 7391 } 7392 7393 static void ex_tag_cmd(exarg_T *eap, const char *name) 7394 { 7395 int cmd; 7396 7397 switch (name[1]) { 7398 case 'j': 7399 cmd = DT_JUMP; // ":tjump" 7400 break; 7401 case 's': 7402 cmd = DT_SELECT; // ":tselect" 7403 break; 7404 case 'p': // ":tprevious" 7405 case 'N': 7406 cmd = DT_PREV; // ":tNext" 7407 break; 7408 case 'n': 7409 cmd = DT_NEXT; // ":tnext" 7410 break; 7411 case 'o': 7412 cmd = DT_POP; // ":pop" 7413 break; 7414 case 'f': // ":tfirst" 7415 case 'r': 7416 cmd = DT_FIRST; // ":trewind" 7417 break; 7418 case 'l': 7419 cmd = DT_LAST; // ":tlast" 7420 break; 7421 default: // ":tag" 7422 cmd = DT_TAG; 7423 break; 7424 } 7425 7426 if (name[0] == 'l') { 7427 cmd = DT_LTAG; 7428 } 7429 7430 do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1, 7431 eap->forceit, true); 7432 } 7433 7434 enum { 7435 SPEC_PERC = 0, 7436 SPEC_HASH, 7437 SPEC_CWORD, 7438 SPEC_CCWORD, 7439 SPEC_CEXPR, 7440 SPEC_CFILE, 7441 SPEC_SFILE, 7442 SPEC_SLNUM, 7443 SPEC_STACK, 7444 SPEC_SCRIPT, 7445 SPEC_AFILE, 7446 SPEC_ABUF, 7447 SPEC_AMATCH, 7448 SPEC_SFLNUM, 7449 SPEC_SID, 7450 // SPEC_CLIENT, 7451 }; 7452 7453 /// Check "str" for starting with a special cmdline variable. 7454 /// If found return one of the SPEC_ values and set "*usedlen" to the length of 7455 /// the variable. Otherwise return -1 and "*usedlen" is unchanged. 7456 ssize_t find_cmdline_var(const char *src, size_t *usedlen) 7457 FUNC_ATTR_NONNULL_ALL 7458 { 7459 static char *(spec_str[]) = { 7460 [SPEC_PERC] = "%", 7461 [SPEC_HASH] = "#", 7462 [SPEC_CWORD] = "<cword>", // cursor word 7463 [SPEC_CCWORD] = "<cWORD>", // cursor WORD 7464 [SPEC_CEXPR] = "<cexpr>", // expr under cursor 7465 [SPEC_CFILE] = "<cfile>", // cursor path name 7466 [SPEC_SFILE] = "<sfile>", // ":so" file name 7467 [SPEC_SLNUM] = "<slnum>", // ":so" file line number 7468 [SPEC_STACK] = "<stack>", // call stack 7469 [SPEC_SCRIPT] = "<script>", // script file name 7470 [SPEC_AFILE] = "<afile>", // autocommand file name 7471 [SPEC_ABUF] = "<abuf>", // autocommand buffer number 7472 [SPEC_AMATCH] = "<amatch>", // autocommand match name 7473 [SPEC_SFLNUM] = "<sflnum>", // script file line number 7474 [SPEC_SID] = "<SID>", // script ID: <SNR>123_ 7475 // [SPEC_CLIENT] = "<client>", 7476 }; 7477 7478 for (size_t i = 0; i < ARRAY_SIZE(spec_str); i++) { 7479 size_t len = strlen(spec_str[i]); 7480 if (strncmp(src, spec_str[i], len) == 0) { 7481 *usedlen = len; 7482 assert(i <= SSIZE_MAX); 7483 return (ssize_t)i; 7484 } 7485 } 7486 return -1; 7487 } 7488 7489 /// Evaluate cmdline variables. 7490 /// 7491 /// change "%" to curbuf->b_ffname 7492 /// "#" to curwin->w_alt_fnum 7493 /// "<cword>" to word under the cursor 7494 /// "<cWORD>" to WORD under the cursor 7495 /// "<cexpr>" to C-expression under the cursor 7496 /// "<cfile>" to path name under the cursor 7497 /// "<sfile>" to sourced file name 7498 /// "<stack>" to call stack 7499 /// "<script>" to current script name 7500 /// "<slnum>" to sourced file line number 7501 /// "<afile>" to file name for autocommand 7502 /// "<abuf>" to buffer number for autocommand 7503 /// "<amatch>" to matching name for autocommand 7504 /// 7505 /// When an error is detected, "errormsg" is set to a non-NULL pointer (may be 7506 /// "" for error without a message) and NULL is returned. 7507 /// 7508 /// @param src pointer into commandline 7509 /// @param srcstart beginning of valid memory for src 7510 /// @param usedlen characters after src that are used 7511 /// @param lnump line number for :e command, or NULL 7512 /// @param errormsg pointer to error message 7513 /// @param escaped return value has escaped white space (can be NULL) 7514 /// @param empty_is_error empty result is considered an error 7515 /// 7516 /// @return an allocated string if a valid match was found. 7517 /// Returns NULL if no match was found. "usedlen" then still contains the 7518 /// number of characters to skip. 7519 char *eval_vars(char *src, const char *srcstart, size_t *usedlen, linenr_T *lnump, 7520 const char **errormsg, int *escaped, bool empty_is_error) 7521 { 7522 char *result = ""; 7523 char *resultbuf = NULL; 7524 size_t resultlen; 7525 int valid = VALID_HEAD | VALID_PATH; // Assume valid result. 7526 bool tilde_file = false; 7527 bool skip_mod = false; 7528 char strbuf[30]; 7529 7530 *errormsg = NULL; 7531 if (escaped != NULL) { 7532 *escaped = false; 7533 } 7534 7535 // Check if there is something to do. 7536 ssize_t spec_idx = find_cmdline_var(src, usedlen); 7537 if (spec_idx < 0) { // no match 7538 *usedlen = 1; 7539 return NULL; 7540 } 7541 7542 // Skip when preceded with a backslash "\%" and "\#". 7543 // Note: In "\\%" the % is also not recognized! 7544 if (src > srcstart && src[-1] == '\\') { 7545 *usedlen = 0; 7546 STRMOVE(src - 1, src); // remove backslash 7547 return NULL; 7548 } 7549 7550 // word or WORD under cursor 7551 if (spec_idx == SPEC_CWORD 7552 || spec_idx == SPEC_CCWORD 7553 || spec_idx == SPEC_CEXPR) { 7554 resultlen = find_ident_under_cursor(&result, 7555 spec_idx == SPEC_CWORD 7556 ? (FIND_IDENT | FIND_STRING) 7557 : (spec_idx == SPEC_CEXPR 7558 ? (FIND_IDENT | FIND_STRING | FIND_EVAL) 7559 : FIND_STRING)); 7560 if (resultlen == 0) { 7561 *errormsg = ""; 7562 return NULL; 7563 } 7564 // 7565 // '#': Alternate file name 7566 // '%': Current file name 7567 // File name under the cursor 7568 // File name for autocommand 7569 // and following modifiers 7570 // 7571 } else { 7572 switch (spec_idx) { 7573 case SPEC_PERC: // '%': current file 7574 if (curbuf->b_fname == NULL) { 7575 result = ""; 7576 valid = 0; // Must have ":p:h" to be valid 7577 } else { 7578 result = curbuf->b_fname; 7579 tilde_file = strcmp(result, "~") == 0; 7580 } 7581 break; 7582 7583 case SPEC_HASH: // '#' or "#99": alternate file 7584 if (src[1] == '#') { // "##": the argument list 7585 result = arg_all(); 7586 resultbuf = result; 7587 *usedlen = 2; 7588 if (escaped != NULL) { 7589 *escaped = true; 7590 } 7591 skip_mod = true; 7592 break; 7593 } 7594 char *s = src + 1; 7595 if (*s == '<') { // "#<99" uses v:oldfiles. 7596 s++; 7597 } 7598 int i = getdigits_int(&s, false, 0); 7599 if (s == src + 2 && src[1] == '-') { 7600 // just a minus sign, don't skip over it 7601 s--; 7602 } 7603 *usedlen = (size_t)(s - src); // length of what we expand 7604 7605 if (src[1] == '<' && i != 0) { 7606 if (*usedlen < 2) { 7607 // Should we give an error message for #<text? 7608 *usedlen = 1; 7609 return NULL; 7610 } 7611 result = (char *)tv_list_find_str(get_vim_var_list(VV_OLDFILES), i - 1); 7612 if (result == NULL) { 7613 *errormsg = ""; 7614 return NULL; 7615 } 7616 } else { 7617 if (i == 0 && src[1] == '<' && *usedlen > 1) { 7618 *usedlen = 1; 7619 } 7620 buf_T *buf = buflist_findnr(i); 7621 if (buf == NULL) { 7622 *errormsg = _("E194: No alternate file name to substitute for '#'"); 7623 return NULL; 7624 } 7625 if (lnump != NULL) { 7626 *lnump = ECMD_LAST; 7627 } 7628 if (buf->b_fname == NULL) { 7629 result = ""; 7630 valid = 0; // Must have ":p:h" to be valid 7631 } else { 7632 result = buf->b_fname; 7633 tilde_file = strcmp(result, "~") == 0; 7634 } 7635 } 7636 break; 7637 7638 case SPEC_CFILE: // file name under cursor 7639 result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1, NULL); 7640 if (result == NULL) { 7641 *errormsg = ""; 7642 return NULL; 7643 } 7644 resultbuf = result; // remember allocated string 7645 break; 7646 7647 case SPEC_AFILE: // file name for autocommand 7648 if (autocmd_fname != NULL && !autocmd_fname_full) { 7649 // Still need to turn the fname into a full path. It was 7650 // postponed to avoid a delay when <afile> is not used. 7651 autocmd_fname_full = true; 7652 result = FullName_save(autocmd_fname, false); 7653 // Copy into `autocmd_fname`, don't reassign it. #8165 7654 xstrlcpy(autocmd_fname, result, MAXPATHL); 7655 xfree(result); 7656 } 7657 result = autocmd_fname; 7658 if (result == NULL) { 7659 *errormsg = _(e_no_autocommand_file_name_to_substitute_for_afile); 7660 return NULL; 7661 } 7662 result = path_try_shorten_fname(result); 7663 break; 7664 7665 case SPEC_ABUF: // buffer number for autocommand 7666 if (autocmd_bufnr <= 0) { 7667 *errormsg = _(e_no_autocommand_buffer_number_to_substitute_for_abuf); 7668 return NULL; 7669 } 7670 snprintf(strbuf, sizeof(strbuf), "%d", autocmd_bufnr); 7671 result = strbuf; 7672 break; 7673 7674 case SPEC_AMATCH: // match name for autocommand 7675 result = autocmd_match; 7676 if (result == NULL) { 7677 *errormsg = _(e_no_autocommand_match_name_to_substitute_for_amatch); 7678 return NULL; 7679 } 7680 break; 7681 7682 case SPEC_SFILE: // file name for ":so" command 7683 result = estack_sfile(ESTACK_SFILE); 7684 if (result == NULL) { 7685 *errormsg = _(e_no_source_file_name_to_substitute_for_sfile); 7686 return NULL; 7687 } 7688 resultbuf = result; // remember allocated string 7689 break; 7690 case SPEC_STACK: // call stack 7691 result = estack_sfile(ESTACK_STACK); 7692 if (result == NULL) { 7693 *errormsg = _(e_no_call_stack_to_substitute_for_stack); 7694 return NULL; 7695 } 7696 resultbuf = result; // remember allocated string 7697 break; 7698 case SPEC_SCRIPT: // script file name 7699 result = estack_sfile(ESTACK_SCRIPT); 7700 if (result == NULL) { 7701 *errormsg = _(e_no_script_file_name_to_substitute_for_script); 7702 return NULL; 7703 } 7704 resultbuf = result; // remember allocated string 7705 break; 7706 7707 case SPEC_SLNUM: // line in file for ":so" command 7708 if (SOURCING_NAME == NULL || SOURCING_LNUM == 0) { 7709 *errormsg = _(e_no_line_number_to_use_for_slnum); 7710 return NULL; 7711 } 7712 snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, SOURCING_LNUM); 7713 result = strbuf; 7714 break; 7715 7716 case SPEC_SFLNUM: // line in script file 7717 if (current_sctx.sc_lnum + SOURCING_LNUM == 0) { 7718 *errormsg = _(e_no_line_number_to_use_for_sflnum); 7719 return NULL; 7720 } 7721 snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, 7722 current_sctx.sc_lnum + SOURCING_LNUM); 7723 result = strbuf; 7724 break; 7725 7726 case SPEC_SID: 7727 if (current_sctx.sc_sid <= 0) { 7728 *errormsg = _(e_usingsid); 7729 return NULL; 7730 } 7731 snprintf(strbuf, sizeof(strbuf), "<SNR>%" PRIdSCID "_", current_sctx.sc_sid); 7732 result = strbuf; 7733 break; 7734 7735 default: 7736 // should not happen 7737 *errormsg = ""; 7738 break; 7739 } 7740 7741 // Length of new string. 7742 resultlen = strlen(result); 7743 // Remove the file name extension. 7744 if (src[*usedlen] == '<') { 7745 (*usedlen)++; 7746 char *s; 7747 if ((s = strrchr(result, '.')) != NULL 7748 && s >= path_tail(result)) { 7749 resultlen = (size_t)(s - result); 7750 } 7751 } else if (!skip_mod) { 7752 valid |= modify_fname(src, tilde_file, usedlen, &result, 7753 &resultbuf, &resultlen); 7754 if (result == NULL) { 7755 *errormsg = ""; 7756 return NULL; 7757 } 7758 } 7759 } 7760 7761 if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH) { 7762 if (empty_is_error) { 7763 if (valid != VALID_HEAD + VALID_PATH) { 7764 // xgettext:no-c-format 7765 *errormsg = _("E499: Empty file name for '%' or '#', only works with \":p:h\""); 7766 } else { 7767 *errormsg = _("E500: Evaluates to an empty string"); 7768 } 7769 } 7770 result = NULL; 7771 } else { 7772 result = xmemdupz(result, resultlen); 7773 } 7774 xfree(resultbuf); 7775 return result; 7776 } 7777 7778 /// Expand the <sfile> string in "arg". 7779 /// 7780 /// @return an allocated string, or NULL for any error. 7781 char *expand_sfile(char *arg) 7782 { 7783 char *result = xstrdup(arg); 7784 7785 for (char *p = result; *p;) { 7786 if (strncmp(p, "<sfile>", 7) != 0) { 7787 p++; 7788 } else { 7789 // replace "<sfile>" with the sourced file name, and do ":" stuff 7790 size_t srclen; 7791 const char *errormsg; 7792 char *repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL, true); 7793 if (errormsg != NULL) { 7794 if (*errormsg) { 7795 emsg(errormsg); 7796 } 7797 xfree(result); 7798 return NULL; 7799 } 7800 if (repl == NULL) { // no match (cannot happen) 7801 p += srclen; 7802 continue; 7803 } 7804 size_t len = strlen(result) - srclen + strlen(repl) + 1; 7805 char *newres = xmalloc(len); 7806 memmove(newres, result, (size_t)(p - result)); 7807 STRCPY(newres + (p - result), repl); 7808 len = strlen(newres); 7809 strcat(newres, p + srclen); 7810 xfree(repl); 7811 xfree(result); 7812 result = newres; 7813 p = newres + len; // continue after the match 7814 } 7815 } 7816 7817 return result; 7818 } 7819 7820 /// ":rshada" and ":wshada". 7821 static void ex_shada(exarg_T *eap) 7822 { 7823 char *save_shada = p_shada; 7824 if (*p_shada == NUL) { 7825 p_shada = "'100"; 7826 } 7827 if (eap->cmdidx == CMD_rviminfo || eap->cmdidx == CMD_rshada) { 7828 shada_read_everything(eap->arg, eap->forceit, false); 7829 } else { 7830 shada_write_file(eap->arg, eap->forceit); 7831 } 7832 p_shada = save_shada; 7833 } 7834 7835 /// Make a dialog message in "buff[DIALOG_MSG_SIZE]". 7836 /// "format" must contain "%s". 7837 void dialog_msg(char *buff, char *format, char *fname) 7838 { 7839 if (fname == NULL) { 7840 fname = _("Untitled"); 7841 } 7842 vim_snprintf(buff, DIALOG_MSG_SIZE, format, fname); 7843 } 7844 7845 static TriState filetype_detect = kNone; 7846 static TriState filetype_plugin = kNone; 7847 static TriState filetype_indent = kNone; 7848 7849 /// ":filetype [plugin] [indent] {on,off,detect}" 7850 /// on: Load the filetype.vim file to install autocommands for file types. 7851 /// off: Load the ftoff.vim file to remove all autocommands for file types. 7852 /// plugin on: load filetype.vim and ftplugin.vim 7853 /// plugin off: load ftplugof.vim 7854 /// indent on: load filetype.vim and indent.vim 7855 /// indent off: load indoff.vim 7856 static void ex_filetype(exarg_T *eap) 7857 { 7858 if (*eap->arg == NUL) { 7859 // Print current status. 7860 smsg(0, "filetype detection:%s plugin:%s indent:%s", 7861 filetype_detect == kTrue ? "ON" : "OFF", 7862 filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", 7863 filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF"); 7864 return; 7865 } 7866 7867 char *arg = eap->arg; 7868 bool plugin = false; 7869 bool indent = false; 7870 7871 // Accept "plugin" and "indent" in any order. 7872 while (true) { 7873 if (strncmp(arg, "plugin", 6) == 0) { 7874 plugin = true; 7875 arg = skipwhite(arg + 6); 7876 continue; 7877 } 7878 if (strncmp(arg, "indent", 6) == 0) { 7879 indent = true; 7880 arg = skipwhite(arg + 6); 7881 continue; 7882 } 7883 break; 7884 } 7885 if (strcmp(arg, "on") == 0 || strcmp(arg, "detect") == 0) { 7886 if (*arg == 'o' || filetype_detect != kTrue) { 7887 source_runtime(FILETYPE_FILE, DIP_ALL); 7888 filetype_detect = kTrue; 7889 if (plugin) { 7890 source_runtime(FTPLUGIN_FILE, DIP_ALL); 7891 filetype_plugin = kTrue; 7892 } 7893 if (indent) { 7894 source_runtime(INDENT_FILE, DIP_ALL); 7895 filetype_indent = kTrue; 7896 } 7897 } 7898 if (*arg == 'd') { 7899 do_doautocmd("filetypedetect BufRead", true, NULL); 7900 do_modelines(0); 7901 } 7902 } else if (strcmp(arg, "off") == 0) { 7903 if (plugin || indent) { 7904 if (plugin) { 7905 source_runtime(FTPLUGOF_FILE, DIP_ALL); 7906 filetype_plugin = kFalse; 7907 } 7908 if (indent) { 7909 source_runtime(INDOFF_FILE, DIP_ALL); 7910 filetype_indent = kFalse; 7911 } 7912 } else { 7913 source_runtime(FTOFF_FILE, DIP_ALL); 7914 filetype_detect = kFalse; 7915 } 7916 } else { 7917 semsg(_(e_invarg2), arg); 7918 } 7919 } 7920 7921 /// Source ftplugin.vim and indent.vim to create the necessary FileType 7922 /// autocommands. We do this separately from filetype.vim so that these 7923 /// autocommands will always fire first (and thus can be overridden) while still 7924 /// allowing general filetype detection to be disabled in the user's init file. 7925 void filetype_plugin_enable(void) 7926 { 7927 if (filetype_plugin == kNone) { 7928 source_runtime(FTPLUGIN_FILE, DIP_ALL); 7929 filetype_plugin = kTrue; 7930 } 7931 if (filetype_indent == kNone) { 7932 source_runtime(INDENT_FILE, DIP_ALL); 7933 filetype_indent = kTrue; 7934 } 7935 } 7936 7937 /// Enable filetype detection if the user did not explicitly disable it. 7938 void filetype_maybe_enable(void) 7939 { 7940 if (filetype_detect == kNone) { 7941 // Normally .vim files are sourced before .lua files when both are 7942 // supported, but we reverse the order here because we want the Lua 7943 // autocommand to be defined first so that it runs first 7944 source_runtime(FILETYPE_FILE, DIP_ALL); 7945 filetype_detect = kTrue; 7946 } 7947 } 7948 7949 /// ":setfiletype [FALLBACK] {name}" 7950 static void ex_setfiletype(exarg_T *eap) 7951 { 7952 if (curbuf->b_did_filetype) { 7953 return; 7954 } 7955 7956 char *arg = eap->arg; 7957 if (strncmp(arg, "FALLBACK ", 9) == 0) { 7958 arg += 9; 7959 } 7960 7961 set_option_value_give_err(kOptFiletype, CSTR_AS_OPTVAL(arg), OPT_LOCAL); 7962 if (arg != eap->arg) { 7963 curbuf->b_did_filetype = false; 7964 } 7965 } 7966 7967 static void ex_digraphs(exarg_T *eap) 7968 { 7969 if (*eap->arg != NUL) { 7970 putdigraph(eap->arg); 7971 } else { 7972 listdigraphs(eap->forceit); 7973 } 7974 } 7975 7976 void set_no_hlsearch(bool flag) 7977 { 7978 no_hlsearch = flag; 7979 set_vim_var_nr(VV_HLSEARCH, !no_hlsearch && p_hls); 7980 } 7981 7982 /// ":nohlsearch" 7983 static void ex_nohlsearch(exarg_T *eap) 7984 { 7985 set_no_hlsearch(true); 7986 redraw_all_later(UPD_SOME_VALID); 7987 } 7988 7989 static void ex_fold(exarg_T *eap) 7990 { 7991 if (foldManualAllowed(true)) { 7992 pos_T start = { eap->line1, 1, 0 }; 7993 pos_T end = { eap->line2, 1, 0 }; 7994 foldCreate(curwin, start, end); 7995 } 7996 } 7997 7998 static void ex_foldopen(exarg_T *eap) 7999 { 8000 pos_T start = { eap->line1, 1, 0 }; 8001 pos_T end = { eap->line2, 1, 0 }; 8002 opFoldRange(start, end, eap->cmdidx == CMD_foldopen, eap->forceit, false); 8003 } 8004 8005 static void ex_folddo(exarg_T *eap) 8006 { 8007 // First set the marks for all lines closed/open. 8008 for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { 8009 if (hasFolding(curwin, lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) { 8010 ml_setmarked(lnum); 8011 } 8012 } 8013 8014 global_exe(eap->arg); // Execute the command on the marked lines. 8015 ml_clearmarked(); // clear rest of the marks 8016 } 8017 8018 /// @return true if the supplied Ex cmdidx is for a location list command 8019 /// instead of a quickfix command. 8020 bool is_loclist_cmd(int cmdidx) 8021 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 8022 { 8023 if (cmdidx < 0 || cmdidx >= CMD_SIZE) { 8024 return false; 8025 } 8026 return cmdnames[cmdidx].cmd_name[0] == 'l'; 8027 } 8028 8029 bool get_pressedreturn(void) 8030 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 8031 { 8032 return ex_pressedreturn; 8033 } 8034 8035 void set_pressedreturn(bool val) 8036 { 8037 ex_pressedreturn = val; 8038 } 8039 8040 /// ":checkhealth [plugins]" 8041 static void ex_checkhealth(exarg_T *eap) 8042 { 8043 Error err = ERROR_INIT; 8044 MAXSIZE_TEMP_ARRAY(args, 2); 8045 8046 char mods[1024]; 8047 size_t mods_len = 0; 8048 mods[0] = NUL; 8049 8050 if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) { 8051 bool multi_mods = false; 8052 mods_len = add_win_cmd_modifiers(mods, &cmdmod, &multi_mods); 8053 assert(mods_len < sizeof(mods)); 8054 } 8055 ADD_C(args, STRING_OBJ(((String){ .data = mods, .size = mods_len }))); 8056 ADD_C(args, CSTR_AS_OBJ(eap->arg)); 8057 8058 NLUA_EXEC_STATIC("vim.health._check(...)", args, kRetNilBool, NULL, &err); 8059 if (!ERROR_SET(&err)) { 8060 return; 8061 } 8062 8063 char *vimruntime_env = os_getenv_noalloc("VIMRUNTIME"); 8064 if (!vimruntime_env) { 8065 emsg(_("E5009: $VIMRUNTIME is empty or unset")); 8066 } else { 8067 bool rtp_ok = NULL != strstr(p_rtp, vimruntime_env); 8068 if (rtp_ok) { 8069 semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env); 8070 } else { 8071 emsg(_("E5009: Invalid 'runtimepath'")); 8072 } 8073 } 8074 semsg_multiline("emsg", err.msg); 8075 api_clear_error(&err); 8076 } 8077 8078 static void ex_terminal(exarg_T *eap) 8079 { 8080 char ex_cmd[1024]; 8081 size_t len = 0; 8082 8083 if (cmdmod.cmod_tab > 0 || cmdmod.cmod_split != 0) { 8084 bool multi_mods = false; 8085 // ex_cmd must be a null-terminated string before passing to add_win_cmd_modifiers 8086 ex_cmd[0] = NUL; 8087 len = add_win_cmd_modifiers(ex_cmd, &cmdmod, &multi_mods); 8088 assert(len < sizeof(ex_cmd)); 8089 int result = snprintf(ex_cmd + len, sizeof(ex_cmd) - len, " new"); 8090 assert(result > 0); 8091 len += (size_t)result; 8092 } else { 8093 int result = snprintf(ex_cmd, sizeof(ex_cmd), "enew%s", eap->forceit ? "!" : ""); 8094 assert(result > 0); 8095 len += (size_t)result; 8096 } 8097 8098 assert(len < sizeof(ex_cmd)); 8099 8100 if (*eap->arg != NUL) { // Run {cmd} in 'shell'. 8101 char *name = vim_strsave_escaped(eap->arg, "\"\\"); 8102 snprintf(ex_cmd + len, sizeof(ex_cmd) - len, 8103 " | call jobstart(\"%s\",{'term':v:true})", name); 8104 xfree(name); 8105 } else { // No {cmd}: run the job with tokenized 'shell'. 8106 if (*p_sh == NUL) { 8107 emsg(_(e_shellempty)); 8108 return; 8109 } 8110 8111 char **argv = shell_build_argv(NULL, NULL); 8112 char **p = argv; 8113 char tempstring[512]; 8114 char shell_argv[512] = { 0 }; 8115 8116 while (*p != NULL) { 8117 char *escaped = vim_strsave_escaped(*p, "\"\\"); 8118 snprintf(tempstring, sizeof(tempstring), ",\"%s\"", escaped); 8119 xfree(escaped); 8120 xstrlcat(shell_argv, tempstring, sizeof(shell_argv)); 8121 p++; 8122 } 8123 shell_free_argv(argv); 8124 8125 snprintf(ex_cmd + len, sizeof(ex_cmd) - len, 8126 " | call jobstart([%s], {'term':v:true})", shell_argv + 1); 8127 } 8128 8129 do_cmdline_cmd(ex_cmd); 8130 } 8131 8132 /// ":lsp {subcmd} {clients}" 8133 static void ex_lsp(exarg_T *eap) 8134 { 8135 Error err = ERROR_INIT; 8136 MAXSIZE_TEMP_ARRAY(args, 1); 8137 8138 ADD_C(args, CSTR_AS_OBJ(eap->arg)); 8139 8140 NLUA_EXEC_STATIC("require'vim._core.ex_cmd'.ex_lsp(...)", args, kRetNilBool, NULL, &err); 8141 if (ERROR_SET(&err)) { 8142 emsg_multiline(err.msg, "lua_error", HLF_E, true); 8143 } 8144 api_clear_error(&err); 8145 } 8146 8147 /// ":fclose" 8148 static void ex_fclose(exarg_T *eap) 8149 { 8150 win_float_remove(eap->forceit, eap->line1); 8151 } 8152 8153 void verify_command(char *cmd) 8154 { 8155 if (strcmp("smile", cmd) != 0) { 8156 return; // acceptable non-existing command 8157 } 8158 int a = HLF_E; 8159 msg(" #xxn` #xnxx` ,+x@##@Mz;` .xxx" 8160 "xxxxxxnz+, znnnnnnnnnnnnnnnn.", a); 8161 msg(" n###z x####` :x##########W+` ,###" 8162 "##########M; W################.", a); 8163 msg(" n####; x####` `z##############W: ,###" 8164 "############# W################.", a); 8165 msg(" n####W. x####` ,W#################+ ,###" 8166 "############## W################.", a); 8167 msg(" n#####n x####` @################### ,###" 8168 "##############i W################.", a); 8169 msg(" n######i x####` .#########@W@########* ,###" 8170 "##############W`W################.", a); 8171 msg(" n######@. x####` x######W*. `;n#######: ,###" 8172 "#x,,,,:*M######iW###@:,,,,,,,,,,,`", a); 8173 msg(" n#######n x####` *######+` :M#####M ,###" 8174 "#n `x#####xW###@`", a); 8175 msg(" n########* x####``@####@; `x#####i ,###" 8176 "#n ,#####@W###@`", a); 8177 msg(" n########@ x####`*#####i `M####M ,###" 8178 "#n x#########@`", a); 8179 msg(" n######### x####`M####z :#####:,###" 8180 "#n z#########@`", a); 8181 msg(" n#########* x####,#####. n####+,###" 8182 "#n n#########@`", a); 8183 msg(" n####@####@, x####i####x ;####x,###" 8184 "#n `W#####@####+++++++++++i", a); 8185 msg(" n####*#####M` x#########* `####@,###" 8186 "#n i#####MW###############W", a); 8187 msg(" n####.######+ x####z####; W####,###" 8188 "#n i@######W###############W", a); 8189 msg(" n####.`W#####: x####n####: M####:###" 8190 "#@nnnnnW#######,W###############W", a); 8191 msg(" n####. :#####M`x####z####; W####,###" 8192 "##############z W###############W", a); 8193 msg(" n####. #######x#########* `####W,###" 8194 "#############W` W###############W", a); 8195 msg(" n####. `M#####W####i####x ;####x,###" 8196 "############W, W####+**********i", a); 8197 msg(" n####. ,##########,#####. n####+,###" 8198 "###########n. W###@`", a); 8199 msg(" n####. ##########`M####z :#####:,###" 8200 "########Wz: W###@`", a); 8201 msg(" n####. x#########`*#####i `M####M ,###" 8202 "#x.....` W###@`", a); 8203 msg(" n####. ,@########``@####@; `x#####i ,###" 8204 "#n W###@`", a); 8205 msg(" n####. *########` *#####@+` ,M#####M ,###" 8206 "#n W###@`", a); 8207 msg(" n####. x#######` x######W*. `;n######@: ,###" 8208 "#n W###@,,,,,,,,,,,,`", a); 8209 msg(" n####. .@######` .#########@W@########* ,###" 8210 "#n W################,", a); 8211 msg(" n####. i######` @################### ,###" 8212 "#n W################,", a); 8213 msg(" n####. n#####` ,W#################+ ,###" 8214 "#n W################,", a); 8215 msg(" n####. .@####` .n##############W; ,###" 8216 "#n W################,", a); 8217 msg(" n####. i####` :x##########W+` ,###" 8218 "#n W################,", a); 8219 msg(" +nnnn` +nnn` ,+x@##@Mz;` .nnn" 8220 "n+ zxxxxxxxxxxxxxxxx.", a); 8221 msg(" ", a); 8222 msg(" " 8223 " ,+M@#Mi", a); 8224 msg(" " 8225 " .z########", a); 8226 msg(" " 8227 " i@#########i", a); 8228 msg(" " 8229 " `############W`", a); 8230 msg(" " 8231 " `n#############i", a); 8232 msg(" " 8233 " `n##############n", a); 8234 msg(" `` " 8235 " z###############@`", a); 8236 msg(" `W@z, " 8237 " ##################,", a); 8238 msg(" *#####` " 8239 " i############@x@###i", a); 8240 msg(" ######M. " 8241 " :#############n`,W##+", a); 8242 msg(" +######@: " 8243 " .W#########M@##+ *##z", a); 8244 msg(" :#######@: " 8245 " `x########@#x###* ,##n", a); 8246 msg(" `@#######@; " 8247 " z#########M*@nW#i .##x", a); 8248 msg(" z########@i " 8249 " *###########WM#@#, `##x", a); 8250 msg(" i##########+ " 8251 " ;###########*n###@ `##x", a); 8252 msg(" `@#MM#######x, " 8253 " ,@#########zM,`z##M `@#x", a); 8254 msg(" n##M#W#######n. " 8255 " `.:i*+#zzzz##+i:.` ,W#########Wii,`n@#@` n@##n", a); 8256 msg(" ;###@#x#######n `,i" 8257 "#nW@#####@@WWW@@####@Mzi. ,W##########@z.. ;zM#+i####z", a); 8258 msg(" x####nz######## .;#x@##" 8259 "@Wn#*;,.` ``,:*#x@##M+, ;@########xz@WM+#` `n@#######", a); 8260 msg(" ,@####M########xi#@##@Mzi," 8261 "` .+x###Mi:n##########Mz```.:i *@######*", a); 8262 msg(" *#####W#########ix+:` " 8263 " :n#############z: `*.`M######i", a); 8264 msg(" i#W##nW@+@##@#M@; " 8265 " ;W@@##########W, i`x@#####,", a); 8266 msg(" `@@n@Wn#@iMW*#*: " 8267 " `iz#z@######x. M######`", a); 8268 msg(" z##zM###x`*, .` " 8269 " `iW#####W;:` +#####M", a); 8270 msg(" ,###nn##n` " 8271 " ,#####x;` ,;@######", a); 8272 msg(" x###xz#. " 8273 " in###+ `:######@.", a); 8274 msg(" ;####n+ " 8275 " `Mnx##xi` , zM#######", a); 8276 msg(" `W####+ " 8277 "i. `.+x###@#. :n,z######:", a); 8278 msg(" z####@` ;" 8279 "#: .ii@###@;.*M*z####@`", a); 8280 msg(" i####M ` `i@" 8281 "#, :: +#n##@+@##W####n", a); 8282 msg(" :####x ,i. ##xzM###" 8283 "@` i. .@@, .z####x#######*", a); 8284 msg(" ,###W; i##Wz########" 8285 "# :## z##n ,@########x###:", a); 8286 msg(" n##n `W###########M" 8287 "`;n, i#x ,###@i *W########W#@`", a); 8288 msg(" .@##+ `x###########@." 8289 " z#+ .M#W``x#####n` `;#######@z#x", a); 8290 msg(" n###z :W############@ " 8291 " z#* @##xM#######@n; `########nW+", a); 8292 msg(" ;####nW##############W " 8293 ":@#* `@#############* :########z@i`", a); 8294 msg(" M##################### " 8295 "M##: @#############@: *W########M#", a); 8296 msg(" ;#####################i." 8297 "##x` W#############W, :n########zx", a); 8298 msg(" x####################@.`" 8299 "x; @#############z. .@########W#", a); 8300 msg(" ,######################` " 8301 " W###############x*,` W######zM#i", a); 8302 msg(" #######################: " 8303 " z##################@x+*#zzi `@#########.", a); 8304 msg(" W########W#z#M#########; " 8305 " *##########################z :@#######@`", a); 8306 msg(" `@#######x`;#z ,x#######; " 8307 " z###########M###xnM@########* :M######@", a); 8308 msg(" i########, x#@` z######; " 8309 " *##########i *#@` `+########+` n######.", a); 8310 msg(" n#######@` M##, `W#####. " 8311 " *#########z ###; z########M: :W####n", a); 8312 msg(" M#######M n##. x####x " 8313 " `x########: z##+ M#########@; .n###+", a); 8314 msg(" W#######@` :#W `@####: " 8315 " `@######W i### ;###########@. n##n", a); 8316 msg(" W########z` ,, .x####z " 8317 " @######@` `W#; `W############* *###;", a); 8318 msg(" `@#########Mi,:*n@####W` " 8319 " W#######* .. `n#############i i###x", a); 8320 msg(" .#####################z " 8321 " `@#######@*` .x############n:` ;####.", a); 8322 msg(" :####################x`,,` " 8323 " `W#########@x#+#@#############i ,####:", a); 8324 msg(" ;###################x#@###x" 8325 "i` *############################: `####i", a); 8326 msg(" i##################+#######" 8327 "#M, x##########################@` W###i", a); 8328 msg(" *################@; @######" 8329 "##@, .W#########################@ x###:", a); 8330 msg(" .+M#############z. M######" 8331 "###x ,W########################@` ####.", a); 8332 msg(" *M*;z@########x: :W#####" 8333 "##i .M########################i i###:", a); 8334 msg(" *##@z;#@####x: :z###" 8335 "@i `########################x .###;", a); 8336 msg(" *#####n;#@## ;##" 8337 "* ,x#####################@` W##*", a); 8338 msg(" *#######n;* :M##" 8339 "W*, *W####################` n##z", a); 8340 msg(" i########@. ,*n####" 8341 "###M*` `###################M *##M", a); 8342 msg(" i########n `z#####@@" 8343 "#####Wi ,M################; ,##@`", a); 8344 msg(" ;WMWW@###* .x##@ni.``" 8345 ".:+zW##z` `n##############z @##,", a); 8346 msg(" .*++*i;;;. .M#@+` " 8347 " .##n `x############x` n##i", a); 8348 msg(" :########* x#W, " 8349 " *#+ *###########M` +##+", a); 8350 msg(" ,######### :#@: " 8351 " ##: #nzzzzzzzzzz. :##x", a); 8352 msg(" .#####Wz+` ##+ " 8353 " `MM` .znnnnnnnnn. `@#@`", a); 8354 msg(" `@@ni;*nMz` @W` " 8355 " :#+ .x#######n x##,", a); 8356 msg(" i;z@#####, .#* " 8357 " z#: ;;;*zW##; ###i", a); 8358 msg(" z########: :#; " 8359 " `Wx +###Wni;n. ;##z", a); 8360 msg(" n########W: .#* " 8361 " ,#, ;#######@+ `@#M", a); 8362 msg(" .###########n;.MM " 8363 " n* ;iM#######* x#@`", a); 8364 msg(" :#############@;; " 8365 " .n` ,#W*iW#####W` +##,", a); 8366 msg(" ,##############. " 8367 " ix. `x###M;####### ,##i", a); 8368 msg(" .#############@` " 8369 " x@n**#W######z;M###@. W##", a); 8370 msg(" .##############W: " 8371 " .x############@*;zW#; z#x", a); 8372 msg(" ,###############@; " 8373 " `##############@n*;. i#@", a); 8374 msg(" ,#################i " 8375 " :n##############W` .##,", a); 8376 msg(" ,###################` " 8377 " .+W##########W, `##i", a); 8378 msg(" :###################@zi,` " 8379 " ;zM@@@WMn*` @#z", a); 8380 msg(" :#######################@x+" 8381 "*i;;:i#M, `` M#W", a); 8382 msg(" ;##########################" 8383 "######@x. n##,", a); 8384 msg(" i#####################@W@@@" 8385 "@Wxz*:` *##+", a); 8386 msg(" *######################+```" 8387 " :##M", a); 8388 msg(" ########################M; " 8389 " `@##,", a); 8390 msg(" z#########################x" 8391 ", z###", a); 8392 msg(" n##########################" 8393 "#n: ;##W`", a); 8394 msg(" x##########################" 8395 "###Mz#++##* `W##i", a); 8396 msg(" M##########################" 8397 "##########@` ###x", a); 8398 msg(" W##########################" 8399 "###########` .###,", a); 8400 msg(" @##########################" 8401 "##########M n##z", a); 8402 msg(" @##################z*i@WMMM" 8403 "x#x@#####,. :##@.", a); 8404 msg(" `#####################@xi` " 8405 " `::,* x##+", a); 8406 msg(" .#####################@#M. " 8407 " ;##@`", a); 8408 msg(" ,#####################:. " 8409 " M##i", a); 8410 msg(" ;###################ni` " 8411 " i##M", a); 8412 msg(" *#################W#` " 8413 " `W##,", a); 8414 msg(" z#################@Wx+. " 8415 " +###", a); 8416 msg(" x######################z. " 8417 " .@#@`", a); 8418 msg(" `@#######################@; " 8419 " z##;", a); 8420 msg(" :##########################: " 8421 " :##z", a); 8422 msg(" +#########################W# " 8423 " M#W", a); 8424 msg(" W################@n+*i;:,` " 8425 " +##,", a); 8426 msg(" :##################WMxz+, " 8427 " ,##i", a); 8428 msg(" n#######################W.., " 8429 " W##", a); 8430 msg(" +#########################WW@+. .:. " 8431 " z#x", a); 8432 msg(" `@#############################@@###: " 8433 " *#W", a); 8434 msg(" #################################Wz: " 8435 " :#@", a); 8436 msg(",@###############################i " 8437 " .##", a); 8438 msg("n@@@@@@@#########################+ " 8439 " `##", a); 8440 msg("` `.:.`.,:iii;;;;;;;;iii;;;:` `.`` " 8441 " `nW", a); 8442 } 8443 8444 /// Get argt of command with id 8445 uint32_t get_cmd_argt(cmdidx_T cmdidx) 8446 { 8447 return cmdnames[(int)cmdidx].cmd_argt; 8448 } 8449 8450 /// Check if a command is a :map/:abbrev command. 8451 bool is_map_cmd(cmdidx_T cmdidx) 8452 { 8453 if (IS_USER_CMDIDX(cmdidx)) { 8454 return false; 8455 } 8456 8457 ex_func_T func = cmdnames[cmdidx].cmd_func; 8458 return func == ex_map // :map, :nmap, :noremap, etc. 8459 || func == ex_unmap // :unmap, :nunmap, etc. 8460 || func == ex_mapclear // :mapclear, :nmapclear, etc. 8461 || func == ex_abbreviate // :abbreviate, :iabbrev, etc. 8462 || func == ex_abclear; // :abclear, :iabclear, etc. 8463 }