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