buffer.c (135454B)
1 // 2 // buffer.c: functions for dealing with the buffer structure 3 // 4 5 // 6 // The buffer list is a double linked list of all buffers. 7 // Each buffer can be in one of these states: 8 // never loaded: BF_NEVERLOADED is set, only the file name is valid 9 // not loaded: b_ml.ml_mfp == NULL, no memfile allocated 10 // hidden: b_nwindows == 0, loaded but not displayed in a window 11 // normal: loaded and displayed in a window 12 // 13 // Instead of storing file names all over the place, each file name is 14 // stored in the buffer list. It can be referenced by a number. 15 // 16 // The current implementation remembers all file names ever used. 17 // 18 19 #include <assert.h> 20 #include <ctype.h> 21 #include <inttypes.h> 22 #include <stdbool.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/stat.h> 26 #include <time.h> 27 28 #include "auto/config.h" 29 #include "klib/kvec.h" 30 #include "nvim/api/private/helpers.h" 31 #include "nvim/arglist.h" 32 #include "nvim/ascii_defs.h" 33 #include "nvim/assert_defs.h" 34 #include "nvim/autocmd.h" 35 #include "nvim/autocmd_defs.h" 36 #include "nvim/buffer.h" 37 #include "nvim/buffer_updates.h" 38 #include "nvim/change.h" 39 #include "nvim/channel.h" 40 #include "nvim/charset.h" 41 #include "nvim/cmdexpand.h" 42 #include "nvim/cursor.h" 43 #include "nvim/diff.h" 44 #include "nvim/digraph.h" 45 #include "nvim/drawscreen.h" 46 #include "nvim/errors.h" 47 #include "nvim/eval/typval.h" 48 #include "nvim/eval/vars.h" 49 #include "nvim/ex_cmds.h" 50 #include "nvim/ex_cmds2.h" 51 #include "nvim/ex_cmds_defs.h" 52 #include "nvim/ex_docmd.h" 53 #include "nvim/ex_eval.h" 54 #include "nvim/ex_eval_defs.h" 55 #include "nvim/ex_getln.h" 56 #include "nvim/extmark.h" 57 #include "nvim/file_search.h" 58 #include "nvim/fileio.h" 59 #include "nvim/fold.h" 60 #include "nvim/fuzzy.h" 61 #include "nvim/garray.h" 62 #include "nvim/garray_defs.h" 63 #include "nvim/getchar.h" 64 #include "nvim/gettext_defs.h" 65 #include "nvim/globals.h" 66 #include "nvim/hashtab.h" 67 #include "nvim/hashtab_defs.h" 68 #include "nvim/help.h" 69 #include "nvim/indent.h" 70 #include "nvim/indent_c.h" 71 #include "nvim/insexpand.h" 72 #include "nvim/main.h" 73 #include "nvim/map_defs.h" 74 #include "nvim/mapping.h" 75 #include "nvim/mark.h" 76 #include "nvim/mark_defs.h" 77 #include "nvim/mbyte.h" 78 #include "nvim/memfile_defs.h" 79 #include "nvim/memline.h" 80 #include "nvim/memline_defs.h" 81 #include "nvim/memory.h" 82 #include "nvim/message.h" 83 #include "nvim/move.h" 84 #include "nvim/normal.h" 85 #include "nvim/option.h" 86 #include "nvim/option_defs.h" 87 #include "nvim/option_vars.h" 88 #include "nvim/optionstr.h" 89 #include "nvim/os/fs.h" 90 #include "nvim/os/fs_defs.h" 91 #include "nvim/os/input.h" 92 #include "nvim/os/os.h" 93 #include "nvim/os/os_defs.h" 94 #include "nvim/os/time.h" 95 #include "nvim/path.h" 96 #include "nvim/plines.h" 97 #include "nvim/pos_defs.h" 98 #include "nvim/quickfix.h" 99 #include "nvim/regexp.h" 100 #include "nvim/regexp_defs.h" 101 #include "nvim/runtime.h" 102 #include "nvim/runtime_defs.h" 103 #include "nvim/spell.h" 104 #include "nvim/state_defs.h" 105 #include "nvim/statusline.h" 106 #include "nvim/strings.h" 107 #include "nvim/syntax.h" 108 #include "nvim/terminal.h" 109 #include "nvim/ui.h" 110 #include "nvim/undo.h" 111 #include "nvim/usercmd.h" 112 #include "nvim/version.h" 113 #include "nvim/vim_defs.h" 114 #include "nvim/window.h" 115 #include "nvim/winfloat.h" 116 117 #include "buffer.c.generated.h" 118 119 #ifdef ABORT_ON_INTERNAL_ERROR 120 # define CHECK_CURBUF \ 121 do { \ 122 if (curwin != NULL && curwin->w_buffer != curbuf) { \ 123 iemsg("curbuf != curwin->w_buffer"); \ 124 } \ 125 } while (0) 126 #else 127 # define CHECK_CURBUF do {} while (0) 128 #endif 129 130 static const char e_attempt_to_delete_buffer_that_is_in_use_str[] 131 = N_("E937: Attempt to delete a buffer that is in use: %s"); 132 133 // Number of times free_buffer() was called. 134 static int buf_free_count = 0; 135 136 static int top_file_num = 1; ///< highest file number 137 138 typedef enum { 139 kBffClearWinInfo = 1, 140 kBffInitChangedtick = 2, 141 } BufFreeFlags; 142 143 static void trigger_undo_ftplugin(buf_T *buf, win_T *win) 144 { 145 const bool win_was_locked = win->w_locked; 146 window_layout_lock(); 147 buf->b_locked++; 148 win->w_locked = true; 149 // b:undo_ftplugin may be set, undo it 150 do_cmdline_cmd("if exists('b:undo_ftplugin') | exe b:undo_ftplugin | endif"); 151 buf->b_locked--; 152 win->w_locked = win_was_locked; 153 window_layout_unlock(); 154 } 155 156 /// Calculate the percentage that `part` is of the `whole`. 157 int calc_percentage(int64_t part, int64_t whole) 158 { 159 // With 32 bit longs and more than 21,474,836 lines multiplying by 100 160 // causes an overflow, thus for large numbers divide instead. 161 return (part > 1000000) ? (int)(part / (whole / 100)) 162 : (int)((part * 100) / whole); 163 } 164 165 /// @return the highest possible buffer number 166 int get_highest_fnum(void) 167 { 168 return top_file_num - 1; 169 } 170 171 /// Read data from buffer for retrying. 172 /// 173 /// @param read_stdin read file from stdin, otherwise fifo 174 /// @param eap for forced 'ff' and 'fenc' or NULL 175 /// @param flags extra flags for readfile() 176 static int read_buffer(bool read_stdin, exarg_T *eap, int flags) 177 { 178 int retval = OK; 179 bool silent = shortmess(SHM_FILEINFO); 180 181 // Read from the buffer which the text is already filled in and append at 182 // the end. This makes it possible to retry when 'fileformat' or 183 // 'fileencoding' was guessed wrong. 184 linenr_T line_count = curbuf->b_ml.ml_line_count; 185 retval = readfile(read_stdin ? NULL : curbuf->b_ffname, 186 read_stdin ? NULL : curbuf->b_fname, 187 line_count, 0, (linenr_T)MAXLNUM, eap, 188 flags | READ_BUFFER, silent); 189 if (retval == OK) { 190 // Delete the binary lines. 191 while (--line_count >= 0) { 192 ml_delete(1); 193 } 194 } else { 195 // Delete the converted lines. 196 while (curbuf->b_ml.ml_line_count > line_count) { 197 ml_delete(line_count); 198 } 199 } 200 // Put the cursor on the first line. 201 curwin->w_cursor.lnum = 1; 202 curwin->w_cursor.col = 0; 203 204 if (read_stdin) { 205 // Set or reset 'modified' before executing autocommands, so that 206 // it can be changed there. 207 if (!readonlymode && !buf_is_empty(curbuf)) { 208 changed(curbuf); 209 } else if (retval != FAIL) { 210 unchanged(curbuf, false, true); 211 } 212 213 apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, false, 214 curbuf, &retval); 215 } 216 return retval; 217 } 218 219 /// Ensure buffer "buf" is loaded. 220 bool buf_ensure_loaded(buf_T *buf) 221 { 222 if (buf->b_ml.ml_mfp != NULL) { 223 // already open (common case) 224 return true; 225 } 226 227 aco_save_T aco; 228 229 // Make sure the buffer is in a window. 230 aucmd_prepbuf(&aco, buf); 231 // status can be OK or NOTDONE (which also means ok/done) 232 int status = open_buffer(false, NULL, 0); 233 aucmd_restbuf(&aco); 234 return (status != FAIL); 235 } 236 237 /// Open current buffer, that is: open the memfile and read the file into 238 /// memory. 239 /// 240 /// @param read_stdin read file from stdin 241 /// @param eap for forced 'ff' and 'fenc' or NULL 242 /// @param flags_arg extra flags for readfile() 243 /// 244 /// @return FAIL for failure, OK otherwise. 245 int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) 246 { 247 int flags = flags_arg; 248 int retval = OK; 249 bufref_T old_curbuf; 250 OptInt old_tw = curbuf->b_p_tw; 251 bool read_fifo = false; 252 bool silent = shortmess(SHM_FILEINFO); 253 254 // The 'readonly' flag is only set when BF_NEVERLOADED is being reset. 255 // When re-entering the same buffer, it should not change, because the 256 // user may have reset the flag by hand. 257 if (readonlymode && curbuf->b_ffname != NULL 258 && (curbuf->b_flags & BF_NEVERLOADED)) { 259 curbuf->b_p_ro = true; 260 } 261 262 if (ml_open(curbuf) == FAIL) { 263 // There MUST be a memfile, otherwise we can't do anything 264 // If we can't create one for the current buffer, take another buffer 265 close_buffer(NULL, curbuf, 0, false, false); 266 267 curbuf = NULL; 268 FOR_ALL_BUFFERS(buf) { 269 if (buf->b_ml.ml_mfp != NULL) { 270 curbuf = buf; 271 break; 272 } 273 } 274 275 // If there is no memfile at all, exit. 276 // This is OK, since there are no changes to lose. 277 if (curbuf == NULL) { 278 emsg(_("E82: Cannot allocate any buffer, exiting...")); 279 280 // Don't try to do any saving, with "curbuf" NULL almost nothing 281 // will work. 282 v_dying = 2; 283 getout(2); 284 } 285 286 emsg(_("E83: Cannot allocate buffer, using other one...")); 287 enter_buffer(curbuf); 288 if (old_tw != curbuf->b_p_tw) { 289 check_colorcolumn(NULL, curwin); 290 } 291 return FAIL; 292 } 293 294 // Do not sync this buffer yet, may first want to read the file. 295 if (curbuf->b_ml.ml_mfp != NULL) { 296 curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES_NOSYNC; 297 } 298 299 // The autocommands in readfile() may change the buffer, but only AFTER 300 // reading the file. 301 set_bufref(&old_curbuf, curbuf); 302 curbuf->b_modified_was_set = false; 303 304 // mark cursor position as being invalid 305 curwin->w_valid = 0; 306 307 // A buffer without an actual file should not use the buffer name to read a 308 // file. 309 if (bt_nofileread(curbuf)) { 310 flags |= READ_NOFILE; 311 } 312 313 // Read the file if there is one. 314 if (curbuf->b_ffname != NULL) { 315 #ifdef UNIX 316 int save_bin = curbuf->b_p_bin; 317 int perm = os_getperm(curbuf->b_ffname); 318 if (perm >= 0 && (0 || S_ISFIFO(perm) 319 || S_ISSOCK(perm) 320 # ifdef OPEN_CHR_FILES 321 || (S_ISCHR(perm) 322 && is_dev_fd_file(curbuf->b_ffname)) 323 # endif 324 )) { 325 read_fifo = true; 326 } 327 if (read_fifo) { 328 curbuf->b_p_bin = true; 329 } 330 #endif 331 332 retval = readfile(curbuf->b_ffname, curbuf->b_fname, 333 0, 0, (linenr_T)MAXLNUM, eap, 334 flags | READ_NEW | (read_fifo ? READ_FIFO : 0), silent); 335 #ifdef UNIX 336 if (read_fifo) { 337 curbuf->b_p_bin = save_bin; 338 if (retval == OK) { 339 // don't add READ_FIFO here, otherwise we won't be able to 340 // detect the encoding 341 retval = read_buffer(false, eap, flags); 342 } 343 } 344 #endif 345 346 // Help buffer: populate *local-additions* in help.txt 347 if (bt_help(curbuf)) { 348 get_local_additions(); 349 } 350 } else if (read_stdin) { 351 int save_bin = curbuf->b_p_bin; 352 353 // First read the text in binary mode into the buffer. 354 // Then read from that same buffer and append at the end. This makes 355 // it possible to retry when 'fileformat' or 'fileencoding' was 356 // guessed wrong. 357 curbuf->b_p_bin = true; 358 retval = readfile(NULL, NULL, 0, 359 0, (linenr_T)MAXLNUM, NULL, 360 flags | (READ_NEW + READ_STDIN), silent); 361 curbuf->b_p_bin = save_bin; 362 if (retval == OK) { 363 retval = read_buffer(true, eap, flags); 364 } 365 } 366 367 // Can now sync this buffer in ml_sync_all(). 368 if (curbuf->b_ml.ml_mfp != NULL 369 && curbuf->b_ml.ml_mfp->mf_dirty == MF_DIRTY_YES_NOSYNC) { 370 curbuf->b_ml.ml_mfp->mf_dirty = MF_DIRTY_YES; 371 } 372 373 // if first time loading this buffer, init b_chartab[] 374 if (curbuf->b_flags & BF_NEVERLOADED) { 375 buf_init_chartab(curbuf, false); 376 parse_cino(curbuf); 377 } 378 379 // Set/reset the Changed flag first, autocmds may change the buffer. 380 // Apply the automatic commands, before processing the modelines. 381 // So the modelines have priority over autocommands. 382 383 // When reading stdin, the buffer contents always needs writing, so set 384 // the changed flag. Unless in readonly mode: "ls | nvim -R -". 385 // When interrupted and 'cpoptions' contains 'i' set changed flag. 386 if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) 387 || curbuf->b_modified_was_set // autocmd did ":set modified" 388 || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) { 389 changed(curbuf); 390 } else if (retval != FAIL && !read_stdin && !read_fifo) { 391 unchanged(curbuf, false, true); 392 } 393 save_file_ff(curbuf); // keep this fileformat 394 395 // Set last_changedtick to avoid triggering a TextChanged autocommand right 396 // after it was added. 397 curbuf->b_last_changedtick = buf_get_changedtick(curbuf); 398 curbuf->b_last_changedtick_i = buf_get_changedtick(curbuf); 399 curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf); 400 401 // require "!" to overwrite the file, because it wasn't read completely 402 if (aborting()) { 403 curbuf->b_flags |= BF_READERR; 404 } 405 406 // Need to update automatic folding. Do this before the autocommands, 407 // they may use the fold info. 408 foldUpdateAll(curwin); 409 410 // need to set w_topline, unless some autocommand already did that. 411 if (!(curwin->w_valid & VALID_TOPLINE)) { 412 curwin->w_topline = 1; 413 curwin->w_topfill = 0; 414 } 415 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, false, curbuf, &retval); 416 417 // if (retval != OK) { 418 if (retval == FAIL) { 419 return retval; 420 } 421 422 // The autocommands may have changed the current buffer. Apply the 423 // modelines to the correct buffer, if it still exists and is loaded. 424 if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL) { 425 aco_save_T aco; 426 427 // Go to the buffer that was opened, make sure it is in a window. 428 aucmd_prepbuf(&aco, old_curbuf.br_buf); 429 do_modelines(0); 430 curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); 431 432 if ((flags & READ_NOWINENTER) == 0) { 433 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, false, curbuf, 434 &retval); 435 } 436 437 // restore curwin/curbuf and a few other things 438 aucmd_restbuf(&aco); 439 } 440 441 return retval; 442 } 443 444 /// Store "buf" in "bufref" and set the free count. 445 /// 446 /// @param bufref Reference to be used for the buffer. 447 /// @param buf The buffer to reference. 448 void set_bufref(bufref_T *bufref, buf_T *buf) 449 { 450 bufref->br_buf = buf; 451 bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum; 452 bufref->br_buf_free_count = buf_free_count; 453 } 454 455 /// Return true if "bufref->br_buf" points to the same buffer as when 456 /// set_bufref() was called and it is a valid buffer. 457 /// Only goes through the buffer list if buf_free_count changed. 458 /// Also checks if b_fnum is still the same, a :bwipe followed by :new might get 459 /// the same allocated memory, but it's a different buffer. 460 /// 461 /// @param bufref Buffer reference to check for. 462 bool bufref_valid(bufref_T *bufref) 463 FUNC_ATTR_PURE 464 { 465 return bufref->br_buf_free_count == buf_free_count 466 ? true 467 : buf_valid(bufref->br_buf) && bufref->br_fnum == bufref->br_buf->b_fnum; 468 } 469 470 /// Check that "buf" points to a valid buffer in the buffer list. 471 /// 472 /// Can be slow if there are many buffers, prefer using bufref_valid(). 473 /// 474 /// @param buf The buffer to check for. 475 bool buf_valid(buf_T *buf) 476 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 477 { 478 if (buf == NULL) { 479 return false; 480 } 481 // Assume that we more often have a recent buffer, 482 // start with the last one. 483 for (buf_T *bp = lastbuf; bp != NULL; bp = bp->b_prev) { 484 if (bp == buf) { 485 return true; 486 } 487 } 488 return false; 489 } 490 491 /// Return true when buffer "buf" can be unloaded. 492 /// Give an error message and return false when the buffer is locked or the 493 /// screen is being redrawn and the buffer is in a window. 494 static bool can_unload_buffer(buf_T *buf) 495 { 496 bool can_unload = !buf->b_locked; 497 498 if (can_unload && updating_screen) { 499 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 500 if (wp->w_buffer == buf) { 501 can_unload = false; 502 break; 503 } 504 } 505 } 506 // Don't unload the buffer while it's still being saved 507 if (can_unload && buf->b_saving) { 508 can_unload = false; 509 } 510 511 if (!can_unload) { 512 char *fname = buf->b_fname != NULL ? buf->b_fname : buf->b_ffname; 513 semsg(_(e_attempt_to_delete_buffer_that_is_in_use_str), 514 fname != NULL ? fname : "[No Name]"); 515 } 516 return can_unload; 517 } 518 519 void buf_close_terminal(buf_T *buf) 520 { 521 assert(buf->terminal); 522 buf->b_locked++; 523 terminal_close(&buf->terminal, -1); 524 buf->b_locked--; 525 } 526 527 /// Close the link to a buffer. 528 /// 529 /// @param win If not NULL, set b_last_cursor. 530 /// @param buf 531 /// @param action Used when there is no longer a window for the buffer. 532 /// Possible values: 533 /// 0 buffer becomes hidden 534 /// DOBUF_UNLOAD buffer is unloaded 535 /// DOBUF_DEL buffer is unloaded and removed from buffer list 536 /// DOBUF_WIPE buffer is unloaded and really deleted 537 /// When doing all but the first one on the current buffer, the 538 /// caller should get a new buffer very soon! 539 /// The 'bufhidden' option can force freeing and deleting. 540 /// @param abort_if_last 541 /// If true, do not close the buffer if autocommands cause 542 /// there to be only one window with this buffer. e.g. when 543 /// ":quit" is supposed to close the window but autocommands 544 /// close all other windows. 545 /// @param ignore_abort 546 /// If true, don't abort even when aborting() returns true. 547 /// @return true if b_nwindows was decremented directly by this call (e.g: not via autocmds). 548 bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool ignore_abort) 549 { 550 bool unload_buf = (action != 0); 551 bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); 552 bool wipe_buf = (action == DOBUF_WIPE); 553 554 bool is_curwin = (curwin != NULL && curwin->w_buffer == buf); 555 win_T *the_curwin = curwin; 556 tabpage_T *the_curtab = curtab; 557 558 CHECK_CURBUF; 559 560 // Force unloading or deleting when 'bufhidden' says so, but not for terminal 561 // buffers. 562 // The caller must take care of NOT deleting/freeing when 'bufhidden' is 563 // "hide" (otherwise we could never free or delete a buffer). 564 if (!buf->terminal) { 565 if (buf->b_p_bh[0] == 'd') { // 'bufhidden' == "delete" 566 del_buf = true; 567 unload_buf = true; 568 } else if (buf->b_p_bh[0] == 'w') { // 'bufhidden' == "wipe" 569 del_buf = true; 570 unload_buf = true; 571 wipe_buf = true; 572 } else if (buf->b_p_bh[0] == 'u') { // 'bufhidden' == "unload" 573 unload_buf = true; 574 } 575 } 576 577 if (buf->terminal && (unload_buf || del_buf || wipe_buf)) { 578 // terminal buffers can only be wiped 579 unload_buf = true; 580 del_buf = true; 581 wipe_buf = true; 582 } 583 584 // Disallow deleting the buffer when it is locked (already being closed or 585 // halfway a command that relies on it). Unloading is allowed. 586 if ((del_buf || wipe_buf) && !can_unload_buffer(buf)) { 587 return false; 588 } 589 590 // check no autocommands closed the window 591 if (win != NULL // Avoid bogus clang warning. 592 && win_valid_any_tab(win)) { 593 // Set b_last_cursor when closing the last window for the buffer. 594 // Remember the last cursor position and window options of the buffer. 595 // This used to be only for the current window, but then options like 596 // 'foldmethod' may be lost with a ":only" command. 597 if (buf->b_nwindows == 1) { 598 set_last_cursor(win); 599 } 600 buflist_setfpos(buf, win, 601 win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, 602 win->w_cursor.col, win->w_config.style != kWinStyleMinimal); 603 } 604 605 bufref_T bufref; 606 set_bufref(&bufref, buf); 607 608 // When the buffer is no longer in a window, trigger BufWinLeave 609 if (buf->b_nwindows == 1) { 610 buf->b_locked++; 611 buf->b_locked_split++; 612 if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, false, 613 buf) && !bufref_valid(&bufref)) { 614 // Autocommands deleted the buffer. 615 emsg(_(e_auabort)); 616 return false; 617 } 618 buf->b_locked--; 619 buf->b_locked_split--; 620 if (abort_if_last && win != NULL && one_window(win, NULL)) { 621 // Autocommands made this the only window. 622 emsg(_(e_auabort)); 623 return false; 624 } 625 626 // When the buffer becomes hidden, but is not unloaded, trigger 627 // BufHidden 628 if (!unload_buf) { 629 buf->b_locked++; 630 buf->b_locked_split++; 631 if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, false, 632 buf) && !bufref_valid(&bufref)) { 633 // Autocommands deleted the buffer. 634 emsg(_(e_auabort)); 635 return false; 636 } 637 buf->b_locked--; 638 buf->b_locked_split--; 639 if (abort_if_last && win != NULL && one_window(win, NULL)) { 640 // Autocommands made this the only window. 641 emsg(_(e_auabort)); 642 return false; 643 } 644 } 645 // autocmds may abort script processing 646 if (!ignore_abort && aborting()) { 647 return false; 648 } 649 } 650 651 // If the buffer was in curwin and the window has changed, go back to that 652 // window, if it still exists. This avoids that ":edit x" triggering a 653 // "tabnext" BufUnload autocmd leaves a window behind without a buffer. 654 if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) { 655 block_autocmds(); 656 goto_tabpage_win(the_curtab, the_curwin); 657 unblock_autocmds(); 658 } 659 660 int nwindows = buf->b_nwindows; 661 662 // decrease the link count from windows (unless not in any window) 663 if (buf->b_nwindows > 0) { 664 buf->b_nwindows--; 665 } 666 667 if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0) { 668 diff_buf_delete(buf); // Clear 'diff' for hidden buffer. 669 } 670 671 // Return when a window is displaying the buffer or when it's not 672 // unloaded. 673 if (buf->b_nwindows > 0 || !unload_buf) { 674 return true; 675 } 676 677 // Always remove the buffer when there is no file name. 678 if (buf->b_ffname == NULL) { 679 del_buf = true; 680 } 681 682 // Free all things allocated for this buffer. 683 // Also calls the "BufDelete" autocommands when del_buf is true. 684 // Remember if we are closing the current buffer. Restore the number of 685 // windows, so that autocommands in buf_freeall() don't get confused. 686 bool is_curbuf = (buf == curbuf); 687 688 // When closing the current buffer stop Visual mode before freeing 689 // anything. 690 if (is_curbuf && VIsual_active 691 #if defined(EXITFREE) 692 && !entered_free_all_mem 693 #endif 694 ) { 695 end_visual_mode(); 696 } 697 698 buf->b_nwindows = nwindows; 699 700 buf_freeall(buf, ((del_buf ? BFA_DEL : 0) 701 + (wipe_buf ? BFA_WIPE : 0) 702 + (ignore_abort ? BFA_IGNORE_ABORT : 0))); 703 704 if (!bufref_valid(&bufref)) { 705 // Autocommands may have deleted the buffer. 706 return false; 707 } 708 // autocmds may abort script processing. 709 if (!ignore_abort && aborting()) { 710 return false; 711 } 712 713 // It's possible that autocommands change curbuf to the one being deleted. 714 // This might cause the previous curbuf to be deleted unexpectedly. But 715 // in some cases it's OK to delete the curbuf, because a new one is 716 // obtained anyway. Therefore only return if curbuf changed to the 717 // deleted buffer. 718 if (buf == curbuf && !is_curbuf) { 719 return false; 720 } 721 722 bool clear_w_buf = false; 723 if (win != NULL // Avoid bogus clang warning. 724 && win_valid_any_tab(win) 725 && win->w_buffer == buf) { 726 // Defer clearing w_buffer until after operations that may invoke dict 727 // watchers (e.g., buf_clear_file()), so callers like tabpagebuflist() 728 // never see a window in the winlist with a NULL buffer. 729 clear_w_buf = true; 730 } 731 732 // Autocommands may have opened or closed windows for this buffer. 733 // Decrement the count for the close we do here. 734 // Don't decrement b_nwindows if the buffer wasn't displayed in any window 735 // before calling buf_freeall(). 736 if (nwindows > 0 && buf->b_nwindows > 0) { 737 buf->b_nwindows--; 738 } 739 740 // Remove the buffer from the list. 741 // Do not wipe out the buffer if it is used in a window, or if autocommands 742 // wiped out all other buffers (unless when inside free_all_mem() where all 743 // buffers need to be freed and autocommands are blocked). 744 if (wipe_buf && buf->b_nwindows <= 0 && (buf->b_prev != NULL || buf->b_next != NULL 745 #if defined(EXITFREE) 746 || entered_free_all_mem 747 #endif 748 )) { 749 if (clear_w_buf) { 750 win->w_buffer = NULL; 751 } 752 FOR_ALL_TAB_WINDOWS(tp, wp) { 753 mark_forget_file(wp, buf->b_fnum); 754 } 755 if (buf->b_sfname != buf->b_ffname) { 756 XFREE_CLEAR(buf->b_sfname); 757 } else { 758 buf->b_sfname = NULL; 759 } 760 XFREE_CLEAR(buf->b_ffname); 761 if (buf->b_prev == NULL) { 762 firstbuf = buf->b_next; 763 } else { 764 buf->b_prev->b_next = buf->b_next; 765 } 766 if (buf->b_next == NULL) { 767 lastbuf = buf->b_prev; 768 } else { 769 buf->b_next->b_prev = buf->b_prev; 770 } 771 free_buffer(buf); 772 } else { 773 if (del_buf) { 774 // Free all internal variables and reset option values, to make 775 // ":bdel" compatible with Vim 5.7. 776 free_buffer_stuff(buf, kBffClearWinInfo | kBffInitChangedtick); 777 778 // Make it look like a new buffer. 779 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; 780 781 // Init the options when loaded again. 782 buf->b_p_initialized = false; 783 } 784 buf_clear_file(buf); 785 if (clear_w_buf) { 786 win->w_buffer = NULL; 787 } 788 if (del_buf) { 789 buf->b_p_bl = false; 790 } 791 } 792 // NOTE: at this point "curbuf" may be invalid! 793 return true; 794 } 795 796 /// Make buffer not contain a file. 797 void buf_clear_file(buf_T *buf) 798 { 799 buf->b_ml.ml_line_count = 1; 800 unchanged(buf, true, true); 801 buf->b_p_eof = false; 802 buf->b_start_eof = false; 803 buf->b_p_eol = true; 804 buf->b_start_eol = true; 805 buf->b_p_bomb = false; 806 buf->b_start_bomb = false; 807 buf->b_ml.ml_mfp = NULL; 808 buf->b_ml.ml_flags = ML_EMPTY; // empty buffer 809 } 810 811 /// Clears the current buffer contents. 812 void buf_clear(void) 813 { 814 linenr_T line_count = curbuf->b_ml.ml_line_count; 815 extmark_free_all(curbuf); // delete any extmarks 816 while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) { 817 ml_delete(1); 818 } 819 deleted_lines_mark(1, line_count); // prepare for display 820 } 821 822 /// buf_freeall() - free all things allocated for a buffer that are related to 823 /// the file. Careful: get here with "curwin" NULL when exiting. 824 /// 825 /// @param flags BFA_DEL buffer is going to be deleted 826 /// BFA_WIPE buffer is going to be wiped out 827 /// BFA_KEEP_UNDO do not free undo information 828 /// BFA_IGNORE_ABORT don't abort even when aborting() returns true 829 void buf_freeall(buf_T *buf, int flags) 830 { 831 bool is_curbuf = (buf == curbuf); 832 int is_curwin = (curwin != NULL && curwin->w_buffer == buf); 833 win_T *the_curwin = curwin; 834 tabpage_T *the_curtab = curtab; 835 836 // Make sure the buffer isn't closed by autocommands. 837 buf->b_locked++; 838 buf->b_locked_split++; 839 840 bufref_T bufref; 841 set_bufref(&bufref, buf); 842 843 if (buf->terminal) { 844 buf_close_terminal(buf); 845 } 846 847 buf_updates_unload(buf, false); 848 849 if ((buf->b_ml.ml_mfp != NULL) 850 && apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf) 851 && !bufref_valid(&bufref)) { 852 // Autocommands deleted the buffer. 853 return; 854 } 855 if ((flags & BFA_DEL) 856 && buf->b_p_bl 857 && apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, false, buf) 858 && !bufref_valid(&bufref)) { 859 // Autocommands may delete the buffer. 860 return; 861 } 862 if ((flags & BFA_WIPE) 863 && apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, false, 864 buf) 865 && !bufref_valid(&bufref)) { 866 // Autocommands may delete the buffer. 867 return; 868 } 869 buf->b_locked--; 870 buf->b_locked_split--; 871 872 // If the buffer was in curwin and the window has changed, go back to that 873 // window, if it still exists. This avoids that ":edit x" triggering a 874 // "tabnext" BufUnload autocmd leaves a window behind without a buffer. 875 if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) { 876 block_autocmds(); 877 goto_tabpage_win(the_curtab, the_curwin); 878 unblock_autocmds(); 879 } 880 // autocmds may abort script processing 881 if ((flags & BFA_IGNORE_ABORT) == 0 && aborting()) { 882 return; 883 } 884 885 // It's possible that autocommands change curbuf to the one being deleted. 886 // This might cause curbuf to be deleted unexpectedly. But in some cases 887 // it's OK to delete the curbuf, because a new one is obtained anyway. 888 // Therefore only return if curbuf changed to the deleted buffer. 889 if (buf == curbuf && !is_curbuf) { 890 return; 891 } 892 diff_buf_delete(buf); // Can't use 'diff' for unloaded buffer. 893 // Remove any ownsyntax, unless exiting. 894 if (curwin != NULL && curwin->w_buffer == buf) { 895 reset_synblock(curwin); 896 } 897 898 // No folds in an empty buffer. 899 FOR_ALL_TAB_WINDOWS(tp, win) { 900 if (win->w_buffer == buf) { 901 clearFolding(win); 902 } 903 } 904 905 // Autocommands may have opened another terminal. Block them this time. 906 if (buf->terminal) { 907 block_autocmds(); 908 buf_close_terminal(buf); 909 unblock_autocmds(); 910 } 911 912 ml_close(buf, true); // close and delete the memline/memfile 913 buf->b_ml.ml_line_count = 0; // no lines in buffer 914 if ((flags & BFA_KEEP_UNDO) == 0) { 915 // free the memory allocated for undo 916 // and reset all undo information 917 u_clearallandblockfree(buf); 918 } 919 syntax_clear(&buf->b_s); // reset syntax info 920 buf->b_flags &= ~BF_READERR; // a read error is no longer relevant 921 } 922 923 /// Free a buffer structure and the things it contains related to the buffer 924 /// itself (not the file, that must have been done already). 925 static void free_buffer(buf_T *buf) 926 { 927 pmap_del(int)(&buffer_handles, buf->b_fnum, NULL); 928 buf_free_count++; 929 // b:changedtick uses an item in buf_T. 930 free_buffer_stuff(buf, kBffClearWinInfo); 931 if (buf->b_vars->dv_refcount > DO_NOT_FREE_CNT) { 932 tv_dict_add(buf->b_vars, 933 tv_dict_item_copy((dictitem_T *)(&buf->changedtick_di))); 934 } 935 unref_var_dict(buf->b_vars); 936 aubuflocal_remove(buf); 937 xfree(buf->additional_data); 938 xfree(buf->b_prompt_text); 939 kv_destroy(buf->b_wininfo); 940 callback_free(&buf->b_prompt_callback); 941 callback_free(&buf->b_prompt_interrupt); 942 clear_fmark(&buf->b_last_cursor, 0); 943 clear_fmark(&buf->b_last_insert, 0); 944 clear_fmark(&buf->b_last_change, 0); 945 clear_fmark(&buf->b_prompt_start, 0); 946 for (size_t i = 0; i < NMARKS; i++) { 947 free_fmark(buf->b_namedm[i]); 948 } 949 for (int i = 0; i < buf->b_changelistlen; i++) { 950 free_fmark(buf->b_changelist[i]); 951 } 952 if (autocmd_busy) { 953 // Do not free the buffer structure while autocommands are executing, 954 // it's still needed. Free it when autocmd_busy is reset. 955 CLEAR_FIELD(buf->b_namedm); 956 CLEAR_FIELD(buf->b_changelist); 957 buf->b_next = au_pending_free_buf; 958 au_pending_free_buf = buf; 959 } else { 960 xfree(buf); 961 if (curbuf == buf) { 962 curbuf = NULL; // make clear it's not to be used 963 } 964 } 965 } 966 967 /// Free the b_wininfo list for buffer "buf". 968 static void clear_wininfo(buf_T *buf) 969 { 970 for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) { 971 free_wininfo(kv_A(buf->b_wininfo, i), buf); 972 } 973 kv_size(buf->b_wininfo) = 0; 974 } 975 976 /// Free stuff in the buffer for ":bdel" and when wiping out the buffer. 977 /// 978 /// @param buf Buffer pointer 979 /// @param free_flags BufFreeFlags 980 static void free_buffer_stuff(buf_T *buf, int free_flags) 981 { 982 if (free_flags & kBffClearWinInfo) { 983 clear_wininfo(buf); // including window-local options 984 free_buf_options(buf, true); 985 ga_clear(&buf->b_s.b_langp); 986 } 987 { 988 // Avoid losing b:changedtick when deleting buffer: clearing variables 989 // implies using clear_tv() on b:changedtick and that sets changedtick to 990 // zero. 991 hashitem_T *const changedtick_hi = hash_find(&buf->b_vars->dv_hashtab, "changedtick"); 992 assert(changedtick_hi != NULL); 993 hash_remove(&buf->b_vars->dv_hashtab, changedtick_hi); 994 } 995 vars_clear(&buf->b_vars->dv_hashtab); // free all internal variables 996 hash_init(&buf->b_vars->dv_hashtab); 997 if (free_flags & kBffInitChangedtick) { 998 buf_init_changedtick(buf); 999 } 1000 uc_clear(&buf->b_ucmds); // clear local user commands 1001 extmark_free_all(buf); // delete any extmarks 1002 map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings 1003 map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs 1004 XFREE_CLEAR(buf->b_start_fenc); 1005 1006 buf_free_callbacks(buf); 1007 } 1008 1009 /// Go to another buffer. Handles the result of the ATTENTION dialog. 1010 void goto_buffer(exarg_T *eap, int start, int dir, int count) 1011 { 1012 const int save_sea = swap_exists_action; 1013 bool skip_help_buf; 1014 1015 switch (eap->cmdidx) { 1016 case CMD_bnext: 1017 case CMD_sbnext: 1018 case CMD_bNext: 1019 case CMD_bprevious: 1020 case CMD_sbNext: 1021 case CMD_sbprevious: 1022 skip_help_buf = true; 1023 break; 1024 default: 1025 skip_help_buf = false; 1026 break; 1027 } 1028 1029 bufref_T old_curbuf; 1030 set_bufref(&old_curbuf, curbuf); 1031 1032 if (swap_exists_action == SEA_NONE) { 1033 swap_exists_action = SEA_DIALOG; 1034 } 1035 (void)do_buffer_ext(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, 1036 (eap->forceit ? DOBUF_FORCEIT : 0) | 1037 (skip_help_buf ? DOBUF_SKIPHELP : 0)); 1038 1039 if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') { 1040 cleanup_T cs; 1041 1042 // Reset the error/interrupt/exception state here so that 1043 // aborting() returns false when closing a window. 1044 enter_cleanup(&cs); 1045 1046 // Quitting means closing the split window, nothing else. 1047 win_close(curwin, true, false); 1048 swap_exists_action = save_sea; 1049 swap_exists_did_quit = true; 1050 1051 // Restore the error/interrupt/exception state if not discarded by a 1052 // new aborting error, interrupt, or uncaught exception. 1053 leave_cleanup(&cs); 1054 } else { 1055 handle_swap_exists(&old_curbuf); 1056 } 1057 } 1058 1059 /// Handle the situation of swap_exists_action being set. 1060 /// 1061 /// It is allowed for "old_curbuf" to be NULL or invalid. 1062 /// 1063 /// @param old_curbuf The buffer to check for. 1064 void handle_swap_exists(bufref_T *old_curbuf) 1065 { 1066 cleanup_T cs; 1067 OptInt old_tw = curbuf->b_p_tw; 1068 buf_T *buf; 1069 1070 if (swap_exists_action == SEA_QUIT) { 1071 // Reset the error/interrupt/exception state here so that 1072 // aborting() returns false when closing a buffer. 1073 enter_cleanup(&cs); 1074 1075 // User selected Quit at ATTENTION prompt. Go back to previous 1076 // buffer. If that buffer is gone or the same as the current one, 1077 // open a new, empty buffer. 1078 swap_exists_action = SEA_NONE; // don't want it again 1079 swap_exists_did_quit = true; 1080 close_buffer(curwin, curbuf, DOBUF_UNLOAD, false, false); 1081 if (old_curbuf == NULL 1082 || !bufref_valid(old_curbuf) 1083 || old_curbuf->br_buf == curbuf) { 1084 // Block autocommands here because curwin->w_buffer is NULL. 1085 block_autocmds(); 1086 buf = buflist_new(NULL, NULL, 1, BLN_CURBUF | BLN_LISTED); 1087 unblock_autocmds(); 1088 } else { 1089 buf = old_curbuf->br_buf; 1090 } 1091 if (buf != NULL) { 1092 enter_buffer(buf); 1093 1094 if (old_tw != curbuf->b_p_tw) { 1095 check_colorcolumn(NULL, curwin); 1096 } 1097 } 1098 // If "old_curbuf" is NULL we are in big trouble here... 1099 1100 // Restore the error/interrupt/exception state if not discarded by a 1101 // new aborting error, interrupt, or uncaught exception. 1102 leave_cleanup(&cs); 1103 } else if (swap_exists_action == SEA_RECOVER) { 1104 // Reset the error/interrupt/exception state here so that 1105 // aborting() returns false when closing a buffer. 1106 enter_cleanup(&cs); 1107 1108 // User selected Recover at ATTENTION prompt. 1109 msg_scroll = true; 1110 ml_recover(false); 1111 msg_puts("\n"); // don't overwrite the last message 1112 cmdline_row = msg_row; 1113 do_modelines(0); 1114 1115 // Restore the error/interrupt/exception state if not discarded by a 1116 // new aborting error, interrupt, or uncaught exception. 1117 leave_cleanup(&cs); 1118 } 1119 swap_exists_action = SEA_NONE; 1120 } 1121 1122 /// do_bufdel() - delete or unload buffer(s) 1123 /// 1124 /// addr_count == 0: ":bdel" - delete current buffer 1125 /// addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete 1126 /// buffer "end_bnr", then any other arguments. 1127 /// addr_count == 2: ":N,N bdel" - delete buffers in range 1128 /// 1129 /// command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or 1130 /// DOBUF_DEL (":bdel") 1131 /// 1132 /// @param arg pointer to extra arguments 1133 /// @param start_bnr first buffer number in a range 1134 /// @param end_bnr buffer nr or last buffer nr in a range 1135 /// 1136 /// @return error message or NULL 1137 char *do_bufdel(int command, char *arg, int addr_count, int start_bnr, int end_bnr, int forceit) 1138 { 1139 int do_current = 0; // delete current buffer? 1140 int deleted = 0; // number of buffers deleted 1141 char *errormsg = NULL; // return value 1142 int bnr; // buffer number 1143 1144 if (addr_count == 0) { 1145 do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); 1146 } else { 1147 if (addr_count == 2) { 1148 if (*arg) { // both range and argument is not allowed 1149 return ex_errmsg(e_trailing_arg, arg); 1150 } 1151 bnr = start_bnr; 1152 } else { // addr_count == 1 1153 bnr = end_bnr; 1154 } 1155 1156 for (; !got_int; os_breakcheck()) { 1157 // delete the current buffer last, otherwise when the 1158 // current buffer is deleted, the next buffer becomes 1159 // the current one and will be loaded, which may then 1160 // also be deleted, etc. 1161 if (bnr == curbuf->b_fnum) { 1162 do_current = bnr; 1163 } else if (do_buffer(command, DOBUF_FIRST, FORWARD, bnr, 1164 forceit) == OK) { 1165 deleted++; 1166 } 1167 1168 // find next buffer number to delete/unload 1169 if (addr_count == 2) { 1170 if (++bnr > end_bnr) { 1171 break; 1172 } 1173 } else { // addr_count == 1 1174 arg = skipwhite(arg); 1175 if (*arg == NUL) { 1176 break; 1177 } 1178 if (!ascii_isdigit(*arg)) { 1179 char *p = skiptowhite_esc(arg); 1180 bnr = buflist_findpat(arg, p, command == DOBUF_WIPE, false, false); 1181 if (bnr < 0) { // failed 1182 break; 1183 } 1184 arg = p; 1185 } else { 1186 bnr = getdigits_int(&arg, false, 0); 1187 } 1188 } 1189 } 1190 if (!got_int && do_current 1191 && do_buffer(command, DOBUF_FIRST, 1192 FORWARD, do_current, forceit) == OK) { 1193 deleted++; 1194 } 1195 1196 if (deleted == 0) { 1197 if (command == DOBUF_UNLOAD) { 1198 xstrlcpy(IObuff, _("E515: No buffers were unloaded"), IOSIZE); 1199 } else if (command == DOBUF_DEL) { 1200 xstrlcpy(IObuff, _("E516: No buffers were deleted"), IOSIZE); 1201 } else { 1202 xstrlcpy(IObuff, _("E517: No buffers were wiped out"), IOSIZE); 1203 } 1204 errormsg = IObuff; 1205 } else if (deleted >= p_report) { 1206 if (command == DOBUF_UNLOAD) { 1207 smsg(0, NGETTEXT("%d buffer unloaded", "%d buffers unloaded", deleted), 1208 deleted); 1209 } else if (command == DOBUF_DEL) { 1210 smsg(0, NGETTEXT("%d buffer deleted", "%d buffers deleted", deleted), 1211 deleted); 1212 } else { 1213 smsg(0, NGETTEXT("%d buffer wiped out", "%d buffers wiped out", deleted), 1214 deleted); 1215 } 1216 } 1217 } 1218 1219 return errormsg; 1220 } 1221 1222 /// Make the current buffer empty. 1223 /// Used when it is wiped out and it's the last buffer. 1224 static int empty_curbuf(bool close_others, int forceit, int action) 1225 { 1226 buf_T *buf = curbuf; 1227 1228 if (action == DOBUF_UNLOAD) { 1229 emsg(_("E90: Cannot unload last buffer")); 1230 return FAIL; 1231 } 1232 1233 bufref_T bufref; 1234 set_bufref(&bufref, buf); 1235 1236 if (close_others) { 1237 bool can_close_all_others = true; 1238 if (curwin->w_floating) { 1239 // Closing all other windows with this buffer may leave only floating windows. 1240 can_close_all_others = false; 1241 for (win_T *wp = firstwin; !wp->w_floating; wp = wp->w_next) { 1242 if (wp->w_buffer != curbuf) { 1243 // Found another non-floating window with a different (probably unlisted) buffer. 1244 // Closing all other windows with this buffer is fine in this case. 1245 can_close_all_others = true; 1246 break; 1247 } 1248 } 1249 } 1250 // If it is fine to close all other windows with this buffer, keep the current window and 1251 // close any other windows with this buffer, then make it empty. 1252 // Otherwise close_windows() will refuse to close the last non-floating window, so allow it 1253 // to close the current window instead. 1254 close_windows(buf, can_close_all_others); 1255 } 1256 1257 setpcmark(); 1258 int retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, forceit ? ECMD_FORCEIT : 0, curwin); 1259 1260 // do_ecmd() may create a new buffer, then we have to delete 1261 // the old one. But do_ecmd() may have done that already, check 1262 // if the buffer still exists. 1263 if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) { 1264 close_buffer(NULL, buf, action, false, false); 1265 } 1266 1267 if (!close_others) { 1268 need_fileinfo = false; 1269 } 1270 1271 return retval; 1272 } 1273 1274 /// Implementation of the commands for the buffer list. 1275 /// 1276 /// action == DOBUF_GOTO go to specified buffer 1277 /// action == DOBUF_SPLIT split window and go to specified buffer 1278 /// action == DOBUF_UNLOAD unload specified buffer(s) 1279 /// action == DOBUF_DEL delete specified buffer(s) from buffer list 1280 /// action == DOBUF_WIPE delete specified buffer(s) really 1281 /// 1282 /// start == DOBUF_CURRENT go to "count" buffer from current buffer 1283 /// start == DOBUF_FIRST go to "count" buffer from first buffer 1284 /// start == DOBUF_LAST go to "count" buffer from last buffer 1285 /// start == DOBUF_MOD go to "count" modified buffer from current buffer 1286 /// 1287 /// @param dir FORWARD or BACKWARD 1288 /// @param count buffer number or number of buffers 1289 /// @param flags see @ref dobuf_flags_value 1290 /// 1291 /// @return FAIL or OK. 1292 static int do_buffer_ext(int action, int start, int dir, int count, int flags) 1293 { 1294 buf_T *buf; 1295 buf_T *bp; 1296 bool update_jumplist = true; 1297 bool unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL 1298 || action == DOBUF_WIPE); 1299 1300 switch (start) { 1301 case DOBUF_FIRST: 1302 buf = firstbuf; break; 1303 case DOBUF_LAST: 1304 buf = lastbuf; break; 1305 default: 1306 buf = curbuf; break; 1307 } 1308 if (start == DOBUF_MOD) { // find next modified buffer 1309 while (count-- > 0) { 1310 do { 1311 buf = buf->b_next; 1312 if (buf == NULL) { 1313 buf = firstbuf; 1314 } 1315 } while (buf != curbuf && !bufIsChanged(buf)); 1316 } 1317 if (!bufIsChanged(buf)) { 1318 emsg(_("E84: No modified buffer found")); 1319 return FAIL; 1320 } 1321 } else if (start == DOBUF_FIRST && count) { // find specified buffer number 1322 while (buf != NULL && buf->b_fnum != count) { 1323 buf = buf->b_next; 1324 } 1325 } else { 1326 const bool help_only = (flags & DOBUF_SKIPHELP) != 0 && buf->b_help; 1327 1328 bp = NULL; 1329 while (count > 0 || (bp != buf && !unload 1330 && !(help_only ? buf->b_help : buf->b_p_bl))) { 1331 // remember the buffer where we start, we come back there when all 1332 // buffers are unlisted. 1333 if (bp == NULL) { 1334 bp = buf; 1335 } 1336 buf = dir == FORWARD ? (buf->b_next != NULL ? buf->b_next : firstbuf) 1337 : (buf->b_prev != NULL ? buf->b_prev : lastbuf); 1338 // Avoid non-help buffers if the starting point was a help buffer 1339 // and vice-versa. 1340 // Don't count unlisted buffers. 1341 if (unload 1342 || (help_only 1343 ? buf->b_help 1344 : (buf->b_p_bl && ((flags & DOBUF_SKIPHELP) == 0 || !buf->b_help)))) { 1345 count--; 1346 bp = NULL; // use this buffer as new starting point 1347 } 1348 if (bp == buf) { 1349 // back where we started, didn't find anything. 1350 emsg(_("E85: There is no listed buffer")); 1351 return FAIL; 1352 } 1353 } 1354 } 1355 1356 if (buf == NULL) { // could not find it 1357 if (start == DOBUF_FIRST) { 1358 // don't warn when deleting 1359 if (!unload) { 1360 semsg(_(e_nobufnr), (int64_t)count); 1361 } 1362 } else if (dir == FORWARD) { 1363 emsg(_("E87: Cannot go beyond last buffer")); 1364 } else { 1365 emsg(_("E88: Cannot go before first buffer")); 1366 } 1367 return FAIL; 1368 } 1369 1370 if (action == DOBUF_GOTO && buf != curbuf 1371 && !check_can_set_curbuf_forceit((flags & DOBUF_FORCEIT) != 0)) { 1372 // disallow navigating to another buffer when 'winfixbuf' is applied 1373 return FAIL; 1374 } 1375 1376 if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) { 1377 // disallow navigating to the dummy buffer 1378 semsg(_(e_nobufnr), count); 1379 return FAIL; 1380 } 1381 1382 // delete buffer "buf" from memory and/or the list 1383 if (unload) { 1384 int forward; 1385 bufref_T bufref; 1386 if (!can_unload_buffer(buf)) { 1387 return FAIL; 1388 } 1389 set_bufref(&bufref, buf); 1390 1391 // When unloading or deleting a buffer that's already unloaded and 1392 // unlisted: fail silently. 1393 if (action != DOBUF_WIPE && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl) { 1394 return FAIL; 1395 } 1396 1397 if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf)) { 1398 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { 1399 dialog_changed(buf, false); 1400 if (!bufref_valid(&bufref)) { 1401 // Autocommand deleted buffer, oops! It's not changed now. 1402 return FAIL; 1403 } 1404 // If it's still changed fail silently, the dialog already 1405 // mentioned why it fails. 1406 if (bufIsChanged(buf)) { 1407 return FAIL; 1408 } 1409 } else { 1410 semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), 1411 buf->b_fnum); 1412 return FAIL; 1413 } 1414 } 1415 1416 if (!(flags & DOBUF_FORCEIT) && buf->terminal && terminal_running(buf->terminal)) { 1417 if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) { 1418 if (!dialog_close_terminal(buf)) { 1419 return FAIL; 1420 } 1421 } else { 1422 semsg(_("E89: %s will be killed (add ! to override)"), buf->b_fname); 1423 return FAIL; 1424 } 1425 } 1426 1427 int buf_fnum = buf->b_fnum; 1428 1429 // When closing the current buffer stop Visual mode. 1430 if (buf == curbuf && VIsual_active) { 1431 end_visual_mode(); 1432 } 1433 1434 // If deleting the last (listed) buffer, make it empty. 1435 // The last (listed) buffer cannot be unloaded. 1436 bp = NULL; 1437 FOR_ALL_BUFFERS(bp2) { 1438 if (bp2->b_p_bl && bp2 != buf) { 1439 bp = bp2; 1440 break; 1441 } 1442 } 1443 if (bp == NULL && buf == curbuf) { 1444 return empty_curbuf(true, (flags & DOBUF_FORCEIT), action); 1445 } 1446 1447 // If the deleted buffer is the current one, close the current window 1448 // (unless it's the only non-floating window). 1449 // When the autocommand window is involved win_close() may need to print an error message. 1450 // Repeat this so long as we end up in a window with this buffer. 1451 while (buf == curbuf 1452 && !(win_locked(curwin) || curwin->w_buffer->b_locked > 0) 1453 && (is_aucmd_win(lastwin) || !last_window(curwin))) { 1454 if (win_close(curwin, false, false) == FAIL) { 1455 break; 1456 } 1457 } 1458 1459 // If the buffer to be deleted is not the current one, delete it here. 1460 if (buf != curbuf) { 1461 if (jop_flags & kOptJopFlagClean) { 1462 // Remove the buffer to be deleted from the jump list. 1463 mark_jumplist_forget_file(curwin, buf_fnum); 1464 } 1465 1466 close_windows(buf, false); 1467 1468 if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) { 1469 close_buffer(NULL, buf, action, false, false); 1470 } 1471 return OK; 1472 } 1473 1474 // Deleting the current buffer: Need to find another buffer to go to. 1475 // There should be another, otherwise it would have been handled 1476 // above. However, autocommands may have deleted all buffers. 1477 // First use au_new_curbuf.br_buf, if it is valid. 1478 // Then prefer the buffer we most recently visited. 1479 // Else try to find one that is loaded, after the current buffer, 1480 // then before the current buffer. 1481 // Finally use any buffer. Skip buffers that are closing throughout. 1482 buf = NULL; // Selected buffer. 1483 bp = NULL; // Used when no loaded buffer found. 1484 if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf) 1485 && !au_new_curbuf.br_buf->b_locked_split) { 1486 buf = au_new_curbuf.br_buf; 1487 } else if (curwin->w_jumplistlen > 0) { 1488 if (jop_flags & kOptJopFlagClean) { 1489 // Remove the buffer from the jump list. 1490 mark_jumplist_forget_file(curwin, buf_fnum); 1491 } 1492 1493 // It's possible that we removed all jump list entries, in that case we need to try another 1494 // approach 1495 if (curwin->w_jumplistlen > 0) { 1496 int jumpidx = curwin->w_jumplistidx; 1497 1498 if (jop_flags & kOptJopFlagClean) { 1499 // If the index is the same as the length, the current position was not yet added to the 1500 // jump list. So we can safely go back to the last entry and search from there. 1501 if (jumpidx == curwin->w_jumplistlen) { 1502 jumpidx = curwin->w_jumplistidx = curwin->w_jumplistlen - 1; 1503 } 1504 } else { 1505 jumpidx--; 1506 if (jumpidx < 0) { 1507 jumpidx = curwin->w_jumplistlen - 1; 1508 } 1509 } 1510 1511 forward = jumpidx; 1512 while ((jop_flags & kOptJopFlagClean) || jumpidx != curwin->w_jumplistidx) { 1513 buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); 1514 1515 if (buf != NULL) { 1516 // Skip current and unlisted bufs. Also skip a quickfix 1517 // or closing buffer, it might be deleted soon. 1518 if (buf == curbuf || !buf->b_p_bl || bt_quickfix(buf) 1519 || buf->b_locked_split) { 1520 buf = NULL; 1521 } else if (buf->b_ml.ml_mfp == NULL) { 1522 // skip unloaded buf, but may keep it for later 1523 if (bp == NULL) { 1524 bp = buf; 1525 } 1526 buf = NULL; 1527 } 1528 } 1529 if (buf != NULL) { // found a valid buffer: stop searching 1530 if (jop_flags & kOptJopFlagClean) { 1531 curwin->w_jumplistidx = jumpidx; 1532 update_jumplist = false; 1533 } 1534 break; 1535 } 1536 // advance to older entry in jump list 1537 if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) { 1538 break; 1539 } 1540 if (--jumpidx < 0) { 1541 jumpidx = curwin->w_jumplistlen - 1; 1542 } 1543 if (jumpidx == forward) { // List exhausted for sure 1544 break; 1545 } 1546 } 1547 } 1548 } 1549 1550 if (buf == NULL) { // No previous buffer, Try 2'nd approach 1551 forward = true; 1552 buf = curbuf->b_next; 1553 while (true) { 1554 if (buf == NULL) { 1555 if (!forward) { // tried both directions 1556 break; 1557 } 1558 buf = curbuf->b_prev; 1559 forward = false; 1560 continue; 1561 } 1562 // in non-help buffer, try to skip help buffers, and vv 1563 if (buf->b_help == curbuf->b_help && buf->b_p_bl 1564 && !bt_quickfix(buf) && !buf->b_locked_split) { 1565 if (buf->b_ml.ml_mfp != NULL) { // found loaded buffer 1566 break; 1567 } 1568 if (bp == NULL) { // remember unloaded buf for later 1569 bp = buf; 1570 } 1571 } 1572 buf = forward ? buf->b_next : buf->b_prev; 1573 } 1574 } 1575 if (buf == NULL) { // No loaded buffer, use unloaded one 1576 buf = bp; 1577 } 1578 if (buf == NULL) { // No loaded buffer, find listed one 1579 FOR_ALL_BUFFERS(buf2) { 1580 if (buf2->b_p_bl && buf2 != curbuf && !bt_quickfix(buf2) && !buf2->b_locked_split) { 1581 buf = buf2; 1582 break; 1583 } 1584 } 1585 } 1586 if (buf == NULL) { // Still no buffer, just take one 1587 buf = curbuf->b_next != NULL ? curbuf->b_next : curbuf->b_prev; 1588 if (bt_quickfix(buf) || (buf != curbuf && buf->b_locked_split)) { 1589 buf = NULL; 1590 } 1591 } 1592 } 1593 1594 if (buf == NULL) { 1595 // Autocommands must have wiped out all other buffers. Only option 1596 // now is to make the current buffer empty. 1597 return empty_curbuf(false, (flags & DOBUF_FORCEIT), action); 1598 } 1599 1600 // make "buf" the current buffer 1601 // If 'switchbuf' is set jump to the window containing "buf". 1602 if (action == DOBUF_SPLIT && swbuf_goto_win_with_buf(buf) != NULL) { 1603 return OK; 1604 } 1605 // Whether splitting or not, don't open a closing buffer in more windows. 1606 if (buf != curbuf && buf->b_locked_split) { 1607 emsg(_(e_cannot_switch_to_a_closing_buffer)); 1608 return FAIL; 1609 } 1610 if (action == DOBUF_SPLIT && win_split(0, 0) == FAIL) { // split window first 1611 return FAIL; 1612 } 1613 1614 // go to current buffer - nothing to do 1615 if (buf == curbuf) { 1616 return OK; 1617 } 1618 1619 // Check if the current buffer may be abandoned. 1620 if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT))) { 1621 if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) { 1622 bufref_T bufref; 1623 set_bufref(&bufref, buf); 1624 dialog_changed(curbuf, false); 1625 if (!bufref_valid(&bufref)) { 1626 // Autocommand deleted buffer, oops! 1627 return FAIL; 1628 } 1629 } 1630 if (bufIsChanged(curbuf)) { 1631 no_write_message(); 1632 return FAIL; 1633 } 1634 } 1635 1636 // Go to the other buffer. 1637 set_curbuf(buf, action, update_jumplist); 1638 1639 if (action == DOBUF_SPLIT) { 1640 RESET_BINDING(curwin); // reset 'scrollbind' and 'cursorbind' 1641 } 1642 1643 if (aborting()) { // autocmds may abort script processing 1644 return FAIL; 1645 } 1646 1647 return OK; 1648 } 1649 1650 int do_buffer(int action, int start, int dir, int count, int forceit) 1651 { 1652 return do_buffer_ext(action, start, dir, count, forceit ? DOBUF_FORCEIT : 0); 1653 } 1654 1655 /// Set current buffer to "buf". Executes autocommands and closes current 1656 /// buffer. 1657 /// 1658 /// @param action tells how to close the current buffer: 1659 /// DOBUF_GOTO free or hide it 1660 /// DOBUF_SPLIT nothing 1661 /// DOBUF_UNLOAD unload it 1662 /// DOBUF_DEL delete it 1663 /// DOBUF_WIPE wipe it out 1664 void set_curbuf(buf_T *buf, int action, bool update_jumplist) 1665 { 1666 buf_T *prevbuf; 1667 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL 1668 || action == DOBUF_WIPE); 1669 OptInt old_tw = curbuf->b_p_tw; 1670 const int last_winid = get_last_winid(); 1671 1672 if (update_jumplist) { 1673 setpcmark(); 1674 } 1675 1676 if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 1677 curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file 1678 } 1679 buflist_altfpos(curwin); // remember curpos 1680 1681 // Don't restart Select mode after switching to another buffer. 1682 VIsual_reselect = false; 1683 1684 // close_windows() or apply_autocmds() may change curbuf and wipe out "buf" 1685 prevbuf = curbuf; 1686 bufref_T newbufref; 1687 bufref_T prevbufref; 1688 set_bufref(&prevbufref, prevbuf); 1689 set_bufref(&newbufref, buf); 1690 const int prev_nwindows = prevbuf->b_nwindows; 1691 1692 // Autocommands may delete the current buffer and/or the buffer we want to 1693 // go to. In those cases don't close the buffer. 1694 if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf) 1695 || (bufref_valid(&prevbufref) && bufref_valid(&newbufref) 1696 && !aborting())) { 1697 if (prevbuf == curwin->w_buffer) { 1698 reset_synblock(curwin); 1699 } 1700 // autocommands may have opened a new window 1701 // with prevbuf, grr 1702 if (unload 1703 || (prev_nwindows <= 1 && last_winid != get_last_winid() 1704 && action == DOBUF_GOTO && !buf_hide(prevbuf))) { 1705 close_windows(prevbuf, false); 1706 } 1707 if (bufref_valid(&prevbufref) && !aborting()) { 1708 win_T *previouswin = curwin; 1709 1710 // Do not sync when in Insert mode and the buffer is open in 1711 // another window, might be a timer doing something in another 1712 // window. 1713 if (prevbuf == curbuf && ((State & MODE_INSERT) == 0 || curbuf->b_nwindows <= 1)) { 1714 u_sync(false); 1715 } 1716 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, 1717 prevbuf, 1718 unload 1719 ? action 1720 : (action == DOBUF_GOTO && !buf_hide(prevbuf) 1721 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, 1722 false, false); 1723 if (curwin != previouswin && win_valid(previouswin)) { 1724 // autocommands changed curwin, Grr! 1725 curwin = previouswin; 1726 } 1727 } 1728 } 1729 // An autocommand may have deleted "buf", already entered it (e.g., when 1730 // it did ":bunload") or aborted the script processing! 1731 // If curwin->w_buffer is null, enter_buffer() will make it valid again 1732 bool valid = buf_valid(buf); 1733 if ((valid && buf != curbuf && !aborting()) || curwin->w_buffer == NULL) { 1734 // autocommands changed curbuf and we will move to another 1735 // buffer soon, so decrement curbuf->b_nwindows 1736 if (curbuf != NULL && prevbuf != curbuf) { 1737 curbuf->b_nwindows--; 1738 } 1739 // If the buffer is not valid but curwin->w_buffer is NULL we must 1740 // enter some buffer. Using the last one is hopefully OK. 1741 enter_buffer(valid ? buf : lastbuf); 1742 if (old_tw != curbuf->b_p_tw) { 1743 check_colorcolumn(NULL, curwin); 1744 } 1745 } 1746 1747 if (bufref_valid(&prevbufref) && prevbuf->terminal != NULL) { 1748 terminal_check_size(prevbuf->terminal); 1749 } 1750 } 1751 1752 /// Enter a new current buffer. 1753 /// Old curbuf must have been abandoned already! This also means "curbuf" may 1754 /// be pointing to freed memory. 1755 static void enter_buffer(buf_T *buf) 1756 { 1757 // when closing the current buffer stop Visual mode 1758 if (VIsual_active 1759 #if defined(EXITFREE) 1760 && !entered_free_all_mem 1761 #endif 1762 ) { 1763 end_visual_mode(); 1764 } 1765 1766 // Get the buffer in the current window. 1767 curwin->w_buffer = buf; 1768 curbuf = buf; 1769 curbuf->b_nwindows++; 1770 1771 // Copy buffer and window local option values. Not for a help buffer. 1772 buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); 1773 if (!buf->b_help) { 1774 get_winopts(buf); 1775 } else { 1776 // Remove all folds in the window. 1777 clearFolding(curwin); 1778 } 1779 foldUpdateAll(curwin); // update folds (later). 1780 1781 if (curwin->w_p_diff) { 1782 diff_buf_add(curbuf); 1783 } 1784 1785 curwin->w_s = &(curbuf->b_s); 1786 1787 // Cursor on first line by default. 1788 curwin->w_cursor.lnum = 1; 1789 curwin->w_cursor.col = 0; 1790 curwin->w_cursor.coladd = 0; 1791 curwin->w_set_curswant = true; 1792 curwin->w_topline_was_set = false; 1793 1794 // mark cursor position as being invalid 1795 curwin->w_valid = 0; 1796 1797 // Make sure the buffer is loaded. 1798 if (curbuf->b_ml.ml_mfp == NULL) { // need to load the file 1799 // If there is no filetype, allow for detecting one. Esp. useful for 1800 // ":ball" used in an autocommand. If there already is a filetype we 1801 // might prefer to keep it. 1802 if (*curbuf->b_p_ft == NUL) { 1803 curbuf->b_did_filetype = false; 1804 } 1805 1806 open_buffer(false, NULL, 0); 1807 } else { 1808 if (!msg_silent && !shortmess(SHM_FILEINFO)) { 1809 need_fileinfo = true; // display file info after redraw 1810 } 1811 // check if file changed 1812 buf_check_timestamp(curbuf); 1813 1814 curwin->w_topline = 1; 1815 curwin->w_topfill = 0; 1816 apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf); 1817 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, false, curbuf); 1818 } 1819 1820 // If autocommands did not change the cursor position, restore cursor lnum 1821 // and possibly cursor col. 1822 if (curwin->w_cursor.lnum == 1 && inindent(0)) { 1823 buflist_getfpos(); 1824 } 1825 1826 check_arg_idx(curwin); // check for valid arg_idx 1827 maketitle(); 1828 // when autocmds didn't change it 1829 if (curwin->w_topline == 1 && !curwin->w_topline_was_set) { 1830 scroll_cursor_halfway(curwin, false, false); // redisplay at correct position 1831 } 1832 1833 // Change directories when the 'acd' option is set. 1834 do_autochdir(); 1835 1836 if (curbuf->b_kmap_state & KEYMAP_INIT) { 1837 keymap_init(); 1838 } 1839 // May need to set the spell language. Can only do this after the buffer 1840 // has been properly setup. 1841 if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) { 1842 parse_spelllang(curwin); 1843 } 1844 curbuf->b_last_used = time(NULL); 1845 1846 if (curbuf->terminal != NULL) { 1847 terminal_check_size(curbuf->terminal); 1848 } 1849 1850 redraw_later(curwin, UPD_NOT_VALID); 1851 } 1852 1853 /// Change to the directory of the current buffer. 1854 /// Don't do this while still starting up. 1855 void do_autochdir(void) 1856 { 1857 if (p_acd) { 1858 if (starting == 0 1859 && curbuf->b_ffname != NULL 1860 && vim_chdirfile(curbuf->b_ffname, kCdCauseAuto) == OK) { 1861 last_chdir_reason = "autochdir"; 1862 shorten_fnames(true); 1863 } 1864 } 1865 } 1866 1867 void no_write_message_buf(buf_T *buf) 1868 { 1869 if (buf->terminal 1870 && channel_job_running((uint64_t)buf->b_p_channel)) { 1871 emsg(_(e_job_still_running_add_bang_to_end_the_job)); 1872 } else { 1873 semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), 1874 buf->b_fnum); 1875 } 1876 } 1877 1878 void no_write_message(void) 1879 { 1880 if (curbuf->terminal 1881 && channel_job_running((uint64_t)curbuf->b_p_channel)) { 1882 emsg(_(e_job_still_running_add_bang_to_end_the_job)); 1883 } else { 1884 emsg(_(e_no_write_since_last_change_add_bang_to_override)); 1885 } 1886 } 1887 1888 void no_write_message_nobang(const buf_T *const buf) 1889 FUNC_ATTR_NONNULL_ALL 1890 { 1891 if (buf->terminal 1892 && channel_job_running((uint64_t)buf->b_p_channel)) { 1893 emsg(_(e_job_still_running)); 1894 } else { 1895 emsg(_(e_no_write_since_last_change)); 1896 } 1897 } 1898 1899 // 1900 // functions for dealing with the buffer list 1901 // 1902 1903 /// Initialize b:changedtick and changedtick_val attribute 1904 /// 1905 /// @param[out] buf Buffer to initialize for. 1906 static inline void buf_init_changedtick(buf_T *const buf) 1907 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 1908 { 1909 STATIC_ASSERT(sizeof("changedtick") <= sizeof(buf->changedtick_di.di_key), 1910 "buf->changedtick_di cannot hold large enough keys"); 1911 buf->changedtick_di = (ChangedtickDictItem) { 1912 .di_flags = DI_FLAGS_RO|DI_FLAGS_FIX, // Must not include DI_FLAGS_ALLOC. 1913 .di_tv = (typval_T) { 1914 .v_type = VAR_NUMBER, 1915 .v_lock = VAR_FIXED, 1916 .vval.v_number = buf_get_changedtick(buf), 1917 }, 1918 .di_key = "changedtick", 1919 }; 1920 tv_dict_add(buf->b_vars, (dictitem_T *)&buf->changedtick_di); 1921 } 1922 1923 /// Add a file name to the buffer list. 1924 /// If the same file name already exists return a pointer to that buffer. 1925 /// If it does not exist, or if fname == NULL, a new entry is created. 1926 /// If (flags & BLN_CURBUF) is true, may use current buffer. 1927 /// If (flags & BLN_LISTED) is true, add new buffer to buffer list. 1928 /// If (flags & BLN_DUMMY) is true, don't count it as a real buffer. 1929 /// If (flags & BLN_NEW) is true, don't use an existing buffer. 1930 /// If (flags & BLN_NOOPT) is true, don't copy options from the current buffer 1931 /// if the buffer already exists. 1932 /// This is the ONLY way to create a new buffer. 1933 /// 1934 /// @param ffname_arg full path of fname or relative 1935 /// @param sfname_arg short fname or NULL 1936 /// @param lnum preferred cursor line 1937 /// @param flags BLN_ defines 1938 /// @param bufnr 1939 /// 1940 /// @return pointer to the buffer 1941 buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags) 1942 { 1943 char *ffname = ffname_arg; 1944 char *sfname = sfname_arg; 1945 buf_T *buf; 1946 1947 fname_expand(curbuf, &ffname, &sfname); // will allocate ffname 1948 1949 // If the file name already exists in the list, update the entry. 1950 1951 // We can use inode numbers when the file exists. Works better 1952 // for hard links. 1953 FileID file_id; 1954 bool file_id_valid = (sfname != NULL && os_fileid(sfname, &file_id)); 1955 if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) 1956 && (buf = buflist_findname_file_id(ffname, &file_id, file_id_valid)) != NULL) { 1957 xfree(ffname); 1958 if (lnum != 0) { 1959 buflist_setfpos(buf, (flags & BLN_NOCURWIN) ? NULL : curwin, 1960 lnum, 0, false); 1961 } 1962 if ((flags & BLN_NOOPT) == 0) { 1963 // Copy the options now, if 'cpo' doesn't have 's' and not done already. 1964 buf_copy_options(buf, 0); 1965 } 1966 if ((flags & BLN_LISTED) && !buf->b_p_bl) { 1967 buf->b_p_bl = true; 1968 bufref_T bufref; 1969 set_bufref(&bufref, buf); 1970 if (!(flags & BLN_DUMMY)) { 1971 if (apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) 1972 && !bufref_valid(&bufref)) { 1973 return NULL; 1974 } 1975 } 1976 } 1977 return buf; 1978 } 1979 1980 // If the current buffer has no name and no contents, use the current 1981 // buffer. Otherwise: Need to allocate a new buffer structure. 1982 // 1983 // This is the ONLY place where a new buffer structure is allocated! 1984 // (A spell file buffer is allocated in spell.c, but that's not a normal 1985 // buffer.) 1986 buf = NULL; 1987 if ((flags & BLN_CURBUF) && curbuf_reusable()) { 1988 bufref_T bufref; 1989 1990 assert(curbuf != NULL); 1991 buf = curbuf; 1992 set_bufref(&bufref, buf); 1993 trigger_undo_ftplugin(buf, curwin); 1994 // It's like this buffer is deleted. Watch out for autocommands that 1995 // change curbuf! If that happens, allocate a new buffer anyway. 1996 buf_freeall(buf, BFA_WIPE | BFA_DEL); 1997 if (aborting()) { // autocmds may abort script processing 1998 xfree(ffname); 1999 return NULL; 2000 } 2001 if (!bufref_valid(&bufref)) { 2002 buf = NULL; // buf was deleted; allocate a new buffer 2003 } 2004 } 2005 if (buf != curbuf || curbuf == NULL) { 2006 buf = xcalloc(1, sizeof(buf_T)); 2007 // init b: variables 2008 buf->b_vars = tv_dict_alloc(); 2009 init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); 2010 buf_init_changedtick(buf); 2011 } 2012 2013 if (ffname != NULL) { 2014 buf->b_ffname = ffname; 2015 buf->b_sfname = xstrdup(sfname); 2016 } 2017 2018 clear_wininfo(buf); 2019 WinInfo *curwin_info = xcalloc(1, sizeof(WinInfo)); 2020 kv_push(buf->b_wininfo, curwin_info); 2021 2022 if (buf == curbuf) { 2023 free_buffer_stuff(buf, kBffInitChangedtick); // delete local vars et al. 2024 2025 // Init the options. 2026 buf->b_p_initialized = false; 2027 buf_copy_options(buf, BCO_ENTER); 2028 2029 // need to reload lmaps and set b:keymap_name 2030 curbuf->b_kmap_state |= KEYMAP_INIT; 2031 } else { 2032 // put new buffer at the end of the buffer list 2033 buf->b_next = NULL; 2034 if (firstbuf == NULL) { // buffer list is empty 2035 buf->b_prev = NULL; 2036 firstbuf = buf; 2037 } else { // append new buffer at end of list 2038 lastbuf->b_next = buf; 2039 buf->b_prev = lastbuf; 2040 } 2041 lastbuf = buf; 2042 2043 buf->b_fnum = top_file_num++; 2044 pmap_put(int)(&buffer_handles, buf->b_fnum, buf); 2045 if (top_file_num < 0) { // wrap around (may cause duplicates) 2046 emsg(_("W14: Warning: List of file names overflow")); 2047 if (emsg_silent == 0 && !in_assert_fails) { 2048 msg_delay(3001, true); // make sure it is noticed 2049 } 2050 top_file_num = 1; 2051 } 2052 2053 // Always copy the options from the current buffer. 2054 buf_copy_options(buf, BCO_ALWAYS); 2055 } 2056 2057 curwin_info->wi_mark = (fmark_T)INIT_FMARK; 2058 curwin_info->wi_mark.mark.lnum = lnum; 2059 curwin_info->wi_win = curwin; 2060 2061 hash_init(&buf->b_s.b_keywtab); 2062 hash_init(&buf->b_s.b_keywtab_ic); 2063 2064 buf->b_fname = buf->b_sfname; 2065 if (!file_id_valid) { 2066 buf->file_id_valid = false; 2067 } else { 2068 buf->file_id_valid = true; 2069 buf->file_id = file_id; 2070 } 2071 buf->b_u_synced = true; 2072 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; 2073 if (flags & BLN_DUMMY) { 2074 buf->b_flags |= BF_DUMMY; 2075 } 2076 buf_clear_file(buf); 2077 clrallmarks(buf, 0); // clear marks 2078 fmarks_check_names(buf); // check file marks for this file 2079 buf->b_p_bl = (flags & BLN_LISTED) ? true : false; // init 'buflisted' 2080 kv_destroy(buf->update_channels); 2081 kv_init(buf->update_channels); 2082 kv_destroy(buf->update_callbacks); 2083 kv_init(buf->update_callbacks); 2084 if (!(flags & BLN_DUMMY)) { 2085 // Tricky: these autocommands may change the buffer list. They could also 2086 // split the window with re-using the one empty buffer. This may result in 2087 // unexpectedly losing the empty buffer. 2088 bufref_T bufref; 2089 set_bufref(&bufref, buf); 2090 if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf) 2091 && !bufref_valid(&bufref)) { 2092 return NULL; 2093 } 2094 if ((flags & BLN_LISTED) 2095 && apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) 2096 && !bufref_valid(&bufref)) { 2097 return NULL; 2098 } 2099 if (aborting()) { 2100 // Autocmds may abort script processing. 2101 return NULL; 2102 } 2103 } 2104 2105 buf->b_prompt_callback.type = kCallbackNone; 2106 buf->b_prompt_interrupt.type = kCallbackNone; 2107 buf->b_prompt_text = NULL; 2108 buf->b_prompt_start = (fmark_T)INIT_FMARK; 2109 buf->b_prompt_start.mark.col = 2; // default prompt is "% " 2110 2111 return buf; 2112 } 2113 2114 /// Return true if the current buffer is empty, unnamed, unmodified and used in 2115 /// only one window. That means it can be reused. 2116 bool curbuf_reusable(void) 2117 { 2118 return (curbuf != NULL 2119 && curbuf->b_ffname == NULL 2120 && curbuf->b_nwindows <= 1 2121 && !curbuf->terminal 2122 && (curbuf->b_ml.ml_mfp == NULL || buf_is_empty(curbuf)) 2123 && !bt_quickfix(curbuf) 2124 && !curbufIsChanged()); 2125 } 2126 2127 /// Free the memory for the options of a buffer. 2128 /// If "free_p_ff" is true also free 'fileformat', 'buftype' and 2129 /// 'fileencoding'. 2130 void free_buf_options(buf_T *buf, bool free_p_ff) 2131 { 2132 if (free_p_ff) { 2133 clear_string_option(&buf->b_p_fenc); 2134 clear_string_option(&buf->b_p_ff); 2135 clear_string_option(&buf->b_p_bh); 2136 clear_string_option(&buf->b_p_bt); 2137 } 2138 clear_string_option(&buf->b_p_def); 2139 clear_string_option(&buf->b_p_inc); 2140 clear_string_option(&buf->b_p_inex); 2141 clear_string_option(&buf->b_p_inde); 2142 clear_string_option(&buf->b_p_indk); 2143 clear_string_option(&buf->b_p_fp); 2144 clear_string_option(&buf->b_p_fex); 2145 clear_string_option(&buf->b_p_kp); 2146 clear_string_option(&buf->b_p_mps); 2147 clear_string_option(&buf->b_p_fo); 2148 clear_string_option(&buf->b_p_flp); 2149 clear_string_option(&buf->b_p_isk); 2150 clear_string_option(&buf->b_p_vsts); 2151 XFREE_CLEAR(buf->b_p_vsts_nopaste); 2152 XFREE_CLEAR(buf->b_p_vsts_array); 2153 clear_string_option(&buf->b_p_vts); 2154 XFREE_CLEAR(buf->b_p_vts_array); 2155 clear_string_option(&buf->b_p_keymap); 2156 keymap_ga_clear(&buf->b_kmap_ga); 2157 ga_clear(&buf->b_kmap_ga); 2158 clear_string_option(&buf->b_p_com); 2159 clear_string_option(&buf->b_p_cms); 2160 clear_string_option(&buf->b_p_nf); 2161 clear_string_option(&buf->b_p_syn); 2162 clear_string_option(&buf->b_s.b_syn_isk); 2163 clear_string_option(&buf->b_s.b_p_spc); 2164 clear_string_option(&buf->b_s.b_p_spf); 2165 vim_regfree(buf->b_s.b_cap_prog); 2166 buf->b_s.b_cap_prog = NULL; 2167 clear_string_option(&buf->b_s.b_p_spl); 2168 clear_string_option(&buf->b_s.b_p_spo); 2169 clear_string_option(&buf->b_p_sua); 2170 clear_string_option(&buf->b_p_ft); 2171 clear_string_option(&buf->b_p_cink); 2172 clear_string_option(&buf->b_p_cino); 2173 clear_string_option(&buf->b_p_lop); 2174 clear_string_option(&buf->b_p_cinsd); 2175 clear_string_option(&buf->b_p_cinw); 2176 clear_string_option(&buf->b_p_cot); 2177 clear_string_option(&buf->b_p_cpt); 2178 clear_string_option(&buf->b_p_cfu); 2179 callback_free(&buf->b_cfu_cb); 2180 clear_string_option(&buf->b_p_ofu); 2181 callback_free(&buf->b_ofu_cb); 2182 clear_string_option(&buf->b_p_tsrfu); 2183 callback_free(&buf->b_tsrfu_cb); 2184 clear_cpt_callbacks(&buf->b_p_cpt_cb, buf->b_p_cpt_count); 2185 buf->b_p_cpt_count = 0; 2186 clear_string_option(&buf->b_p_gefm); 2187 clear_string_option(&buf->b_p_gp); 2188 clear_string_option(&buf->b_p_mp); 2189 clear_string_option(&buf->b_p_efm); 2190 clear_string_option(&buf->b_p_ep); 2191 clear_string_option(&buf->b_p_path); 2192 clear_string_option(&buf->b_p_tags); 2193 clear_string_option(&buf->b_p_tc); 2194 clear_string_option(&buf->b_p_tfu); 2195 callback_free(&buf->b_tfu_cb); 2196 clear_string_option(&buf->b_p_ffu); 2197 callback_free(&buf->b_ffu_cb); 2198 clear_string_option(&buf->b_p_dict); 2199 clear_string_option(&buf->b_p_dia); 2200 clear_string_option(&buf->b_p_tsr); 2201 clear_string_option(&buf->b_p_qe); 2202 buf->b_p_ac = -1; 2203 buf->b_p_ar = -1; 2204 buf->b_p_fs = -1; 2205 buf->b_p_ul = NO_LOCAL_UNDOLEVEL; 2206 clear_string_option(&buf->b_p_lw); 2207 clear_string_option(&buf->b_p_bkc); 2208 clear_string_option(&buf->b_p_menc); 2209 } 2210 2211 /// Get alternate file "n". 2212 /// Set linenr to "lnum" or altfpos.lnum if "lnum" == 0. 2213 /// Also set cursor column to altfpos.col if 'startofline' is not set. 2214 /// if (options & GETF_SETMARK) call setpcmark() 2215 /// if (options & GETF_ALT) we are jumping to an alternate file. 2216 /// if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping 2217 /// 2218 /// Return FAIL for failure, OK for success. 2219 int buflist_getfile(int n, linenr_T lnum, int options, int forceit) 2220 { 2221 win_T *wp = NULL; 2222 fmark_T *fm = NULL; 2223 2224 buf_T *buf = buflist_findnr(n); 2225 if (buf == NULL) { 2226 if ((options & GETF_ALT) && n == 0) { 2227 emsg(_(e_noalt)); 2228 } else { 2229 semsg(_(e_buffer_nr_not_found), n); 2230 } 2231 return FAIL; 2232 } 2233 2234 // if alternate file is the current buffer, nothing to do 2235 if (buf == curbuf) { 2236 return OK; 2237 } 2238 2239 if (text_or_buf_locked()) { 2240 return FAIL; 2241 } 2242 2243 colnr_T col; 2244 bool restore_view = false; 2245 // altfpos may be changed by getfile(), get it now 2246 if (lnum == 0) { 2247 fm = buflist_findfmark(buf); 2248 lnum = fm->mark.lnum; 2249 col = fm->mark.col; 2250 restore_view = true; 2251 } else { 2252 col = 0; 2253 } 2254 2255 if (options & GETF_SWITCH) { 2256 // If 'switchbuf' is set jump to the window containing "buf". 2257 wp = swbuf_goto_win_with_buf(buf); 2258 2259 // If 'switchbuf' contains "split", "vsplit" or "newtab" and the 2260 // current buffer isn't empty: open new tab or window 2261 if (wp == NULL && (swb_flags & (kOptSwbFlagVsplit | kOptSwbFlagSplit | kOptSwbFlagNewtab)) 2262 && !buf_is_empty(curbuf)) { 2263 if (swb_flags & kOptSwbFlagNewtab) { 2264 tabpage_new(); 2265 } else if (win_split(0, (swb_flags & kOptSwbFlagVsplit) ? WSP_VERT : 0) 2266 == FAIL) { 2267 return FAIL; 2268 } 2269 RESET_BINDING(curwin); 2270 } 2271 } 2272 2273 RedrawingDisabled++; 2274 if (GETFILE_SUCCESS(getfile(buf->b_fnum, NULL, NULL, 2275 (options & GETF_SETMARK), lnum, forceit))) { 2276 RedrawingDisabled--; 2277 2278 // cursor is at to BOL and w_cursor.lnum is checked due to getfile() 2279 if (!p_sol && col != 0) { 2280 curwin->w_cursor.col = col; 2281 check_cursor_col(curwin); 2282 curwin->w_cursor.coladd = 0; 2283 curwin->w_set_curswant = true; 2284 } 2285 if (jop_flags & kOptJopFlagView && restore_view) { 2286 mark_view_restore(fm); 2287 } 2288 return OK; 2289 } 2290 RedrawingDisabled--; 2291 return FAIL; 2292 } 2293 2294 /// Go to the last known line number for the current buffer. 2295 static void buflist_getfpos(void) 2296 { 2297 fmark_T *fm = buflist_findfmark(curbuf); 2298 const pos_T *fpos = &fm->mark; 2299 2300 curwin->w_cursor.lnum = fpos->lnum; 2301 check_cursor_lnum(curwin); 2302 2303 if (p_sol) { 2304 curwin->w_cursor.col = 0; 2305 } else { 2306 curwin->w_cursor.col = fpos->col; 2307 check_cursor_col(curwin); 2308 curwin->w_cursor.coladd = 0; 2309 curwin->w_set_curswant = true; 2310 } 2311 2312 if (jop_flags & kOptJopFlagView) { 2313 mark_view_restore(fm); 2314 } 2315 } 2316 2317 /// Find file in buffer list by name (it has to be for the current window). 2318 /// 2319 /// @return buffer or NULL if not found 2320 buf_T *buflist_findname_exp(char *fname) 2321 { 2322 buf_T *buf = NULL; 2323 2324 // First make the name into a full path name 2325 char *ffname = FullName_save(fname, 2326 #ifdef UNIX 2327 // force expansion, get rid of symbolic links 2328 true 2329 #else 2330 false 2331 #endif 2332 ); 2333 if (ffname != NULL) { 2334 buf = buflist_findname(ffname); 2335 xfree(ffname); 2336 } 2337 return buf; 2338 } 2339 2340 /// Find file in buffer list by name (it has to be for the current window). 2341 /// "ffname" must have a full path. 2342 /// Skips dummy buffers. 2343 /// 2344 /// @return buffer or NULL if not found 2345 buf_T *buflist_findname(char *ffname) 2346 { 2347 FileID file_id; 2348 bool file_id_valid = os_fileid(ffname, &file_id); 2349 return buflist_findname_file_id(ffname, &file_id, file_id_valid); 2350 } 2351 2352 /// Same as buflist_findname(), but pass the FileID structure to avoid 2353 /// getting it twice for the same file. 2354 /// 2355 /// @return buffer or NULL if not found 2356 static buf_T *buflist_findname_file_id(char *ffname, FileID *file_id, bool file_id_valid) 2357 FUNC_ATTR_PURE 2358 { 2359 // Start at the last buffer, expect to find a match sooner. 2360 FOR_ALL_BUFFERS_BACKWARDS(buf) { 2361 if ((buf->b_flags & BF_DUMMY) == 0 2362 && !otherfile_buf(buf, ffname, file_id, file_id_valid)) { 2363 return buf; 2364 } 2365 } 2366 return NULL; 2367 } 2368 2369 /// Find file in buffer list by a regexp pattern. 2370 /// 2371 /// @param pattern_end pointer to first char after pattern 2372 /// @param unlisted find unlisted buffers 2373 /// @param diffmode find diff-mode buffers only 2374 /// @param curtab_only find buffers in current tab only 2375 /// 2376 /// @return fnum of the found buffer or < 0 for error. 2377 int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted, bool diffmode, 2378 bool curtab_only) 2379 FUNC_ATTR_NONNULL_ARG(1) 2380 { 2381 int match = -1; 2382 2383 if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) { 2384 match = *pattern == '%' ? curbuf->b_fnum : curwin->w_alt_fnum; 2385 buf_T *found_buf = buflist_findnr(match); 2386 if (diffmode && !(found_buf && diff_mode_buf(found_buf))) { 2387 match = -1; 2388 } 2389 } else { 2390 // Try four ways of matching a listed buffer: 2391 // attempt == 0: without '^' or '$' (at any position) 2392 // attempt == 1: with '^' at start (only at position 0) 2393 // attempt == 2: with '$' at end (only match at end) 2394 // attempt == 3: with '^' at start and '$' at end (only full match) 2395 // Repeat this for finding an unlisted buffer if there was no matching 2396 // listed buffer. 2397 2398 char *pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, false); 2399 if (pat == NULL) { 2400 return -1; 2401 } 2402 char *patend = pat + strlen(pat) - 1; 2403 bool toggledollar = (patend > pat && *patend == '$'); 2404 2405 // First try finding a listed buffer. If not found and "unlisted" 2406 // is true, try finding an unlisted buffer. 2407 2408 int find_listed = true; 2409 while (true) { 2410 for (int attempt = 0; attempt <= 3; attempt++) { 2411 // may add '^' and '$' 2412 if (toggledollar) { 2413 *patend = (attempt < 2) ? NUL : '$'; // add/remove '$' 2414 } 2415 char *p = pat; 2416 if (*p == '^' && !(attempt & 1)) { // add/remove '^' 2417 p++; 2418 } 2419 2420 regmatch_T regmatch; 2421 regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0); 2422 2423 FOR_ALL_BUFFERS_BACKWARDS(buf) { 2424 if (regmatch.regprog == NULL) { 2425 // invalid pattern, possibly after switching engine 2426 xfree(pat); 2427 return -1; 2428 } 2429 if (buf->b_p_bl == find_listed 2430 && (!diffmode || diff_mode_buf(buf)) 2431 && buflist_match(®match, buf, false) != NULL) { 2432 if (curtab_only) { 2433 // Ignore the match if the buffer is not open in 2434 // the current tab. 2435 bool found_window = false; 2436 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 2437 if (wp->w_buffer == buf) { 2438 found_window = true; 2439 break; 2440 } 2441 } 2442 if (!found_window) { 2443 continue; 2444 } 2445 } 2446 if (match >= 0) { // already found a match 2447 match = -2; 2448 break; 2449 } 2450 match = buf->b_fnum; // remember first match 2451 } 2452 } 2453 2454 vim_regfree(regmatch.regprog); 2455 if (match >= 0) { // found one match 2456 break; 2457 } 2458 } 2459 2460 // Only search for unlisted buffers if there was no match with 2461 // a listed buffer. 2462 if (!unlisted || !find_listed || match != -1) { 2463 break; 2464 } 2465 find_listed = false; 2466 } 2467 2468 xfree(pat); 2469 } 2470 2471 if (match == -2) { 2472 semsg(_("E93: More than one match for %s"), pattern); 2473 } else if (match < 0) { 2474 semsg(_("E94: No matching buffer for %s"), pattern); 2475 } 2476 return match; 2477 } 2478 2479 typedef struct { 2480 buf_T *buf; 2481 char *match; 2482 } bufmatch_T; 2483 2484 /// Compare functions for qsort() below, that compares b_last_used. 2485 static int buf_time_compare(const void *s1, const void *s2) 2486 { 2487 buf_T *buf1 = *(buf_T **)s1; 2488 buf_T *buf2 = *(buf_T **)s2; 2489 2490 if (buf1->b_last_used == buf2->b_last_used) { 2491 return 0; 2492 } 2493 return buf1->b_last_used > buf2->b_last_used ? -1 : 1; 2494 } 2495 2496 /// Find all buffer names that match. 2497 /// For command line expansion of ":buf" and ":sbuf". 2498 /// 2499 /// @return OK if matches found, FAIL otherwise. 2500 int ExpandBufnames(char *pat, int *num_file, char ***file, int options) 2501 { 2502 bufmatch_T *matches = NULL; 2503 bool to_free = false; 2504 2505 *num_file = 0; // return values in case of FAIL 2506 *file = NULL; 2507 2508 if ((options & BUF_DIFF_FILTER) && !curwin->w_p_diff) { 2509 return FAIL; 2510 } 2511 2512 const bool fuzzy = cmdline_fuzzy_complete(pat); 2513 2514 char *patc = NULL; 2515 fuzmatch_str_T *fuzmatch = NULL; 2516 regmatch_T regmatch; 2517 2518 // Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular 2519 // expression matching) 2520 if (!fuzzy) { 2521 if (*pat == '^' && pat[1] != NUL) { 2522 patc = xstrdup(pat + 1); 2523 to_free = true; 2524 } else if (*pat == '^') { 2525 patc = ""; 2526 } else { 2527 patc = pat; 2528 } 2529 regmatch.regprog = vim_regcomp(patc, RE_MAGIC); 2530 } 2531 2532 int count = 0; 2533 int score = 0; 2534 // round == 1: Count the matches. 2535 // round == 2: Build the array to keep the matches. 2536 for (int round = 1; round <= 2; round++) { 2537 count = 0; 2538 FOR_ALL_BUFFERS(buf) { 2539 if (!buf->b_p_bl) { // skip unlisted buffers 2540 continue; 2541 } 2542 if (options & BUF_DIFF_FILTER) { 2543 // Skip buffers not suitable for 2544 // :diffget or :diffput completion. 2545 if (buf == curbuf || !diff_mode_buf(buf)) { 2546 continue; 2547 } 2548 } 2549 2550 char *p = NULL; 2551 if (!fuzzy) { 2552 if (regmatch.regprog == NULL) { 2553 // invalid pattern, possibly after recompiling 2554 if (to_free) { 2555 xfree(patc); 2556 } 2557 return FAIL; 2558 } 2559 p = buflist_match(®match, buf, p_wic); 2560 } else { 2561 p = NULL; 2562 // first try matching with the short file name 2563 if ((score = fuzzy_match_str(buf->b_sfname, pat)) != FUZZY_SCORE_NONE) { 2564 p = buf->b_sfname; 2565 } 2566 if (p == NULL) { 2567 // next try matching with the full path file name 2568 if ((score = fuzzy_match_str(buf->b_ffname, pat)) != FUZZY_SCORE_NONE) { 2569 p = buf->b_ffname; 2570 } 2571 } 2572 } 2573 2574 if (p == NULL) { 2575 continue; 2576 } 2577 2578 if (round == 1) { 2579 count++; 2580 continue; 2581 } 2582 2583 if (options & WILD_HOME_REPLACE) { 2584 p = home_replace_save(buf, p); 2585 } else { 2586 p = xstrdup(p); 2587 } 2588 2589 if (!fuzzy) { 2590 if (matches != NULL) { 2591 matches[count].buf = buf; 2592 matches[count].match = p; 2593 count++; 2594 } else { 2595 (*file)[count++] = p; 2596 } 2597 } else { 2598 fuzmatch[count].idx = count; 2599 fuzmatch[count].str = p; 2600 fuzmatch[count].score = score; 2601 count++; 2602 } 2603 } 2604 if (count == 0) { // no match found, break here 2605 break; 2606 } 2607 if (round == 1) { 2608 if (!fuzzy) { 2609 *file = xmalloc((size_t)count * sizeof(**file)); 2610 if (options & WILD_BUFLASTUSED) { 2611 matches = xmalloc((size_t)count * sizeof(*matches)); 2612 } 2613 } else { 2614 fuzmatch = xmalloc((size_t)count * sizeof(fuzmatch_str_T)); 2615 } 2616 } 2617 } 2618 2619 if (!fuzzy) { 2620 vim_regfree(regmatch.regprog); 2621 if (to_free) { 2622 xfree(patc); 2623 } 2624 } 2625 2626 if (!fuzzy) { 2627 if (matches != NULL) { 2628 if (count > 1) { 2629 qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare); 2630 } 2631 2632 // if the current buffer is first in the list, place it at the end 2633 if (matches[0].buf == curbuf) { 2634 for (int i = 1; i < count; i++) { 2635 (*file)[i - 1] = matches[i].match; 2636 } 2637 (*file)[count - 1] = matches[0].match; 2638 } else { 2639 for (int i = 0; i < count; i++) { 2640 (*file)[i] = matches[i].match; 2641 } 2642 } 2643 xfree(matches); 2644 } 2645 } else { 2646 fuzzymatches_to_strmatches(fuzmatch, file, count, false); 2647 } 2648 2649 *num_file = count; 2650 return count == 0 ? FAIL : OK; 2651 } 2652 2653 /// Check for a match on the file name for buffer "buf" with regprog "prog". 2654 /// Note that rmp->regprog may become NULL when switching regexp engine. 2655 /// 2656 /// @param ignore_case When true, ignore case. Use 'fic' otherwise. 2657 static char *buflist_match(regmatch_T *rmp, buf_T *buf, bool ignore_case) 2658 { 2659 // First try the short file name, then the long file name. 2660 char *match = fname_match(rmp, buf->b_sfname, ignore_case); 2661 if (match == NULL && rmp->regprog != NULL) { 2662 match = fname_match(rmp, buf->b_ffname, ignore_case); 2663 } 2664 return match; 2665 } 2666 2667 /// Try matching the regexp in "rmp->regprog" with file name "name". 2668 /// Note that rmp->regprog may become NULL when switching regexp engine. 2669 /// 2670 /// @param ignore_case When true, ignore case. Use 'fileignorecase' otherwise. 2671 /// 2672 /// @return "name" when there is a match, NULL when not. 2673 static char *fname_match(regmatch_T *rmp, char *name, bool ignore_case) 2674 { 2675 char *match = NULL; 2676 2677 // extra check for valid arguments 2678 if (name == NULL || rmp->regprog == NULL) { 2679 return NULL; 2680 } 2681 2682 // Ignore case when 'fileignorecase' or the argument is set. 2683 rmp->rm_ic = p_fic || ignore_case; 2684 if (vim_regexec(rmp, name, 0)) { 2685 match = name; 2686 } else if (rmp->regprog != NULL) { 2687 // Replace $(HOME) with '~' and try matching again. 2688 char *p = home_replace_save(NULL, name); 2689 if (vim_regexec(rmp, p, 0)) { 2690 match = name; 2691 } 2692 xfree(p); 2693 } 2694 2695 return match; 2696 } 2697 2698 /// Find a file in the buffer list by buffer number. 2699 buf_T *buflist_findnr(int nr) 2700 { 2701 if (nr == 0) { 2702 nr = curwin->w_alt_fnum; 2703 } 2704 2705 return handle_get_buffer((handle_T)nr); 2706 } 2707 2708 /// Get name of file 'n' in the buffer list. 2709 /// When the file has no name an empty string is returned. 2710 /// home_replace() is used to shorten the file name (used for marks). 2711 /// 2712 /// @param helptail for help buffers return tail only 2713 /// 2714 /// @return a pointer to allocated memory, of NULL when failed. 2715 char *buflist_nr2name(int n, int fullname, int helptail) 2716 { 2717 buf_T *buf = buflist_findnr(n); 2718 if (buf == NULL) { 2719 return NULL; 2720 } 2721 return home_replace_save(helptail ? buf : NULL, 2722 fullname ? buf->b_ffname : buf->b_fname); 2723 } 2724 2725 /// Set the line and column numbers for the given buffer and window 2726 /// 2727 /// @param[in,out] buf Buffer for which line and column are set. 2728 /// @param[in,out] win Window for which line and column are set. 2729 /// May be NULL when using :badd. 2730 /// @param[in] lnum Line number to be set. If it is zero then only 2731 /// options are touched. 2732 /// @param[in] col Column number to be set. 2733 /// @param[in] copy_options If true save the local window option values. 2734 void buflist_setfpos(buf_T *const buf, win_T *const win, linenr_T lnum, colnr_T col, 2735 bool copy_options) 2736 FUNC_ATTR_NONNULL_ARG(1) 2737 { 2738 WinInfo *wip; 2739 2740 size_t i; 2741 for (i = 0; i < kv_size(buf->b_wininfo); i++) { 2742 wip = kv_A(buf->b_wininfo, i); 2743 if (wip->wi_win == win) { 2744 break; 2745 } 2746 } 2747 2748 if (i == kv_size(buf->b_wininfo)) { 2749 // allocate a new entry 2750 wip = xcalloc(1, sizeof(WinInfo)); 2751 wip->wi_win = win; 2752 if (lnum == 0) { // set lnum even when it's 0 2753 lnum = 1; 2754 } 2755 } else { 2756 // remove the entry from the list 2757 kv_shift(buf->b_wininfo, i, 1); 2758 if (copy_options && wip->wi_optset) { 2759 clear_winopt(&wip->wi_opt); 2760 deleteFoldRecurse(buf, &wip->wi_folds); 2761 } 2762 } 2763 if (lnum != 0) { 2764 wip->wi_mark.mark.lnum = lnum; 2765 wip->wi_mark.mark.col = col; 2766 if (win != NULL) { 2767 wip->wi_mark.view = mark_view_make(win->w_topline, wip->wi_mark.mark); 2768 } 2769 } 2770 if (win != NULL) { 2771 wip->wi_changelistidx = win->w_changelistidx; 2772 } 2773 if (copy_options && win != NULL) { 2774 // Save the window-specific option values. 2775 copy_winopt(&win->w_onebuf_opt, &wip->wi_opt); 2776 wip->wi_fold_manual = win->w_fold_manual; 2777 cloneFoldGrowArray(&win->w_folds, &wip->wi_folds); 2778 wip->wi_optset = true; 2779 } 2780 2781 // insert the entry in front of the list 2782 kv_pushp(buf->b_wininfo); 2783 memmove(&kv_A(buf->b_wininfo, 1), &kv_A(buf->b_wininfo, 0), 2784 (kv_size(buf->b_wininfo) - 1) * sizeof(kv_A(buf->b_wininfo, 0))); 2785 kv_A(buf->b_wininfo, 0) = wip; 2786 } 2787 2788 /// Check that "wip" has 'diff' set and the diff is only for another tab page. 2789 /// That's because a diff is local to a tab page. 2790 static bool wininfo_other_tab_diff(WinInfo *wip) 2791 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 2792 { 2793 if (!wip->wi_opt.wo_diff) { 2794 return false; 2795 } 2796 2797 FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { 2798 // return false when it's a window in the current tab page, thus 2799 // the buffer was in diff mode here 2800 if (wip->wi_win == wp) { 2801 return false; 2802 } 2803 } 2804 return true; 2805 } 2806 2807 /// Find info for the current window in buffer "buf". 2808 /// If not found, return the info for the most recently used window. 2809 /// 2810 /// @param need_options when true, skip entries where wi_optset is false. 2811 /// @param skip_diff_buffer when true, avoid windows with 'diff' set that is in another tab page. 2812 /// 2813 /// @return NULL when there isn't any info. 2814 static WinInfo *find_wininfo(buf_T *buf, bool need_options, bool skip_diff_buffer) 2815 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE 2816 { 2817 for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) { 2818 WinInfo *wip = kv_A(buf->b_wininfo, i); 2819 if (wip->wi_win == curwin 2820 && (!skip_diff_buffer || !wininfo_other_tab_diff(wip)) 2821 && (!need_options || wip->wi_optset)) { 2822 return wip; 2823 } 2824 } 2825 2826 // If no wininfo for curwin, use the first in the list (that doesn't have 2827 // 'diff' set and is in another tab page). 2828 // If "need_options" is true skip entries that don't have options set, 2829 // unless the window is editing "buf", so we can copy from the window 2830 // itself. 2831 if (skip_diff_buffer) { 2832 for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) { 2833 WinInfo *wip = kv_A(buf->b_wininfo, i); 2834 if (!wininfo_other_tab_diff(wip) 2835 && (!need_options 2836 || wip->wi_optset 2837 || (wip->wi_win != NULL 2838 && wip->wi_win->w_buffer == buf))) { 2839 return wip; 2840 } 2841 } 2842 } else if (kv_size(buf->b_wininfo)) { 2843 return kv_A(buf->b_wininfo, 0); 2844 } 2845 return NULL; 2846 } 2847 2848 /// Reset the local window options to the values last used in this window. 2849 /// If the buffer wasn't used in this window before, use the values from 2850 /// the most recently used window. If the values were never set, use the 2851 /// global values for the window. 2852 void get_winopts(buf_T *buf) 2853 { 2854 clear_winopt(&curwin->w_onebuf_opt); 2855 clearFolding(curwin); 2856 2857 WinInfo *const wip = find_wininfo(buf, true, true); 2858 if (wip != NULL && wip->wi_win != curwin && wip->wi_win != NULL 2859 && wip->wi_win->w_buffer == buf) { 2860 win_T *wp = wip->wi_win; 2861 copy_winopt(&wp->w_onebuf_opt, &curwin->w_onebuf_opt); 2862 curwin->w_fold_manual = wp->w_fold_manual; 2863 curwin->w_foldinvalid = true; 2864 cloneFoldGrowArray(&wp->w_folds, &curwin->w_folds); 2865 } else if (wip != NULL && wip->wi_optset) { 2866 copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt); 2867 curwin->w_fold_manual = wip->wi_fold_manual; 2868 curwin->w_foldinvalid = true; 2869 cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds); 2870 } else { 2871 copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt); 2872 } 2873 if (wip != NULL) { 2874 curwin->w_changelistidx = wip->wi_changelistidx; 2875 } 2876 2877 if (curwin->w_config.style == kWinStyleMinimal) { 2878 didset_window_options(curwin, false); 2879 win_set_minimal_style(curwin); 2880 } 2881 2882 // Set 'foldlevel' to 'foldlevelstart' if it's not negative. 2883 if (p_fdls >= 0) { 2884 curwin->w_p_fdl = p_fdls; 2885 } 2886 didset_window_options(curwin, false); 2887 } 2888 2889 /// Find the mark for the buffer 'buf' for the current window. 2890 /// 2891 /// @return a pointer to no_position if no position is found. 2892 fmark_T *buflist_findfmark(buf_T *buf) 2893 FUNC_ATTR_PURE 2894 { 2895 static fmark_T no_position = { { 1, 0, 0 }, 0, 0, INIT_FMARKV, NULL }; 2896 2897 WinInfo *const wip = find_wininfo(buf, false, false); 2898 return (wip == NULL) ? &no_position : &(wip->wi_mark); 2899 } 2900 2901 /// Find the lnum for the buffer 'buf' for the current window. 2902 linenr_T buflist_findlnum(buf_T *buf) 2903 FUNC_ATTR_PURE 2904 { 2905 return buflist_findfmark(buf)->mark.lnum; 2906 } 2907 2908 /// List all known file names (for :files and :buffers command). 2909 void buflist_list(exarg_T *eap) 2910 { 2911 buf_T *buf = firstbuf; 2912 2913 garray_T buflist; 2914 buf_T **buflist_data = NULL; 2915 2916 msg_ext_set_kind("list_cmd"); 2917 if (vim_strchr(eap->arg, 't')) { 2918 ga_init(&buflist, sizeof(buf_T *), 50); 2919 for (buf = firstbuf; buf != NULL; buf = buf->b_next) { 2920 ga_grow(&buflist, 1); 2921 ((buf_T **)buflist.ga_data)[buflist.ga_len++] = buf; 2922 } 2923 2924 qsort(buflist.ga_data, (size_t)buflist.ga_len, 2925 sizeof(buf_T *), buf_time_compare); 2926 2927 buflist_data = (buf_T **)buflist.ga_data; 2928 buf = *buflist_data; 2929 } 2930 buf_T **p = buflist_data; 2931 2932 for (; 2933 buf != NULL && !got_int; 2934 buf = buflist_data != NULL 2935 ? (++p < buflist_data + buflist.ga_len ? *p : NULL) : buf->b_next) { 2936 const bool is_terminal = buf->terminal; 2937 const bool job_running = buf->terminal && terminal_running(buf->terminal); 2938 2939 // skip unspecified buffers 2940 if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u')) 2941 || (vim_strchr(eap->arg, 'u') && buf->b_p_bl) 2942 || (vim_strchr(eap->arg, '+') 2943 && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf))) 2944 || (vim_strchr(eap->arg, 'a') 2945 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0)) 2946 || (vim_strchr(eap->arg, 'h') 2947 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0)) 2948 || (vim_strchr(eap->arg, 'R') && (!is_terminal || !job_running)) 2949 || (vim_strchr(eap->arg, 'F') && (!is_terminal || job_running)) 2950 || (vim_strchr(eap->arg, '-') && buf->b_p_ma) 2951 || (vim_strchr(eap->arg, '=') && !buf->b_p_ro) 2952 || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR)) 2953 || (vim_strchr(eap->arg, '%') && buf != curbuf) 2954 || (vim_strchr(eap->arg, '#') 2955 && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum))) { 2956 continue; 2957 } 2958 char *name = buf_spname(buf); 2959 if (name != NULL) { 2960 xstrlcpy(NameBuff, name, MAXPATHL); 2961 } else { 2962 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, true); 2963 } 2964 2965 if (message_filtered(NameBuff)) { 2966 continue; 2967 } 2968 2969 const int changed_char = (buf->b_flags & BF_READERR) 2970 ? 'x' 2971 : (bufIsChanged(buf) ? '+' : ' '); 2972 int ro_char = !MODIFIABLE(buf) ? '-' : (buf->b_p_ro ? '=' : ' '); 2973 if (buf->terminal) { 2974 ro_char = terminal_running(buf->terminal) ? 'R' : 'F'; 2975 } 2976 2977 if (!ui_has(kUIMessages) || msg_col > 0) { 2978 msg_putchar('\n'); 2979 } 2980 int len = (int)vim_snprintf_safelen(IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", 2981 buf->b_fnum, 2982 buf->b_p_bl ? ' ' : 'u', 2983 buf == curbuf ? '%' 2984 : (curwin->w_alt_fnum 2985 == buf->b_fnum ? '#' : ' '), 2986 buf->b_ml.ml_mfp == NULL ? ' ' 2987 : (buf->b_nwindows 2988 == 0 ? 'h' : 'a'), 2989 ro_char, 2990 changed_char, 2991 NameBuff); 2992 2993 len = MIN(len, IOSIZE - 20); 2994 2995 // put "line 999" in column 40 or after the file name 2996 int i = 40 - vim_strsize(IObuff); 2997 do { 2998 IObuff[len++] = ' '; 2999 } while (--i > 0 && len < IOSIZE - 18); 3000 if (vim_strchr(eap->arg, 't') && buf->b_last_used) { 3001 undo_fmt_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used); 3002 } else { 3003 vim_snprintf(IObuff + len, (size_t)(IOSIZE - len), _("line %" PRId64), 3004 buf == curbuf ? (int64_t)curwin->w_cursor.lnum : (int64_t)buflist_findlnum(buf)); 3005 } 3006 3007 msg_outtrans(IObuff, 0, false); 3008 line_breakcheck(); 3009 } 3010 3011 if (buflist_data) { 3012 ga_clear(&buflist); 3013 } 3014 } 3015 3016 /// Get file name and line number for file 'fnum'. 3017 /// Used by DoOneCmd() for translating '%' and '#'. 3018 /// Used by insert_reg() and cmdline_paste() for '#' register. 3019 /// 3020 /// @return FAIL if not found, OK for success. 3021 int buflist_name_nr(int fnum, char **fname, linenr_T *lnum) 3022 { 3023 buf_T *buf = buflist_findnr(fnum); 3024 if (buf == NULL || buf->b_fname == NULL) { 3025 return FAIL; 3026 } 3027 3028 *fname = buf->b_fname; 3029 *lnum = buflist_findlnum(buf); 3030 3031 return OK; 3032 } 3033 3034 /// Set the file name for "buf" to "ffname_arg", short file name to 3035 /// "sfname_arg". 3036 /// The file name with the full path is also remembered, for when :cd is used. 3037 /// 3038 /// @param message give message when buffer already exists 3039 /// 3040 /// @return FAIL for failure (file name already in use by other buffer) OK otherwise. 3041 int setfname(buf_T *buf, char *ffname_arg, char *sfname_arg, bool message) 3042 { 3043 char *ffname = ffname_arg; 3044 char *sfname = sfname_arg; 3045 buf_T *obuf = NULL; 3046 FileID file_id; 3047 bool file_id_valid = false; 3048 3049 if (ffname == NULL || *ffname == NUL) { 3050 // Removing the name. 3051 if (buf->b_sfname != buf->b_ffname) { 3052 XFREE_CLEAR(buf->b_sfname); 3053 } else { 3054 buf->b_sfname = NULL; 3055 } 3056 XFREE_CLEAR(buf->b_ffname); 3057 } else { 3058 fname_expand(buf, &ffname, &sfname); // will allocate ffname 3059 if (ffname == NULL) { // out of memory 3060 return FAIL; 3061 } 3062 3063 // If the file name is already used in another buffer: 3064 // - if the buffer is loaded, fail 3065 // - if the buffer is not loaded, delete it from the list 3066 file_id_valid = os_fileid(ffname, &file_id); 3067 if (!(buf->b_flags & BF_DUMMY)) { 3068 obuf = buflist_findname_file_id(ffname, &file_id, file_id_valid); 3069 } 3070 if (obuf != NULL && obuf != buf) { 3071 bool in_use = false; 3072 3073 // during startup a window may use a buffer that is not loaded yet 3074 FOR_ALL_TAB_WINDOWS(tab, win) { 3075 if (win->w_buffer == obuf) { 3076 in_use = true; 3077 } 3078 } 3079 3080 // it's loaded or used in a window, fail 3081 if (obuf->b_ml.ml_mfp != NULL || in_use) { 3082 if (message) { 3083 emsg(_("E95: Buffer with this name already exists")); 3084 } 3085 xfree(ffname); 3086 return FAIL; 3087 } 3088 // delete from the list 3089 close_buffer(NULL, obuf, DOBUF_WIPE, false, false); 3090 } 3091 sfname = xstrdup(sfname); 3092 #ifdef CASE_INSENSITIVE_FILENAME 3093 path_fix_case(sfname); // set correct case for short file name 3094 #endif 3095 if (buf->b_sfname != buf->b_ffname) { 3096 xfree(buf->b_sfname); 3097 } 3098 xfree(buf->b_ffname); 3099 buf->b_ffname = ffname; 3100 buf->b_sfname = sfname; 3101 } 3102 buf->b_fname = buf->b_sfname; 3103 if (!file_id_valid) { 3104 buf->file_id_valid = false; 3105 } else { 3106 buf->file_id_valid = true; 3107 buf->file_id = file_id; 3108 } 3109 3110 buf_name_changed(buf); 3111 return OK; 3112 } 3113 3114 /// Crude way of changing the name of a buffer. Use with care! 3115 /// The name should be relative to the current directory. 3116 void buf_set_name(int fnum, char *name) 3117 { 3118 buf_T *buf = buflist_findnr(fnum); 3119 if (buf == NULL) { 3120 return; 3121 } 3122 3123 if (buf->b_sfname != buf->b_ffname) { 3124 xfree(buf->b_sfname); 3125 } 3126 xfree(buf->b_ffname); 3127 buf->b_ffname = xstrdup(name); 3128 buf->b_sfname = NULL; 3129 // Allocate ffname and expand into full path. Also resolves .lnk 3130 // files on Win32. 3131 fname_expand(buf, &buf->b_ffname, &buf->b_sfname); 3132 buf->b_fname = buf->b_sfname; 3133 } 3134 3135 /// Take care of what needs to be done when the name of buffer "buf" has changed. 3136 void buf_name_changed(buf_T *buf) 3137 { 3138 // If the file name changed, also change the name of the swapfile 3139 if (buf->b_ml.ml_mfp != NULL) { 3140 ml_setname(buf); 3141 } 3142 3143 if (curwin->w_buffer == buf) { 3144 check_arg_idx(curwin); // check file name for arg list 3145 } 3146 maketitle(); // set window title 3147 status_redraw_all(); // status lines need to be redrawn 3148 fmarks_check_names(buf); // check named file marks 3149 ml_timestamp(buf); // reset timestamp 3150 } 3151 3152 /// Set alternate file name for current window 3153 /// 3154 /// Used by do_one_cmd(), do_write() and do_ecmd(). 3155 /// 3156 /// @return the buffer. 3157 buf_T *setaltfname(char *ffname, char *sfname, linenr_T lnum) 3158 { 3159 // Create a buffer. 'buflisted' is not set if it's a new buffer 3160 buf_T *buf = buflist_new(ffname, sfname, lnum, 0); 3161 if (buf != NULL && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0) { 3162 curwin->w_alt_fnum = buf->b_fnum; 3163 } 3164 return buf; 3165 } 3166 3167 /// Get alternate file name for current window. 3168 /// Return NULL if there isn't any, and give error message if requested. 3169 /// 3170 /// @param errmsg give error message 3171 char *getaltfname(bool errmsg) 3172 { 3173 char *fname; 3174 linenr_T dummy; 3175 3176 if (buflist_name_nr(0, &fname, &dummy) == FAIL) { 3177 if (errmsg) { 3178 emsg(_(e_noalt)); 3179 } 3180 return NULL; 3181 } 3182 return fname; 3183 } 3184 3185 /// Add a file name to the buflist and return its number. 3186 /// Uses same flags as buflist_new(), except BLN_DUMMY. 3187 /// 3188 /// Used by qf_init(), main() and doarglist() 3189 int buflist_add(char *fname, int flags) 3190 { 3191 buf_T *buf = buflist_new(fname, NULL, 0, flags); 3192 if (buf != NULL) { 3193 return buf->b_fnum; 3194 } 3195 return 0; 3196 } 3197 3198 #if defined(BACKSLASH_IN_FILENAME) 3199 /// Adjust slashes in file names. Called after 'shellslash' was set. 3200 void buflist_slash_adjust(void) 3201 { 3202 FOR_ALL_BUFFERS(bp) { 3203 if (bp->b_ffname != NULL) { 3204 slash_adjust(bp->b_ffname); 3205 } 3206 if (bp->b_sfname != NULL) { 3207 slash_adjust(bp->b_sfname); 3208 } 3209 } 3210 } 3211 3212 #endif 3213 3214 /// Set alternate cursor position for the current buffer and window "win". 3215 /// Also save the local window option values. 3216 void buflist_altfpos(win_T *win) 3217 { 3218 buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, 3219 win->w_config.style != kWinStyleMinimal); 3220 } 3221 3222 /// Check that "ffname" is not the same file as current file. 3223 /// Fname must have a full path (expanded by path_to_absolute()). 3224 /// 3225 /// @param ffname full path name to check 3226 bool otherfile(char *ffname) 3227 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 3228 { 3229 return otherfile_buf(curbuf, ffname, NULL, false); 3230 } 3231 3232 /// Check that "ffname" is not the same file as the file loaded in "buf". 3233 /// Fname must have a full path (expanded by path_to_absolute()). 3234 /// 3235 /// @param buf buffer to check 3236 /// @param ffname full path name to check 3237 /// @param file_id_p information about the file at "ffname". 3238 /// @param file_id_valid whether a valid "file_id_p" was passed in. 3239 static bool otherfile_buf(buf_T *buf, char *ffname, FileID *file_id_p, bool file_id_valid) 3240 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3241 { 3242 // no name is different 3243 if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) { 3244 return true; 3245 } 3246 if (path_fnamecmp(ffname, buf->b_ffname) == 0) { 3247 return false; 3248 } 3249 { 3250 FileID file_id; 3251 // If no struct stat given, get it now 3252 if (file_id_p == NULL) { 3253 file_id_p = &file_id; 3254 file_id_valid = os_fileid(ffname, file_id_p); 3255 } 3256 if (!file_id_valid) { 3257 // file_id not valid, assume files are different. 3258 return true; 3259 } 3260 // Use dev/ino to check if the files are the same, even when the names 3261 // are different (possible with links). Still need to compare the 3262 // name above, for when the file doesn't exist yet. 3263 // Problem: The dev/ino changes when a file is deleted (and created 3264 // again) and remains the same when renamed/moved. We don't want to 3265 // stat() each buffer each time, that would be too slow. Get the 3266 // dev/ino again when they appear to match, but not when they appear 3267 // to be different: Could skip a buffer when it's actually the same 3268 // file. 3269 if (buf_same_file_id(buf, file_id_p)) { 3270 buf_set_file_id(buf); 3271 if (buf_same_file_id(buf, file_id_p)) { 3272 return false; 3273 } 3274 } 3275 } 3276 return true; 3277 } 3278 3279 /// Set file_id for a buffer. 3280 /// Must always be called when b_fname is changed! 3281 void buf_set_file_id(buf_T *buf) 3282 { 3283 FileID file_id; 3284 if (buf->b_fname != NULL 3285 && os_fileid(buf->b_fname, &file_id)) { 3286 buf->file_id_valid = true; 3287 buf->file_id = file_id; 3288 } else { 3289 buf->file_id_valid = false; 3290 } 3291 } 3292 3293 /// Check that file_id in buffer "buf" matches with "file_id". 3294 /// 3295 /// @param buf buffer 3296 /// @param file_id file id 3297 static bool buf_same_file_id(buf_T *buf, FileID *file_id) 3298 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 3299 { 3300 return buf->file_id_valid && os_fileid_equal(&(buf->file_id), file_id); 3301 } 3302 3303 /// Print info about the current buffer. 3304 /// 3305 /// @param fullname when non-zero print full path 3306 void fileinfo(int fullname, int shorthelp, bool dont_truncate) 3307 { 3308 char *buffer = xmalloc(IOSIZE); 3309 size_t bufferlen = 0; 3310 3311 if (fullname > 1) { // 2 CTRL-G: include buffer number 3312 bufferlen = vim_snprintf_safelen(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); 3313 } 3314 3315 buffer[bufferlen++] = '"'; 3316 3317 char *name = buf_spname(curbuf); 3318 if (name != NULL) { 3319 bufferlen += vim_snprintf_safelen(buffer + bufferlen, 3320 IOSIZE - bufferlen, "%s", name); 3321 } else { 3322 name = (!fullname && curbuf->b_fname != NULL) ? curbuf->b_fname : curbuf->b_ffname; 3323 home_replace(shorthelp ? curbuf : NULL, name, buffer + bufferlen, 3324 IOSIZE - bufferlen, true); 3325 bufferlen += strlen(buffer + bufferlen); 3326 } 3327 3328 bool dontwrite = bt_dontwrite(curbuf); 3329 bufferlen += vim_snprintf_safelen(buffer + bufferlen, 3330 IOSIZE - bufferlen, 3331 "\"%s%s%s%s%s%s", 3332 curbufIsChanged() 3333 ? (shortmess(SHM_MOD) ? " [+]" : _(" [Modified]")) 3334 : " ", 3335 (curbuf->b_flags & BF_NOTEDITED) && !dontwrite 3336 ? _("[Not edited]") : "", 3337 (curbuf->b_flags & BF_NEW) && !dontwrite 3338 ? _("[New]") : "", 3339 (curbuf->b_flags & BF_READERR) 3340 ? _("[Read errors]") : "", 3341 curbuf->b_p_ro 3342 ? (shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")) 3343 : "", 3344 (curbufIsChanged() 3345 || (curbuf->b_flags & BF_WRITE_MASK) 3346 || curbuf->b_p_ro) 3347 ? " " : ""); 3348 3349 if (curbuf->b_ml.ml_flags & ML_EMPTY) { 3350 bufferlen += vim_snprintf_safelen(buffer + bufferlen, 3351 IOSIZE - bufferlen, "%s", _(no_lines_msg)); 3352 } else if (p_ru) { 3353 // Current line and column are already on the screen -- webb 3354 bufferlen += vim_snprintf_safelen(buffer + bufferlen, 3355 IOSIZE - bufferlen, 3356 NGETTEXT("%" PRId64 " line --%d%%--", 3357 "%" PRId64 " lines --%d%%--", 3358 curbuf->b_ml.ml_line_count), 3359 (int64_t)curbuf->b_ml.ml_line_count, 3360 calc_percentage(curwin->w_cursor.lnum, 3361 curbuf->b_ml.ml_line_count)); 3362 } else { 3363 bufferlen += vim_snprintf_safelen(buffer + bufferlen, 3364 IOSIZE - bufferlen, 3365 _("line %" PRId64 " of %" PRId64 " --%d%%-- col "), 3366 (int64_t)curwin->w_cursor.lnum, 3367 (int64_t)curbuf->b_ml.ml_line_count, 3368 calc_percentage(curwin->w_cursor.lnum, 3369 curbuf->b_ml.ml_line_count)); 3370 validate_virtcol(curwin); 3371 bufferlen += (size_t)col_print(buffer + bufferlen, IOSIZE - bufferlen, 3372 curwin->w_cursor.col + 1, curwin->w_virtcol + 1); 3373 } 3374 3375 append_arg_number(curwin, buffer + bufferlen, IOSIZE - bufferlen); 3376 3377 if (dont_truncate) { 3378 // Temporarily set msg_scroll to avoid the message being truncated. 3379 // First call msg_start() to get the message in the right place. 3380 msg_start(); 3381 int n = msg_scroll; 3382 msg_scroll = true; 3383 msg(buffer, 0); 3384 msg_scroll = n; 3385 } else { 3386 char *p = msg_trunc(buffer, false, 0); 3387 if (restart_edit != 0 || (msg_scrolled && !need_wait_return)) { 3388 // Need to repeat the message after redrawing when: 3389 // - When restart_edit is set (otherwise there will be a delay 3390 // before redrawing). 3391 // - When the screen was scrolled but there is no wait-return 3392 // prompt. 3393 set_keep_msg(p, 0); 3394 } 3395 } 3396 3397 xfree(buffer); 3398 } 3399 3400 int col_print(char *buf, size_t buflen, int col, int vcol) 3401 { 3402 if (col == vcol) { 3403 return (int)vim_snprintf_safelen(buf, buflen, "%d", col); 3404 } 3405 3406 return (int)vim_snprintf_safelen(buf, buflen, "%d-%d", col, vcol); 3407 } 3408 3409 static char *lasttitle = NULL; 3410 static char *lasticon = NULL; 3411 3412 /// Put the title name in the title bar and icon of the window. 3413 void maketitle(void) 3414 { 3415 char *title_str = NULL; 3416 char *icon_str = NULL; 3417 char buf[IOSIZE]; 3418 3419 if (!redrawing()) { 3420 // Postpone updating the title when 'lazyredraw' is set. 3421 need_maketitle = true; 3422 return; 3423 } 3424 3425 need_maketitle = false; 3426 if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL) { 3427 return; // nothing to do 3428 } 3429 3430 if (p_title) { 3431 int maxlen = 0; 3432 3433 if (p_titlelen > 0) { 3434 maxlen = MAX((int)(p_titlelen * Columns / 100), 10); 3435 } 3436 3437 if (*p_titlestring != NUL) { 3438 if (stl_syntax & STL_IN_TITLE) { 3439 build_stl_str_hl(curwin, buf, sizeof(buf), p_titlestring, 3440 kOptTitlestring, 0, 0, maxlen, NULL, NULL, NULL, NULL); 3441 title_str = buf; 3442 } else { 3443 title_str = p_titlestring; 3444 } 3445 } else { 3446 // Format: "fname + (path) (1 of 2) - Nvim". 3447 char *default_titlestring = "%t%( %M%)%( (%{expand(\"%:~:h\")})%)%a - Nvim"; 3448 build_stl_str_hl(curwin, buf, sizeof(buf), default_titlestring, 3449 kOptTitlestring, 0, 0, maxlen, NULL, NULL, NULL, NULL); 3450 title_str = buf; 3451 } 3452 } 3453 bool mustset = value_change(title_str, &lasttitle); 3454 3455 if (p_icon) { 3456 icon_str = buf; 3457 if (*p_iconstring != NUL) { 3458 if (stl_syntax & STL_IN_ICON) { 3459 build_stl_str_hl(curwin, icon_str, sizeof(buf), p_iconstring, 3460 kOptIconstring, 0, 0, 0, NULL, NULL, NULL, NULL); 3461 } else { 3462 icon_str = p_iconstring; 3463 } 3464 } else { 3465 char *name = buf_spname(curbuf); 3466 if (name == NULL) { 3467 name = path_tail(curbuf->b_ffname); 3468 } 3469 // Truncate name at 100 bytes. 3470 int namelen = (int)strlen(name); 3471 if (namelen > 100) { 3472 namelen -= 100; 3473 namelen += utf_cp_bounds(name, name + namelen).end_off; 3474 name += namelen; 3475 } 3476 STRCPY(buf, name); 3477 trans_characters(buf, sizeof(buf)); 3478 } 3479 } 3480 3481 mustset |= value_change(icon_str, &lasticon); 3482 3483 if (mustset) { 3484 resettitle(); 3485 } 3486 } 3487 3488 /// Used for title and icon: Check if "str" differs from "*last". Set "*last" 3489 /// from "str" if it does by freeing the old value of "*last" and duplicating 3490 /// "str". 3491 /// 3492 /// @param str desired title string 3493 /// @param[in,out] last current title string 3494 /// 3495 /// @return true if resettitle() is to be called. 3496 static bool value_change(char *str, char **last) 3497 FUNC_ATTR_WARN_UNUSED_RESULT 3498 { 3499 if ((str == NULL) != (*last == NULL) 3500 || (str != NULL && *last != NULL && strcmp(str, *last) != 0)) { 3501 xfree(*last); 3502 if (str == NULL) { 3503 *last = NULL; 3504 resettitle(); 3505 } else { 3506 *last = xstrdup(str); 3507 return true; 3508 } 3509 } 3510 return false; 3511 } 3512 3513 /// Set current window title 3514 void resettitle(void) 3515 { 3516 ui_call_set_icon(cstr_as_string(lasticon)); 3517 ui_call_set_title(cstr_as_string(lasttitle)); 3518 } 3519 3520 #if defined(EXITFREE) 3521 void free_titles(void) 3522 { 3523 xfree(lasttitle); 3524 xfree(lasticon); 3525 } 3526 3527 #endif 3528 3529 /// Get relative cursor position in window into "buf[]", in the localized 3530 /// percentage form like %99, 99%; using "Top", "Bot" or "All" when appropriate. 3531 int get_rel_pos(win_T *wp, char *buf, int buflen) 3532 { 3533 // Need at least 3 chars for writing. 3534 if (buflen < 3) { 3535 return 0; 3536 } 3537 3538 linenr_T above; // number of lines above window 3539 linenr_T below; // number of lines below window 3540 3541 above = wp->w_topline - 1; 3542 above += win_get_fill(wp, wp->w_topline) - wp->w_topfill; 3543 if (wp->w_topline == 1 && wp->w_topfill >= 1) { 3544 // All buffer lines are displayed and there is an indication 3545 // of filler lines, that can be considered seeing all lines. 3546 above = 0; 3547 } 3548 below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; 3549 if (below <= 0) { 3550 return (int)vim_snprintf_safelen(buf, (size_t)buflen, 3551 "%s", (above == 0) ? _("All") : _("Bot")); 3552 } 3553 3554 if (above <= 0) { 3555 return (int)vim_snprintf_safelen(buf, (size_t)buflen, 3556 "%s", _("Top")); 3557 } 3558 3559 int perc = calc_percentage(above, above + below); 3560 char tmp[8]; 3561 // localized percentage value 3562 vim_snprintf(tmp, sizeof(tmp), _("%d%%"), perc); 3563 return (int)vim_snprintf_safelen(buf, (size_t)buflen, _("%3s"), tmp); 3564 } 3565 3566 /// Append (2 of 8) to "buf[]", if editing more than one file. 3567 /// 3568 /// @param wp window whose buffers to check 3569 /// @param[in,out] buf string buffer to add the text to 3570 /// @param buflen length of the string buffer 3571 /// 3572 /// @return the number of characters appended. 3573 int append_arg_number(win_T *wp, char *buf, size_t buflen) 3574 FUNC_ATTR_NONNULL_ALL 3575 { 3576 // Nothing to do 3577 if (ARGCOUNT <= 1) { 3578 return 0; 3579 } 3580 3581 const char *msg = wp->w_arg_idx_invalid ? _(" ((%d) of %d)") : _(" (%d of %d)"); 3582 3583 return (int)vim_snprintf_safelen(buf, buflen, msg, wp->w_arg_idx + 1, ARGCOUNT); 3584 } 3585 3586 /// Make "*ffname" a full file name, set "*sfname" to "*ffname" if not NULL. 3587 /// "*ffname" becomes a pointer to allocated memory (or NULL). 3588 /// When resolving a link both "*sfname" and "*ffname" will point to the same 3589 /// allocated memory. 3590 /// The "*ffname" and "*sfname" pointer values on call will not be freed. 3591 /// Note that the resulting "*ffname" pointer should be considered not allocated. 3592 void fname_expand(buf_T *buf, char **ffname, char **sfname) 3593 { 3594 if (*ffname == NULL) { // no file name given, nothing to do 3595 return; 3596 } 3597 if (*sfname == NULL) { // no short file name given, use ffname 3598 *sfname = *ffname; 3599 } 3600 *ffname = fix_fname((*ffname)); // expand to full path 3601 3602 #ifdef MSWIN 3603 if (!buf->b_p_bin) { 3604 // If the file name is a shortcut file, use the file it links to. 3605 char *rfname = os_resolve_shortcut(*ffname); 3606 if (rfname != NULL) { 3607 xfree(*ffname); 3608 *ffname = rfname; 3609 *sfname = rfname; 3610 } 3611 } 3612 #endif 3613 } 3614 3615 /// @return true if "buf" is a prompt buffer. 3616 bool bt_prompt(buf_T *buf) 3617 FUNC_ATTR_PURE 3618 { 3619 return buf != NULL && buf->b_p_bt[0] == 'p'; 3620 } 3621 3622 /// Open a window for a number of buffers. 3623 void ex_buffer_all(exarg_T *eap) 3624 { 3625 win_T *wpnext; 3626 int split_ret = OK; 3627 int open_wins = 0; 3628 int had_tab = cmdmod.cmod_tab; 3629 3630 // Maximum number of windows to open. 3631 linenr_T count = eap->addr_count == 0 3632 ? 9999 // make as many windows as possible 3633 : eap->line2; // make as many windows as specified 3634 3635 // When true also load inactive buffers. 3636 int all = eap->cmdidx != CMD_unhide && eap->cmdidx != CMD_sunhide; 3637 3638 // Stop Visual mode, the cursor and "VIsual" may very well be invalid after 3639 // switching to another buffer. 3640 reset_VIsual_and_resel(); 3641 3642 setpcmark(); 3643 3644 // Close superfluous windows (two windows for the same buffer). 3645 // Also close windows that are not full-width. 3646 if (had_tab > 0) { 3647 goto_tabpage_tp(first_tabpage, true, true); 3648 } 3649 while (true) { 3650 tabpage_T *tpnext = curtab->tp_next; 3651 // Try to close floating windows first 3652 for (win_T *wp = lastwin->w_floating ? lastwin : firstwin; wp != NULL; wp = wpnext) { 3653 wpnext = wp->w_floating 3654 ? wp->w_prev->w_floating ? wp->w_prev : firstwin 3655 : (wp->w_next == NULL || wp->w_next->w_floating) ? NULL : wp->w_next; 3656 if ((wp->w_buffer->b_nwindows > 1 3657 || wp->w_floating 3658 || ((cmdmod.cmod_split & WSP_VERT) 3659 ? wp->w_height + wp->w_hsep_height + wp->w_status_height < Rows - p_ch 3660 - tabline_height() - global_stl_height() 3661 : wp->w_width != Columns) 3662 || (had_tab > 0 && wp != firstwin)) 3663 && !ONE_WINDOW 3664 && !(win_locked(curwin) || wp->w_buffer->b_locked > 0) 3665 && !is_aucmd_win(wp)) { 3666 if (win_close(wp, false, false) == FAIL) { 3667 break; 3668 } 3669 // Just in case an autocommand does something strange with 3670 // windows: start all over... 3671 wpnext = lastwin->w_floating ? lastwin : firstwin; 3672 tpnext = first_tabpage; 3673 open_wins = 0; 3674 } else { 3675 open_wins++; 3676 } 3677 } 3678 3679 // Without the ":tab" modifier only do the current tab page. 3680 if (had_tab == 0 || tpnext == NULL) { 3681 break; 3682 } 3683 goto_tabpage_tp(tpnext, true, true); 3684 } 3685 3686 // Go through the buffer list. When a buffer doesn't have a window yet, 3687 // open one. Otherwise move the window to the right position. 3688 // Watch out for autocommands that delete buffers or windows! 3689 // 3690 // Don't execute Win/Buf Enter/Leave autocommands here. 3691 autocmd_no_enter++; 3692 // lastwin may be aucmd_win 3693 win_enter(lastwin_nofloating(), false); 3694 autocmd_no_leave++; 3695 for (buf_T *buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) { 3696 // Check if this buffer needs a window 3697 if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl) { 3698 continue; 3699 } 3700 3701 win_T *wp; 3702 if (had_tab != 0) { 3703 // With the ":tab" modifier don't move the window. 3704 wp = buf->b_nwindows > 0 3705 ? lastwin // buffer has a window, skip it 3706 : NULL; 3707 } else { 3708 // Check if this buffer already has a window 3709 for (wp = firstwin; wp != NULL; wp = wp->w_next) { 3710 if (!wp->w_floating && wp->w_buffer == buf) { 3711 break; 3712 } 3713 } 3714 // If the buffer already has a window, move it 3715 if (wp != NULL) { 3716 win_move_after(wp, curwin); 3717 } 3718 } 3719 3720 if (wp == NULL && split_ret == OK) { 3721 bufref_T bufref; 3722 set_bufref(&bufref, buf); 3723 // Split the window and put the buffer in it. 3724 bool p_ea_save = p_ea; 3725 p_ea = true; // use space from all windows 3726 split_ret = win_split(0, WSP_ROOM | WSP_BELOW); 3727 open_wins++; 3728 p_ea = p_ea_save; 3729 if (split_ret == FAIL) { 3730 continue; 3731 } 3732 3733 // Open the buffer in this window. 3734 swap_exists_action = SEA_DIALOG; 3735 set_curbuf(buf, DOBUF_GOTO, !(jop_flags & kOptJopFlagClean)); 3736 if (!bufref_valid(&bufref)) { 3737 // Autocommands deleted the buffer. 3738 swap_exists_action = SEA_NONE; 3739 break; 3740 } 3741 if (swap_exists_action == SEA_QUIT) { 3742 cleanup_T cs; 3743 3744 // Reset the error/interrupt/exception state here so that 3745 // aborting() returns false when closing a window. 3746 enter_cleanup(&cs); 3747 3748 // User selected Quit at ATTENTION prompt; close this window. 3749 win_close(curwin, true, false); 3750 open_wins--; 3751 swap_exists_action = SEA_NONE; 3752 swap_exists_did_quit = true; 3753 3754 // Restore the error/interrupt/exception state if not 3755 // discarded by a new aborting error, interrupt, or uncaught 3756 // exception. 3757 leave_cleanup(&cs); 3758 } else { 3759 handle_swap_exists(NULL); 3760 } 3761 } 3762 3763 os_breakcheck(); 3764 if (got_int) { 3765 vgetc(); // only break the file loading, not the rest 3766 break; 3767 } 3768 // Autocommands deleted the buffer or aborted script processing!!! 3769 if (aborting()) { 3770 break; 3771 } 3772 // When ":tab" was used open a new tab for a new window repeatedly. 3773 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) { 3774 cmdmod.cmod_tab = 9999; 3775 } 3776 } 3777 autocmd_no_enter--; 3778 win_enter(firstwin, false); // back to first window 3779 autocmd_no_leave--; 3780 3781 // Close superfluous windows. 3782 for (win_T *wp = lastwin; open_wins > count;) { 3783 bool r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) 3784 || autowrite(wp->w_buffer, false) == OK) && !is_aucmd_win(wp); 3785 if (!win_valid(wp)) { 3786 // BufWrite Autocommands made the window invalid, start over 3787 wp = lastwin; 3788 } else if (r) { 3789 win_close(wp, !buf_hide(wp->w_buffer), false); 3790 open_wins--; 3791 wp = lastwin; 3792 } else { 3793 wp = wp->w_prev; 3794 if (wp == NULL) { 3795 break; 3796 } 3797 } 3798 } 3799 } 3800 3801 /// do_modelines() - process mode lines for the current file 3802 /// 3803 /// @param flags 3804 /// OPT_WINONLY only set options local to window 3805 /// OPT_NOWIN don't set options local to window 3806 /// 3807 /// Returns immediately if the "ml" option isn't set. 3808 void do_modelines(int flags) 3809 { 3810 linenr_T lnum; 3811 int nmlines; 3812 static int entered = 0; 3813 3814 if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0) { 3815 return; 3816 } 3817 3818 // Disallow recursive entry here. Can happen when executing a modeline 3819 // triggers an autocommand, which reloads modelines with a ":do". 3820 if (entered) { 3821 return; 3822 } 3823 3824 entered++; 3825 for (lnum = 1; curbuf->b_p_ml && lnum <= curbuf->b_ml.ml_line_count 3826 && lnum <= nmlines; lnum++) { 3827 if (chk_modeline(lnum, flags) == FAIL) { 3828 nmlines = 0; 3829 } 3830 } 3831 3832 for (lnum = curbuf->b_ml.ml_line_count; curbuf->b_p_ml && lnum > 0 3833 && lnum > nmlines && lnum > curbuf->b_ml.ml_line_count - nmlines; 3834 lnum--) { 3835 if (chk_modeline(lnum, flags) == FAIL) { 3836 nmlines = 0; 3837 } 3838 } 3839 entered--; 3840 } 3841 3842 /// chk_modeline() - check a single line for a mode string 3843 /// Return FAIL if an error encountered. 3844 /// 3845 /// @param flags Same as for do_modelines(). 3846 static int chk_modeline(linenr_T lnum, int flags) 3847 { 3848 char *e; 3849 int retval = OK; 3850 ESTACK_CHECK_DECLARATION; 3851 3852 int prev = -1; 3853 char *s = ml_get(lnum); 3854 char *line_end = s + ml_get_len(lnum); 3855 for (; *s != NUL; s++) { 3856 if (prev == -1 || ascii_isspace(prev)) { 3857 if ((prev != -1 && strncmp(s, "ex:", 3) == 0) 3858 || strncmp(s, "vi:", 3) == 0) { 3859 break; 3860 } 3861 // Accept both "vim" and "Vim". 3862 if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') { 3863 if (s[3] == '<' || s[3] == '=' || s[3] == '>') { 3864 e = s + 4; 3865 } else { 3866 e = s + 3; 3867 } 3868 intmax_t vers; 3869 if (!try_getdigits(&e, &vers)) { 3870 continue; 3871 } 3872 3873 const int vim_version = min_vim_version(); 3874 if (*e == ':' 3875 && (s[0] != 'V' 3876 || strncmp(skipwhite(e + 1), "set", 3) == 0) 3877 && (s[3] == ':' 3878 || (vim_version >= vers && isdigit((uint8_t)s[3])) 3879 || (vim_version < vers && s[3] == '<') 3880 || (vim_version > vers && s[3] == '>') 3881 || (vim_version == vers && s[3] == '='))) { 3882 break; 3883 } 3884 } 3885 } 3886 prev = (uint8_t)(*s); 3887 } 3888 3889 if (!*s) { 3890 return retval; 3891 } 3892 3893 do { // skip over "ex:", "vi:" or "vim:" 3894 s++; 3895 } while (s[-1] != ':'); 3896 3897 size_t len = (size_t)(line_end - s); // remember the line length so we can restore 3898 // 'line_end' after the copy 3899 char *linecopy; // local copy of any modeline found 3900 s = linecopy = xstrnsave(s, len); // copy the line, it will change 3901 3902 line_end = s + len; // restore 'line_end' 3903 3904 // prepare for emsg() 3905 estack_push(ETYPE_MODELINE, "modelines", lnum); 3906 ESTACK_CHECK_SETUP; 3907 3908 bool end = false; 3909 while (end == false) { 3910 s = skipwhite(s); 3911 if (*s == NUL) { 3912 break; 3913 } 3914 3915 // Find end of set command: ':' or end of line. 3916 // Skip over "\:", replacing it with ":". 3917 for (e = s; *e != ':' && *e != NUL; e++) { 3918 if (e[0] == '\\' && e[1] == ':') { 3919 memmove(e, e + 1, (size_t)(line_end - (e + 1)) + 1); // +1 for NUL 3920 line_end--; 3921 } 3922 } 3923 if (*e == NUL) { 3924 end = true; 3925 } 3926 3927 // If there is a "set" command, require a terminating ':' and 3928 // ignore the stuff after the ':'. 3929 // "vi:set opt opt opt: foo" -- foo not interpreted 3930 // "vi:opt opt opt: foo" -- foo interpreted 3931 // Accept "se" for compatibility with Elvis. 3932 if (strncmp(s, "set ", 4) == 0 3933 || strncmp(s, "se ", 3) == 0) { 3934 if (*e != ':') { // no terminating ':'? 3935 break; 3936 } 3937 end = true; 3938 s += (*(s + 2) == ' ') ? 3 : 4; 3939 } 3940 *e = NUL; // truncate the set command 3941 3942 if (*s != NUL) { // skip over an empty "::" 3943 const int secure_save = secure; 3944 const sctx_T save_current_sctx = current_sctx; 3945 current_sctx.sc_sid = SID_MODELINE; 3946 current_sctx.sc_seq = 0; 3947 current_sctx.sc_lnum = lnum; 3948 // Make sure no risky things are executed as a side effect. 3949 secure = 1; 3950 3951 retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); 3952 3953 secure = secure_save; 3954 current_sctx = save_current_sctx; 3955 if (retval == FAIL) { // stop if error found 3956 break; 3957 } 3958 } 3959 s = (e == line_end) ? e : e + 1; // advance to next part 3960 // careful not to go off the end 3961 } 3962 3963 ESTACK_CHECK_NOW; 3964 estack_pop(); 3965 xfree(linecopy); 3966 3967 return retval; 3968 } 3969 3970 /// @return true if "buf" is a help buffer. 3971 bool bt_help(const buf_T *const buf) 3972 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3973 { 3974 return buf != NULL && buf->b_help; 3975 } 3976 3977 /// @return true if "buf" is a normal buffer, 'buftype' is empty. 3978 bool bt_normal(const buf_T *const buf) 3979 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3980 { 3981 return buf != NULL && buf->b_p_bt[0] == NUL; 3982 } 3983 3984 /// @return true if "buf" is the quickfix buffer. 3985 bool bt_quickfix(const buf_T *const buf) 3986 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3987 { 3988 return buf != NULL && buf->b_p_bt[0] == 'q'; 3989 } 3990 3991 /// @return true if "buf" is a terminal buffer. 3992 bool bt_terminal(const buf_T *const buf) 3993 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 3994 { 3995 return buf != NULL && buf->b_p_bt[0] == 't'; 3996 } 3997 3998 /// @return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt" 3999 /// buffer. This means the buffer name may not be a file name, 4000 /// at least not for writing the buffer. 4001 bool bt_nofilename(const buf_T *const buf) 4002 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 4003 { 4004 return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') 4005 || buf->b_p_bt[0] == 'a' 4006 || buf->terminal 4007 || buf->b_p_bt[0] == 'p'); 4008 } 4009 4010 /// @return true if "buf" is a "nofile", "quickfix", "terminal" or "prompt" 4011 /// buffer. This means the buffer is not to be read from a file. 4012 static bool bt_nofileread(const buf_T *const buf) 4013 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 4014 { 4015 return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') 4016 || buf->b_p_bt[0] == 't' 4017 || buf->b_p_bt[0] == 'q' 4018 || buf->b_p_bt[0] == 'p'); 4019 } 4020 4021 /// @return true if "buf" has 'buftype' set to "nofile". 4022 bool bt_nofile(const buf_T *const buf) 4023 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 4024 { 4025 return buf != NULL && buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f'; 4026 } 4027 4028 /// @return true if "buf" is a "nowrite", "nofile", "terminal" or "prompt" 4029 /// buffer. 4030 bool bt_dontwrite(const buf_T *const buf) 4031 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 4032 { 4033 return buf != NULL && (buf->b_p_bt[0] == 'n' 4034 || buf->terminal 4035 || buf->b_p_bt[0] == 'p'); 4036 } 4037 4038 bool bt_dontwrite_msg(const buf_T *const buf) 4039 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 4040 { 4041 if (bt_dontwrite(buf)) { 4042 emsg(_("E382: Cannot write, 'buftype' option is set")); 4043 return true; 4044 } 4045 return false; 4046 } 4047 4048 /// @return true if the buffer should be hidden, according to 'hidden', ":hide" 4049 /// and 'bufhidden'. 4050 bool buf_hide(const buf_T *const buf) 4051 FUNC_ATTR_PURE 4052 { 4053 // 'bufhidden' overrules 'hidden' and ":hide", check it first 4054 switch (buf->b_p_bh[0]) { 4055 case 'u': // "unload" 4056 case 'w': // "wipe" 4057 case 'd': 4058 return false; // "delete" 4059 case 'h': 4060 return true; // "hide" 4061 } 4062 return p_hid || (cmdmod.cmod_flags & CMOD_HIDE); 4063 } 4064 4065 /// @return special buffer name or 4066 /// NULL when the buffer has a normal file name. 4067 char *buf_spname(buf_T *buf) 4068 { 4069 if (bt_quickfix(buf)) { 4070 // Differentiate between the quickfix and location list buffers using 4071 // the buffer number stored in the global quickfix stack. 4072 if (buf->b_fnum == qf_stack_get_bufnr()) { 4073 return _(msg_qflist); 4074 } 4075 return _(msg_loclist); 4076 } 4077 // There is no _file_ when 'buftype' is "nofile", b_sfname 4078 // contains the name as specified by the user. 4079 if (bt_nofilename(buf)) { 4080 if (buf->b_fname != NULL) { 4081 return buf->b_fname; 4082 } 4083 if (buf == cmdwin_buf) { 4084 return _("[Command Line]"); 4085 } 4086 if (bt_prompt(buf)) { 4087 return _("[Prompt]"); 4088 } 4089 return _("[Scratch]"); 4090 } 4091 if (buf->b_fname == NULL) { 4092 return buf_get_fname(buf); 4093 } 4094 return NULL; 4095 } 4096 4097 /// Get "buf->b_fname", use "[No Name]" if it is NULL. 4098 char *buf_get_fname(const buf_T *buf) 4099 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 4100 { 4101 if (buf->b_fname == NULL) { 4102 return _("[No Name]"); 4103 } 4104 return buf->b_fname; 4105 } 4106 4107 /// Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. 4108 void set_buflisted(int on) 4109 { 4110 if (on == curbuf->b_p_bl) { 4111 return; 4112 } 4113 4114 curbuf->b_p_bl = on; 4115 if (on) { 4116 apply_autocmds(EVENT_BUFADD, NULL, NULL, false, curbuf); 4117 } else { 4118 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, false, curbuf); 4119 } 4120 } 4121 4122 /// Read the file for "buf" again and check if the contents changed. 4123 /// Return true if it changed or this could not be checked. 4124 /// 4125 /// @param buf buffer to check 4126 /// 4127 /// @return true if the buffer's contents have changed 4128 bool buf_contents_changed(buf_T *buf) 4129 FUNC_ATTR_NONNULL_ALL 4130 { 4131 bool differ = true; 4132 4133 // Allocate a buffer without putting it in the buffer list. 4134 buf_T *newbuf = buflist_new(NULL, NULL, 1, BLN_DUMMY); 4135 if (newbuf == NULL) { 4136 return true; 4137 } 4138 4139 // Force the 'fileencoding' and 'fileformat' to be equal. 4140 exarg_T ea; 4141 prep_exarg(&ea, buf); 4142 4143 // Set curwin/curbuf to buf and save a few things. 4144 aco_save_T aco; 4145 aucmd_prepbuf(&aco, newbuf); 4146 4147 // We don't want to trigger autocommands now, they may have nasty 4148 // side-effects like wiping buffers 4149 block_autocmds(); 4150 4151 if (ml_open(curbuf) == OK 4152 && readfile(buf->b_ffname, buf->b_fname, 4153 0, 0, (linenr_T)MAXLNUM, 4154 &ea, READ_NEW | READ_DUMMY, false) == OK) { 4155 // compare the two files line by line 4156 if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) { 4157 differ = false; 4158 for (linenr_T lnum = 1; lnum <= curbuf->b_ml.ml_line_count; lnum++) { 4159 if (strcmp(ml_get_buf(buf, lnum), ml_get(lnum)) != 0) { 4160 differ = true; 4161 break; 4162 } 4163 } 4164 } 4165 } 4166 xfree(ea.cmd); 4167 4168 // restore curwin/curbuf and a few other things 4169 aucmd_restbuf(&aco); 4170 4171 if (curbuf != newbuf) { // safety check 4172 wipe_buffer(newbuf, false); 4173 } 4174 4175 unblock_autocmds(); 4176 4177 return differ; 4178 } 4179 4180 /// Wipe out a (typically temporary) buffer. 4181 /// @param aucmd When true trigger autocommands. 4182 void wipe_buffer(buf_T *buf, bool aucmd) 4183 { 4184 if (!aucmd) { 4185 // Don't trigger BufDelete autocommands here. 4186 block_autocmds(); 4187 } 4188 close_buffer(NULL, buf, DOBUF_WIPE, false, true); 4189 if (!aucmd) { 4190 unblock_autocmds(); 4191 } 4192 } 4193 4194 /// Creates or switches to a scratch buffer. :h special-buffers 4195 /// Scratch buffer is: 4196 /// - buftype=nofile bufhidden=hide noswapfile 4197 /// - Always considered 'nomodified' 4198 /// 4199 /// @param bufnr Buffer to switch to, or 0 to create a new buffer. 4200 /// @param bufname Buffer name, or NULL. 4201 /// 4202 /// @see curbufIsChanged() 4203 /// 4204 /// @return FAIL for failure, OK otherwise 4205 int buf_open_scratch(handle_T bufnr, char *bufname) 4206 { 4207 if (do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL) { 4208 return FAIL; 4209 } 4210 if (bufname != NULL) { 4211 apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf); 4212 setfname(curbuf, bufname, NULL, true); 4213 apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf); 4214 } 4215 set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL); 4216 set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL); 4217 set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL); 4218 RESET_BINDING(curwin); 4219 return OK; 4220 } 4221 4222 bool buf_is_empty(buf_T *buf) 4223 { 4224 return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL; 4225 } 4226 4227 /// Increment b:changedtick value 4228 /// 4229 /// Also checks b: for consistency in case of debug build. 4230 /// 4231 /// @param[in,out] buf Buffer to increment value in. 4232 void buf_inc_changedtick(buf_T *const buf) 4233 FUNC_ATTR_NONNULL_ALL 4234 { 4235 buf_set_changedtick(buf, buf_get_changedtick(buf) + 1); 4236 } 4237 4238 /// Set b:changedtick, also checking b: for consistency in debug build 4239 /// 4240 /// @param[out] buf Buffer to set changedtick in. 4241 /// @param[in] changedtick New value. 4242 void buf_set_changedtick(buf_T *const buf, const varnumber_T changedtick) 4243 FUNC_ATTR_NONNULL_ALL 4244 { 4245 typval_T old_val = buf->changedtick_di.di_tv; 4246 4247 #ifndef NDEBUG 4248 dictitem_T *const changedtick_di = tv_dict_find(buf->b_vars, S_LEN("changedtick")); 4249 assert(changedtick_di != NULL); 4250 assert(changedtick_di->di_tv.v_type == VAR_NUMBER); 4251 assert(changedtick_di->di_tv.v_lock == VAR_FIXED); 4252 // For some reason formatc does not like the below. 4253 # ifndef UNIT_TESTING_LUA_PREPROCESSING 4254 assert(changedtick_di->di_flags == (DI_FLAGS_RO|DI_FLAGS_FIX)); 4255 # endif 4256 assert(changedtick_di == (dictitem_T *)&buf->changedtick_di); 4257 #endif 4258 buf->changedtick_di.di_tv.vval.v_number = changedtick; 4259 4260 if (tv_dict_is_watched(buf->b_vars)) { 4261 buf->b_locked++; 4262 tv_dict_watcher_notify(buf->b_vars, 4263 (char *)buf->changedtick_di.di_key, 4264 &buf->changedtick_di.di_tv, 4265 &old_val); 4266 buf->b_locked--; 4267 } 4268 } 4269 4270 /// Read the given buffer contents into a string. 4271 void read_buffer_into(buf_T *buf, linenr_T start, linenr_T end, StringBuilder *sb) 4272 FUNC_ATTR_NONNULL_ALL 4273 { 4274 assert(buf); 4275 assert(sb); 4276 4277 if (buf->b_ml.ml_flags & ML_EMPTY) { 4278 return; 4279 } 4280 4281 size_t written = 0; 4282 size_t len = 0; 4283 linenr_T lnum = start; 4284 char *lp = ml_get_buf(buf, lnum); 4285 size_t lplen = (size_t)ml_get_buf_len(buf, lnum); 4286 4287 while (true) { 4288 if (lplen == 0) { 4289 len = 0; 4290 } else if (lp[written] == NL) { 4291 // NL -> NUL translation 4292 len = 1; 4293 kv_push(*sb, NUL); 4294 } else { 4295 char *s = vim_strchr(lp + written, NL); 4296 len = s == NULL ? lplen - written : (size_t)(s - (lp + written)); 4297 kv_concat_len(*sb, lp + written, len); 4298 } 4299 4300 if (len == lplen - written) { 4301 // Finished a line, add a NL, unless this line should not have one. 4302 if (lnum != end 4303 || (!buf->b_p_bin && buf->b_p_fixeol) 4304 || (lnum != buf->b_no_eol_lnum 4305 && (lnum != buf->b_ml.ml_line_count || buf->b_p_eol))) { 4306 kv_push(*sb, NL); 4307 } 4308 lnum++; 4309 if (lnum > end) { 4310 break; 4311 } 4312 lp = ml_get_buf(buf, lnum); 4313 lplen = (size_t)ml_get_buf_len(buf, lnum); 4314 written = 0; 4315 } else if (len > 0) { 4316 written += len; 4317 } 4318 } 4319 }