1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * buffer.c: functions for dealing with the buffer structure 12 */ 13 14 /* 15 * The buffer list is a double linked list of all buffers. 16 * Each buffer can be in one of these states: 17 * never loaded: BF_NEVERLOADED is set, only the file name is valid 18 * not loaded: b_ml.ml_mfp == NULL, no memfile allocated 19 * hidden: b_nwindows == 0, loaded but not displayed in a window 20 * normal: loaded and displayed in a window 21 * 22 * Instead of storing file names all over the place, each file name is 23 * stored in the buffer list. It can be referenced by a number. 24 * 25 * The current implementation remembers all file names ever used. 26 */ 27 28 #include "vim.h" 29 30 static void enter_buffer(buf_T *buf); 31 static void buflist_getfpos(void); 32 static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case); 33 static char_u *fname_match(regmatch_T *rmp, char_u *name, int ignore_case); 34 #ifdef UNIX 35 static buf_T *buflist_findname_stat(char_u *ffname, stat_T *st); 36 static int otherfile_buf(buf_T *buf, char_u *ffname, stat_T *stp); 37 static int buf_same_ino(buf_T *buf, stat_T *stp); 38 #else 39 static int otherfile_buf(buf_T *buf, char_u *ffname); 40 #endif 41 #ifdef FEAT_TITLE 42 static int value_changed(char_u *str, char_u **last); 43 #endif 44 static int append_arg_number(win_T *wp, char_u *buf, int buflen, int add_file); 45 static void free_buffer(buf_T *); 46 static void free_buffer_stuff(buf_T *buf, int free_options); 47 static void clear_wininfo(buf_T *buf); 48 49 #ifdef UNIX 50 # define dev_T dev_t 51 #else 52 # define dev_T unsigned 53 #endif 54 55 #if defined(FEAT_QUICKFIX) 56 static char *msg_loclist = N_("[Location List]"); 57 static char *msg_qflist = N_("[Quickfix List]"); 58 #endif 59 static char *e_auabort = N_("E855: Autocommands caused command to abort"); 60 61 // Number of times free_buffer() was called. 62 static int buf_free_count = 0; 63 64 static int top_file_num = 1; // highest file number 65 static garray_T buf_reuse = GA_EMPTY; // file numbers to recycle 66 67 /* 68 * Return the highest possible buffer number. 69 */ 70 int 71 get_highest_fnum(void) 72 { 73 return top_file_num - 1; 74 } 75 76 /* 77 * Read data from buffer for retrying. 78 */ 79 static int 80 read_buffer( 81 int read_stdin, /* read file from stdin, otherwise fifo */ 82 exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */ 83 int flags) /* extra flags for readfile() */ 84 { 85 int retval = OK; 86 linenr_T line_count; 87 88 /* 89 * Read from the buffer which the text is already filled in and append at 90 * the end. This makes it possible to retry when 'fileformat' or 91 * 'fileencoding' was guessed wrong. 92 */ 93 line_count = curbuf->b_ml.ml_line_count; 94 retval = readfile( 95 read_stdin ? NULL : curbuf->b_ffname, 96 read_stdin ? NULL : curbuf->b_fname, 97 (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, 98 flags | READ_BUFFER); 99 if (retval == OK) 100 { 101 /* Delete the binary lines. */ 102 while (--line_count >= 0) 103 ml_delete((linenr_T)1, FALSE); 104 } 105 else 106 { 107 /* Delete the converted lines. */ 108 while (curbuf->b_ml.ml_line_count > line_count) 109 ml_delete(line_count, FALSE); 110 } 111 /* Put the cursor on the first line. */ 112 curwin->w_cursor.lnum = 1; 113 curwin->w_cursor.col = 0; 114 115 if (read_stdin) 116 { 117 /* Set or reset 'modified' before executing autocommands, so that 118 * it can be changed there. */ 119 if (!readonlymode && !BUFEMPTY()) 120 changed(); 121 else if (retval == OK) 122 unchanged(curbuf, FALSE, TRUE); 123 124 if (retval == OK) 125 { 126 #ifdef FEAT_EVAL 127 apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, 128 curbuf, &retval); 129 #else 130 apply_autocmds(EVENT_STDINREADPOST, NULL, NULL, FALSE, curbuf); 131 #endif 132 } 133 } 134 return retval; 135 } 136 137 /* 138 * Ensure buffer "buf" is loaded. Does not trigger the swap-exists action. 139 */ 140 void 141 buffer_ensure_loaded(buf_T *buf) 142 { 143 if (buf->b_ml.ml_mfp == NULL) 144 { 145 aco_save_T aco; 146 147 aucmd_prepbuf(&aco, buf); 148 swap_exists_action = SEA_NONE; 149 open_buffer(FALSE, NULL, 0); 150 aucmd_restbuf(&aco); 151 } 152 } 153 154 /* 155 * Open current buffer, that is: open the memfile and read the file into 156 * memory. 157 * Return FAIL for failure, OK otherwise. 158 */ 159 int 160 open_buffer( 161 int read_stdin, /* read file from stdin */ 162 exarg_T *eap, /* for forced 'ff' and 'fenc' or NULL */ 163 int flags) /* extra flags for readfile() */ 164 { 165 int retval = OK; 166 bufref_T old_curbuf; 167 #ifdef FEAT_SYN_HL 168 long old_tw = curbuf->b_p_tw; 169 #endif 170 int read_fifo = FALSE; 171 172 /* 173 * The 'readonly' flag is only set when BF_NEVERLOADED is being reset. 174 * When re-entering the same buffer, it should not change, because the 175 * user may have reset the flag by hand. 176 */ 177 if (readonlymode && curbuf->b_ffname != NULL 178 && (curbuf->b_flags & BF_NEVERLOADED)) 179 curbuf->b_p_ro = TRUE; 180 181 if (ml_open(curbuf) == FAIL) 182 { 183 /* 184 * There MUST be a memfile, otherwise we can't do anything 185 * If we can't create one for the current buffer, take another buffer 186 */ 187 close_buffer(NULL, curbuf, 0, FALSE); 188 FOR_ALL_BUFFERS(curbuf) 189 if (curbuf->b_ml.ml_mfp != NULL) 190 break; 191 /* 192 * If there is no memfile at all, exit. 193 * This is OK, since there are no changes to lose. 194 */ 195 if (curbuf == NULL) 196 { 197 emsg(_("E82: Cannot allocate any buffer, exiting...")); 198 199 // Don't try to do any saving, with "curbuf" NULL almost nothing 200 // will work. 201 v_dying = 2; 202 getout(2); 203 } 204 205 emsg(_("E83: Cannot allocate buffer, using other one...")); 206 enter_buffer(curbuf); 207 #ifdef FEAT_SYN_HL 208 if (old_tw != curbuf->b_p_tw) 209 check_colorcolumn(curwin); 210 #endif 211 return FAIL; 212 } 213 214 /* The autocommands in readfile() may change the buffer, but only AFTER 215 * reading the file. */ 216 set_bufref(&old_curbuf, curbuf); 217 modified_was_set = FALSE; 218 219 /* mark cursor position as being invalid */ 220 curwin->w_valid = 0; 221 222 if (curbuf->b_ffname != NULL 223 #ifdef FEAT_NETBEANS_INTG 224 && netbeansReadFile 225 #endif 226 ) 227 { 228 int old_msg_silent = msg_silent; 229 #ifdef UNIX 230 int save_bin = curbuf->b_p_bin; 231 int perm; 232 #endif 233 #ifdef FEAT_NETBEANS_INTG 234 int oldFire = netbeansFireChanges; 235 236 netbeansFireChanges = 0; 237 #endif 238 #ifdef UNIX 239 perm = mch_getperm(curbuf->b_ffname); 240 if (perm >= 0 && (S_ISFIFO(perm) 241 || S_ISSOCK(perm) 242 # ifdef OPEN_CHR_FILES 243 || (S_ISCHR(perm) && is_dev_fd_file(curbuf->b_ffname)) 244 # endif 245 )) 246 read_fifo = TRUE; 247 if (read_fifo) 248 curbuf->b_p_bin = TRUE; 249 #endif 250 if (shortmess(SHM_FILEINFO)) 251 msg_silent = 1; 252 retval = readfile(curbuf->b_ffname, curbuf->b_fname, 253 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap, 254 flags | READ_NEW | (read_fifo ? READ_FIFO : 0)); 255 #ifdef UNIX 256 if (read_fifo) 257 { 258 curbuf->b_p_bin = save_bin; 259 if (retval == OK) 260 retval = read_buffer(FALSE, eap, flags); 261 } 262 #endif 263 msg_silent = old_msg_silent; 264 #ifdef FEAT_NETBEANS_INTG 265 netbeansFireChanges = oldFire; 266 #endif 267 /* Help buffer is filtered. */ 268 if (bt_help(curbuf)) 269 fix_help_buffer(); 270 } 271 else if (read_stdin) 272 { 273 int save_bin = curbuf->b_p_bin; 274 275 /* 276 * First read the text in binary mode into the buffer. 277 * Then read from that same buffer and append at the end. This makes 278 * it possible to retry when 'fileformat' or 'fileencoding' was 279 * guessed wrong. 280 */ 281 curbuf->b_p_bin = TRUE; 282 retval = readfile(NULL, NULL, (linenr_T)0, 283 (linenr_T)0, (linenr_T)MAXLNUM, NULL, 284 flags | (READ_NEW + READ_STDIN)); 285 curbuf->b_p_bin = save_bin; 286 if (retval == OK) 287 retval = read_buffer(TRUE, eap, flags); 288 } 289 290 /* if first time loading this buffer, init b_chartab[] */ 291 if (curbuf->b_flags & BF_NEVERLOADED) 292 { 293 (void)buf_init_chartab(curbuf, FALSE); 294 #ifdef FEAT_CINDENT 295 parse_cino(curbuf); 296 #endif 297 } 298 299 /* 300 * Set/reset the Changed flag first, autocmds may change the buffer. 301 * Apply the automatic commands, before processing the modelines. 302 * So the modelines have priority over autocommands. 303 */ 304 /* When reading stdin, the buffer contents always needs writing, so set 305 * the changed flag. Unless in readonly mode: "ls | gview -". 306 * When interrupted and 'cpoptions' contains 'i' set changed flag. */ 307 if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) 308 || modified_was_set /* ":set modified" used in autocmd */ 309 #ifdef FEAT_EVAL 310 || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL) 311 #endif 312 ) 313 changed(); 314 else if (retval == OK && !read_stdin && !read_fifo) 315 unchanged(curbuf, FALSE, TRUE); 316 save_file_ff(curbuf); /* keep this fileformat */ 317 318 /* Set last_changedtick to avoid triggering a TextChanged autocommand right 319 * after it was added. */ 320 curbuf->b_last_changedtick = CHANGEDTICK(curbuf); 321 curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); 322 323 /* require "!" to overwrite the file, because it wasn't read completely */ 324 #ifdef FEAT_EVAL 325 if (aborting()) 326 #else 327 if (got_int) 328 #endif 329 curbuf->b_flags |= BF_READERR; 330 331 #ifdef FEAT_FOLDING 332 /* Need to update automatic folding. Do this before the autocommands, 333 * they may use the fold info. */ 334 foldUpdateAll(curwin); 335 #endif 336 337 /* need to set w_topline, unless some autocommand already did that. */ 338 if (!(curwin->w_valid & VALID_TOPLINE)) 339 { 340 curwin->w_topline = 1; 341 #ifdef FEAT_DIFF 342 curwin->w_topfill = 0; 343 #endif 344 } 345 #ifdef FEAT_EVAL 346 apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf, &retval); 347 #else 348 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); 349 #endif 350 351 if (retval == OK) 352 { 353 /* 354 * The autocommands may have changed the current buffer. Apply the 355 * modelines to the correct buffer, if it still exists and is loaded. 356 */ 357 if (bufref_valid(&old_curbuf) && old_curbuf.br_buf->b_ml.ml_mfp != NULL) 358 { 359 aco_save_T aco; 360 361 /* Go to the buffer that was opened. */ 362 aucmd_prepbuf(&aco, old_curbuf.br_buf); 363 do_modelines(0); 364 curbuf->b_flags &= ~(BF_CHECK_RO | BF_NEVERLOADED); 365 366 #ifdef FEAT_EVAL 367 apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf, 368 &retval); 369 #else 370 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); 371 #endif 372 373 /* restore curwin/curbuf and a few other things */ 374 aucmd_restbuf(&aco); 375 } 376 } 377 378 return retval; 379 } 380 381 /* 382 * Store "buf" in "bufref" and set the free count. 383 */ 384 void 385 set_bufref(bufref_T *bufref, buf_T *buf) 386 { 387 bufref->br_buf = buf; 388 bufref->br_fnum = buf == NULL ? 0 : buf->b_fnum; 389 bufref->br_buf_free_count = buf_free_count; 390 } 391 392 /* 393 * Return TRUE if "bufref->br_buf" points to the same buffer as when 394 * set_bufref() was called and it is a valid buffer. 395 * Only goes through the buffer list if buf_free_count changed. 396 * Also checks if b_fnum is still the same, a :bwipe followed by :new might get 397 * the same allocated memory, but it's a different buffer. 398 */ 399 int 400 bufref_valid(bufref_T *bufref) 401 { 402 return bufref->br_buf_free_count == buf_free_count 403 ? TRUE : buf_valid(bufref->br_buf) 404 && bufref->br_fnum == bufref->br_buf->b_fnum; 405 } 406 407 /* 408 * Return TRUE if "buf" points to a valid buffer (in the buffer list). 409 * This can be slow if there are many buffers, prefer using bufref_valid(). 410 */ 411 int 412 buf_valid(buf_T *buf) 413 { 414 buf_T *bp; 415 416 /* Assume that we more often have a recent buffer, start with the last 417 * one. */ 418 for (bp = lastbuf; bp != NULL; bp = bp->b_prev) 419 if (bp == buf) 420 return TRUE; 421 return FALSE; 422 } 423 424 /* 425 * A hash table used to quickly lookup a buffer by its number. 426 */ 427 static hashtab_T buf_hashtab; 428 429 static void 430 buf_hashtab_add(buf_T *buf) 431 { 432 sprintf((char *)buf->b_key, "%x", buf->b_fnum); 433 if (hash_add(&buf_hashtab, buf->b_key) == FAIL) 434 emsg(_("E931: Buffer cannot be registered")); 435 } 436 437 static void 438 buf_hashtab_remove(buf_T *buf) 439 { 440 hashitem_T *hi = hash_find(&buf_hashtab, buf->b_key); 441 442 if (!HASHITEM_EMPTY(hi)) 443 hash_remove(&buf_hashtab, hi); 444 } 445 446 /* 447 * Return TRUE when buffer "buf" can be unloaded. 448 * Give an error message and return FALSE when the buffer is locked or the 449 * screen is being redrawn and the buffer is in a window. 450 */ 451 static int 452 can_unload_buffer(buf_T *buf) 453 { 454 int can_unload = !buf->b_locked; 455 456 if (can_unload && updating_screen) 457 { 458 win_T *wp; 459 460 FOR_ALL_WINDOWS(wp) 461 if (wp->w_buffer == buf) 462 { 463 can_unload = FALSE; 464 break; 465 } 466 } 467 if (!can_unload) 468 semsg(_("E937: Attempt to delete a buffer that is in use: %s"), 469 buf->b_fname); 470 return can_unload; 471 } 472 473 /* 474 * Close the link to a buffer. 475 * "action" is used when there is no longer a window for the buffer. 476 * It can be: 477 * 0 buffer becomes hidden 478 * DOBUF_UNLOAD buffer is unloaded 479 * DOBUF_DELETE buffer is unloaded and removed from buffer list 480 * DOBUF_WIPE buffer is unloaded and really deleted 481 * DOBUF_WIPE_REUSE idem, and add to buf_reuse list 482 * When doing all but the first one on the current buffer, the caller should 483 * get a new buffer very soon! 484 * 485 * The 'bufhidden' option can force freeing and deleting. 486 * 487 * When "abort_if_last" is TRUE then do not close the buffer if autocommands 488 * cause there to be only one window with this buffer. e.g. when ":quit" is 489 * supposed to close the window but autocommands close all other windows. 490 */ 491 void 492 close_buffer( 493 win_T *win, /* if not NULL, set b_last_cursor */ 494 buf_T *buf, 495 int action, 496 int abort_if_last) 497 { 498 int is_curbuf; 499 int nwindows; 500 bufref_T bufref; 501 int is_curwin = (curwin != NULL && curwin->w_buffer == buf); 502 win_T *the_curwin = curwin; 503 tabpage_T *the_curtab = curtab; 504 int unload_buf = (action != 0); 505 int wipe_buf = (action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); 506 int del_buf = (action == DOBUF_DEL || wipe_buf); 507 508 /* 509 * Force unloading or deleting when 'bufhidden' says so. 510 * The caller must take care of NOT deleting/freeing when 'bufhidden' is 511 * "hide" (otherwise we could never free or delete a buffer). 512 */ 513 if (buf->b_p_bh[0] == 'd') /* 'bufhidden' == "delete" */ 514 { 515 del_buf = TRUE; 516 unload_buf = TRUE; 517 } 518 else if (buf->b_p_bh[0] == 'w') /* 'bufhidden' == "wipe" */ 519 { 520 del_buf = TRUE; 521 unload_buf = TRUE; 522 wipe_buf = TRUE; 523 } 524 else if (buf->b_p_bh[0] == 'u') /* 'bufhidden' == "unload" */ 525 unload_buf = TRUE; 526 527 #ifdef FEAT_TERMINAL 528 if (bt_terminal(buf) && (buf->b_nwindows == 1 || del_buf)) 529 { 530 if (term_job_running(buf->b_term)) 531 { 532 if (wipe_buf || unload_buf) 533 { 534 if (!can_unload_buffer(buf)) 535 return; 536 537 /* Wiping out or unloading a terminal buffer kills the job. */ 538 free_terminal(buf); 539 } 540 else 541 { 542 /* The job keeps running, hide the buffer. */ 543 del_buf = FALSE; 544 unload_buf = FALSE; 545 } 546 } 547 else 548 { 549 /* A terminal buffer is wiped out if the job has finished. */ 550 del_buf = TRUE; 551 unload_buf = TRUE; 552 wipe_buf = TRUE; 553 } 554 } 555 #endif 556 557 /* Disallow deleting the buffer when it is locked (already being closed or 558 * halfway a command that relies on it). Unloading is allowed. */ 559 if ((del_buf || wipe_buf) && !can_unload_buffer(buf)) 560 return; 561 562 /* check no autocommands closed the window */ 563 if (win != NULL && win_valid_any_tab(win)) 564 { 565 /* Set b_last_cursor when closing the last window for the buffer. 566 * Remember the last cursor position and window options of the buffer. 567 * This used to be only for the current window, but then options like 568 * 'foldmethod' may be lost with a ":only" command. */ 569 if (buf->b_nwindows == 1) 570 set_last_cursor(win); 571 buflist_setfpos(buf, win, 572 win->w_cursor.lnum == 1 ? 0 : win->w_cursor.lnum, 573 win->w_cursor.col, TRUE); 574 } 575 576 set_bufref(&bufref, buf); 577 578 /* When the buffer is no longer in a window, trigger BufWinLeave */ 579 if (buf->b_nwindows == 1) 580 { 581 ++buf->b_locked; 582 if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, 583 FALSE, buf) 584 && !bufref_valid(&bufref)) 585 { 586 /* Autocommands deleted the buffer. */ 587 aucmd_abort: 588 emsg(_(e_auabort)); 589 return; 590 } 591 --buf->b_locked; 592 if (abort_if_last && one_window()) 593 /* Autocommands made this the only window. */ 594 goto aucmd_abort; 595 596 /* When the buffer becomes hidden, but is not unloaded, trigger 597 * BufHidden */ 598 if (!unload_buf) 599 { 600 ++buf->b_locked; 601 if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, 602 FALSE, buf) 603 && !bufref_valid(&bufref)) 604 /* Autocommands deleted the buffer. */ 605 goto aucmd_abort; 606 --buf->b_locked; 607 if (abort_if_last && one_window()) 608 /* Autocommands made this the only window. */ 609 goto aucmd_abort; 610 } 611 #ifdef FEAT_EVAL 612 if (aborting()) /* autocmds may abort script processing */ 613 return; 614 #endif 615 } 616 617 /* If the buffer was in curwin and the window has changed, go back to that 618 * window, if it still exists. This avoids that ":edit x" triggering a 619 * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */ 620 if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) 621 { 622 block_autocmds(); 623 goto_tabpage_win(the_curtab, the_curwin); 624 unblock_autocmds(); 625 } 626 627 nwindows = buf->b_nwindows; 628 629 /* decrease the link count from windows (unless not in any window) */ 630 if (buf->b_nwindows > 0) 631 --buf->b_nwindows; 632 633 #ifdef FEAT_DIFF 634 if (diffopt_hiddenoff() && !unload_buf && buf->b_nwindows == 0) 635 diff_buf_delete(buf); /* Clear 'diff' for hidden buffer. */ 636 #endif 637 638 /* Return when a window is displaying the buffer or when it's not 639 * unloaded. */ 640 if (buf->b_nwindows > 0 || !unload_buf) 641 return; 642 643 /* Always remove the buffer when there is no file name. */ 644 if (buf->b_ffname == NULL) 645 del_buf = TRUE; 646 647 /* When closing the current buffer stop Visual mode before freeing 648 * anything. */ 649 if (buf == curbuf && VIsual_active 650 #if defined(EXITFREE) 651 && !entered_free_all_mem 652 #endif 653 ) 654 end_visual_mode(); 655 656 /* 657 * Free all things allocated for this buffer. 658 * Also calls the "BufDelete" autocommands when del_buf is TRUE. 659 */ 660 /* Remember if we are closing the current buffer. Restore the number of 661 * windows, so that autocommands in buf_freeall() don't get confused. */ 662 is_curbuf = (buf == curbuf); 663 buf->b_nwindows = nwindows; 664 665 buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); 666 667 /* Autocommands may have deleted the buffer. */ 668 if (!bufref_valid(&bufref)) 669 return; 670 #ifdef FEAT_EVAL 671 if (aborting()) /* autocmds may abort script processing */ 672 return; 673 #endif 674 675 /* 676 * It's possible that autocommands change curbuf to the one being deleted. 677 * This might cause the previous curbuf to be deleted unexpectedly. But 678 * in some cases it's OK to delete the curbuf, because a new one is 679 * obtained anyway. Therefore only return if curbuf changed to the 680 * deleted buffer. 681 */ 682 if (buf == curbuf && !is_curbuf) 683 return; 684 685 if (win_valid_any_tab(win) && win->w_buffer == buf) 686 win->w_buffer = NULL; /* make sure we don't use the buffer now */ 687 688 /* Autocommands may have opened or closed windows for this buffer. 689 * Decrement the count for the close we do here. */ 690 if (buf->b_nwindows > 0) 691 --buf->b_nwindows; 692 693 /* 694 * Remove the buffer from the list. 695 */ 696 if (wipe_buf) 697 { 698 if (action == DOBUF_WIPE_REUSE) 699 { 700 // we can re-use this buffer number, store it 701 if (buf_reuse.ga_itemsize == 0) 702 ga_init2(&buf_reuse, sizeof(int), 50); 703 if (ga_grow(&buf_reuse, 1) == OK) 704 ((int *)buf_reuse.ga_data)[buf_reuse.ga_len++] = buf->b_fnum; 705 } 706 if (buf->b_sfname != buf->b_ffname) 707 VIM_CLEAR(buf->b_sfname); 708 else 709 buf->b_sfname = NULL; 710 VIM_CLEAR(buf->b_ffname); 711 if (buf->b_prev == NULL) 712 firstbuf = buf->b_next; 713 else 714 buf->b_prev->b_next = buf->b_next; 715 if (buf->b_next == NULL) 716 lastbuf = buf->b_prev; 717 else 718 buf->b_next->b_prev = buf->b_prev; 719 free_buffer(buf); 720 } 721 else 722 { 723 if (del_buf) 724 { 725 /* Free all internal variables and reset option values, to make 726 * ":bdel" compatible with Vim 5.7. */ 727 free_buffer_stuff(buf, TRUE); 728 729 /* Make it look like a new buffer. */ 730 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; 731 732 /* Init the options when loaded again. */ 733 buf->b_p_initialized = FALSE; 734 } 735 buf_clear_file(buf); 736 if (del_buf) 737 buf->b_p_bl = FALSE; 738 } 739 } 740 741 /* 742 * Make buffer not contain a file. 743 */ 744 void 745 buf_clear_file(buf_T *buf) 746 { 747 buf->b_ml.ml_line_count = 1; 748 unchanged(buf, TRUE, TRUE); 749 buf->b_shortname = FALSE; 750 buf->b_p_eol = TRUE; 751 buf->b_start_eol = TRUE; 752 buf->b_p_bomb = FALSE; 753 buf->b_start_bomb = FALSE; 754 buf->b_ml.ml_mfp = NULL; 755 buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */ 756 #ifdef FEAT_NETBEANS_INTG 757 netbeans_deleted_all_lines(buf); 758 #endif 759 } 760 761 /* 762 * buf_freeall() - free all things allocated for a buffer that are related to 763 * the file. Careful: get here with "curwin" NULL when exiting. 764 * flags: 765 * BFA_DEL buffer is going to be deleted 766 * BFA_WIPE buffer is going to be wiped out 767 * BFA_KEEP_UNDO do not free undo information 768 */ 769 void 770 buf_freeall(buf_T *buf, int flags) 771 { 772 int is_curbuf = (buf == curbuf); 773 bufref_T bufref; 774 int is_curwin = (curwin != NULL && curwin->w_buffer == buf); 775 win_T *the_curwin = curwin; 776 tabpage_T *the_curtab = curtab; 777 778 /* Make sure the buffer isn't closed by autocommands. */ 779 ++buf->b_locked; 780 set_bufref(&bufref, buf); 781 if (buf->b_ml.ml_mfp != NULL) 782 { 783 if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, 784 FALSE, buf) 785 && !bufref_valid(&bufref)) 786 /* autocommands deleted the buffer */ 787 return; 788 } 789 if ((flags & BFA_DEL) && buf->b_p_bl) 790 { 791 if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname, 792 FALSE, buf) 793 && !bufref_valid(&bufref)) 794 /* autocommands deleted the buffer */ 795 return; 796 } 797 if (flags & BFA_WIPE) 798 { 799 if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname, 800 FALSE, buf) 801 && !bufref_valid(&bufref)) 802 /* autocommands deleted the buffer */ 803 return; 804 } 805 --buf->b_locked; 806 807 /* If the buffer was in curwin and the window has changed, go back to that 808 * window, if it still exists. This avoids that ":edit x" triggering a 809 * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */ 810 if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) 811 { 812 block_autocmds(); 813 goto_tabpage_win(the_curtab, the_curwin); 814 unblock_autocmds(); 815 } 816 817 #ifdef FEAT_EVAL 818 if (aborting()) /* autocmds may abort script processing */ 819 return; 820 #endif 821 822 /* 823 * It's possible that autocommands change curbuf to the one being deleted. 824 * This might cause curbuf to be deleted unexpectedly. But in some cases 825 * it's OK to delete the curbuf, because a new one is obtained anyway. 826 * Therefore only return if curbuf changed to the deleted buffer. 827 */ 828 if (buf == curbuf && !is_curbuf) 829 return; 830 #ifdef FEAT_DIFF 831 diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */ 832 #endif 833 #ifdef FEAT_SYN_HL 834 /* Remove any ownsyntax, unless exiting. */ 835 if (curwin != NULL && curwin->w_buffer == buf) 836 reset_synblock(curwin); 837 #endif 838 839 #ifdef FEAT_FOLDING 840 /* No folds in an empty buffer. */ 841 { 842 win_T *win; 843 tabpage_T *tp; 844 845 FOR_ALL_TAB_WINDOWS(tp, win) 846 if (win->w_buffer == buf) 847 clearFolding(win); 848 } 849 #endif 850 851 #ifdef FEAT_TCL 852 tcl_buffer_free(buf); 853 #endif 854 ml_close(buf, TRUE); /* close and delete the memline/memfile */ 855 buf->b_ml.ml_line_count = 0; /* no lines in buffer */ 856 if ((flags & BFA_KEEP_UNDO) == 0) 857 { 858 u_blockfree(buf); /* free the memory allocated for undo */ 859 u_clearall(buf); /* reset all undo information */ 860 } 861 #ifdef FEAT_SYN_HL 862 syntax_clear(&buf->b_s); /* reset syntax info */ 863 #endif 864 #ifdef FEAT_TEXT_PROP 865 clear_buf_prop_types(buf); 866 #endif 867 buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */ 868 } 869 870 /* 871 * Free a buffer structure and the things it contains related to the buffer 872 * itself (not the file, that must have been done already). 873 */ 874 static void 875 free_buffer(buf_T *buf) 876 { 877 ++buf_free_count; 878 free_buffer_stuff(buf, TRUE); 879 #ifdef FEAT_EVAL 880 /* b:changedtick uses an item in buf_T, remove it now */ 881 dictitem_remove(buf->b_vars, (dictitem_T *)&buf->b_ct_di); 882 unref_var_dict(buf->b_vars); 883 #endif 884 #ifdef FEAT_LUA 885 lua_buffer_free(buf); 886 #endif 887 #ifdef FEAT_MZSCHEME 888 mzscheme_buffer_free(buf); 889 #endif 890 #ifdef FEAT_PERL 891 perl_buf_free(buf); 892 #endif 893 #ifdef FEAT_PYTHON 894 python_buffer_free(buf); 895 #endif 896 #ifdef FEAT_PYTHON3 897 python3_buffer_free(buf); 898 #endif 899 #ifdef FEAT_RUBY 900 ruby_buffer_free(buf); 901 #endif 902 #ifdef FEAT_JOB_CHANNEL 903 channel_buffer_free(buf); 904 #endif 905 #ifdef FEAT_TERMINAL 906 free_terminal(buf); 907 #endif 908 #ifdef FEAT_JOB_CHANNEL 909 vim_free(buf->b_prompt_text); 910 free_callback(&buf->b_prompt_callback); 911 #endif 912 913 buf_hashtab_remove(buf); 914 915 aubuflocal_remove(buf); 916 917 if (autocmd_busy) 918 { 919 /* Do not free the buffer structure while autocommands are executing, 920 * it's still needed. Free it when autocmd_busy is reset. */ 921 buf->b_next = au_pending_free_buf; 922 au_pending_free_buf = buf; 923 } 924 else 925 vim_free(buf); 926 } 927 928 /* 929 * Initializes b:changedtick. 930 */ 931 static void 932 init_changedtick(buf_T *buf) 933 { 934 dictitem_T *di = (dictitem_T *)&buf->b_ct_di; 935 936 di->di_flags = DI_FLAGS_FIX | DI_FLAGS_RO; 937 di->di_tv.v_type = VAR_NUMBER; 938 di->di_tv.v_lock = VAR_FIXED; 939 di->di_tv.vval.v_number = 0; 940 941 #ifdef FEAT_EVAL 942 STRCPY(buf->b_ct_di.di_key, "changedtick"); 943 (void)dict_add(buf->b_vars, di); 944 #endif 945 } 946 947 /* 948 * Free stuff in the buffer for ":bdel" and when wiping out the buffer. 949 */ 950 static void 951 free_buffer_stuff( 952 buf_T *buf, 953 int free_options) /* free options as well */ 954 { 955 if (free_options) 956 { 957 clear_wininfo(buf); /* including window-local options */ 958 free_buf_options(buf, TRUE); 959 #ifdef FEAT_SPELL 960 ga_clear(&buf->b_s.b_langp); 961 #endif 962 } 963 #ifdef FEAT_EVAL 964 { 965 varnumber_T tick = CHANGEDTICK(buf); 966 967 vars_clear(&buf->b_vars->dv_hashtab); /* free all buffer variables */ 968 hash_init(&buf->b_vars->dv_hashtab); 969 init_changedtick(buf); 970 CHANGEDTICK(buf) = tick; 971 } 972 #endif 973 uc_clear(&buf->b_ucmds); // clear local user commands 974 #ifdef FEAT_SIGNS 975 buf_delete_signs(buf, (char_u *)"*"); // delete any signs 976 #endif 977 #ifdef FEAT_NETBEANS_INTG 978 netbeans_file_killed(buf); 979 #endif 980 map_clear_int(buf, MAP_ALL_MODES, TRUE, FALSE); /* clear local mappings */ 981 map_clear_int(buf, MAP_ALL_MODES, TRUE, TRUE); /* clear local abbrevs */ 982 VIM_CLEAR(buf->b_start_fenc); 983 } 984 985 /* 986 * Free the b_wininfo list for buffer "buf". 987 */ 988 static void 989 clear_wininfo(buf_T *buf) 990 { 991 wininfo_T *wip; 992 993 while (buf->b_wininfo != NULL) 994 { 995 wip = buf->b_wininfo; 996 buf->b_wininfo = wip->wi_next; 997 if (wip->wi_optset) 998 { 999 clear_winopt(&wip->wi_opt); 1000 #ifdef FEAT_FOLDING 1001 deleteFoldRecurse(&wip->wi_folds); 1002 #endif 1003 } 1004 vim_free(wip); 1005 } 1006 } 1007 1008 /* 1009 * Go to another buffer. Handles the result of the ATTENTION dialog. 1010 */ 1011 void 1012 goto_buffer( 1013 exarg_T *eap, 1014 int start, 1015 int dir, 1016 int count) 1017 { 1018 bufref_T old_curbuf; 1019 1020 set_bufref(&old_curbuf, curbuf); 1021 1022 swap_exists_action = SEA_DIALOG; 1023 (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, 1024 start, dir, count, eap->forceit); 1025 if (swap_exists_action == SEA_QUIT && *eap->cmd == 's') 1026 { 1027 #if defined(FEAT_EVAL) 1028 cleanup_T cs; 1029 1030 /* Reset the error/interrupt/exception state here so that 1031 * aborting() returns FALSE when closing a window. */ 1032 enter_cleanup(&cs); 1033 #endif 1034 1035 /* Quitting means closing the split window, nothing else. */ 1036 win_close(curwin, TRUE); 1037 swap_exists_action = SEA_NONE; 1038 swap_exists_did_quit = TRUE; 1039 1040 #if defined(FEAT_EVAL) 1041 /* Restore the error/interrupt/exception state if not discarded by a 1042 * new aborting error, interrupt, or uncaught exception. */ 1043 leave_cleanup(&cs); 1044 #endif 1045 } 1046 else 1047 handle_swap_exists(&old_curbuf); 1048 } 1049 1050 /* 1051 * Handle the situation of swap_exists_action being set. 1052 * It is allowed for "old_curbuf" to be NULL or invalid. 1053 */ 1054 void 1055 handle_swap_exists(bufref_T *old_curbuf) 1056 { 1057 #if defined(FEAT_EVAL) 1058 cleanup_T cs; 1059 #endif 1060 #ifdef FEAT_SYN_HL 1061 long old_tw = curbuf->b_p_tw; 1062 #endif 1063 buf_T *buf; 1064 1065 if (swap_exists_action == SEA_QUIT) 1066 { 1067 #if defined(FEAT_EVAL) 1068 /* Reset the error/interrupt/exception state here so that 1069 * aborting() returns FALSE when closing a buffer. */ 1070 enter_cleanup(&cs); 1071 #endif 1072 1073 /* User selected Quit at ATTENTION prompt. Go back to previous 1074 * buffer. If that buffer is gone or the same as the current one, 1075 * open a new, empty buffer. */ 1076 swap_exists_action = SEA_NONE; /* don't want it again */ 1077 swap_exists_did_quit = TRUE; 1078 close_buffer(curwin, curbuf, DOBUF_UNLOAD, FALSE); 1079 if (old_curbuf == NULL || !bufref_valid(old_curbuf) 1080 || old_curbuf->br_buf == curbuf) 1081 buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED); 1082 else 1083 buf = old_curbuf->br_buf; 1084 if (buf != NULL) 1085 { 1086 int old_msg_silent = msg_silent; 1087 1088 if (shortmess(SHM_FILEINFO)) 1089 msg_silent = 1; // prevent fileinfo message 1090 enter_buffer(buf); 1091 // restore msg_silent, so that the command line will be shown 1092 msg_silent = old_msg_silent; 1093 1094 #ifdef FEAT_SYN_HL 1095 if (old_tw != curbuf->b_p_tw) 1096 check_colorcolumn(curwin); 1097 #endif 1098 } 1099 /* If "old_curbuf" is NULL we are in big trouble here... */ 1100 1101 #if defined(FEAT_EVAL) 1102 /* Restore the error/interrupt/exception state if not discarded by a 1103 * new aborting error, interrupt, or uncaught exception. */ 1104 leave_cleanup(&cs); 1105 #endif 1106 } 1107 else if (swap_exists_action == SEA_RECOVER) 1108 { 1109 #if defined(FEAT_EVAL) 1110 /* Reset the error/interrupt/exception state here so that 1111 * aborting() returns FALSE when closing a buffer. */ 1112 enter_cleanup(&cs); 1113 #endif 1114 1115 /* User selected Recover at ATTENTION prompt. */ 1116 msg_scroll = TRUE; 1117 ml_recover(FALSE); 1118 msg_puts("\n"); /* don't overwrite the last message */ 1119 cmdline_row = msg_row; 1120 do_modelines(0); 1121 1122 #if defined(FEAT_EVAL) 1123 /* Restore the error/interrupt/exception state if not discarded by a 1124 * new aborting error, interrupt, or uncaught exception. */ 1125 leave_cleanup(&cs); 1126 #endif 1127 } 1128 swap_exists_action = SEA_NONE; 1129 } 1130 1131 /* 1132 * do_bufdel() - delete or unload buffer(s) 1133 * 1134 * addr_count == 0: ":bdel" - delete current buffer 1135 * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete 1136 * buffer "end_bnr", then any other arguments. 1137 * addr_count == 2: ":N,N bdel" - delete buffers in range 1138 * 1139 * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or 1140 * DOBUF_DEL (":bdel") 1141 * 1142 * Returns error message or NULL 1143 */ 1144 char * 1145 do_bufdel( 1146 int command, 1147 char_u *arg, /* pointer to extra arguments */ 1148 int addr_count, 1149 int start_bnr, /* first buffer number in a range */ 1150 int end_bnr, /* buffer nr or last buffer nr in a range */ 1151 int forceit) 1152 { 1153 int do_current = 0; /* delete current buffer? */ 1154 int deleted = 0; /* number of buffers deleted */ 1155 char *errormsg = NULL; /* return value */ 1156 int bnr; /* buffer number */ 1157 char_u *p; 1158 1159 if (addr_count == 0) 1160 { 1161 (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); 1162 } 1163 else 1164 { 1165 if (addr_count == 2) 1166 { 1167 if (*arg) /* both range and argument is not allowed */ 1168 return _(e_trailing); 1169 bnr = start_bnr; 1170 } 1171 else /* addr_count == 1 */ 1172 bnr = end_bnr; 1173 1174 for ( ;!got_int; ui_breakcheck()) 1175 { 1176 /* 1177 * delete the current buffer last, otherwise when the 1178 * current buffer is deleted, the next buffer becomes 1179 * the current one and will be loaded, which may then 1180 * also be deleted, etc. 1181 */ 1182 if (bnr == curbuf->b_fnum) 1183 do_current = bnr; 1184 else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr, 1185 forceit) == OK) 1186 ++deleted; 1187 1188 /* 1189 * find next buffer number to delete/unload 1190 */ 1191 if (addr_count == 2) 1192 { 1193 if (++bnr > end_bnr) 1194 break; 1195 } 1196 else /* addr_count == 1 */ 1197 { 1198 arg = skipwhite(arg); 1199 if (*arg == NUL) 1200 break; 1201 if (!VIM_ISDIGIT(*arg)) 1202 { 1203 p = skiptowhite_esc(arg); 1204 bnr = buflist_findpat(arg, p, 1205 command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE, 1206 FALSE, FALSE); 1207 if (bnr < 0) /* failed */ 1208 break; 1209 arg = p; 1210 } 1211 else 1212 bnr = getdigits(&arg); 1213 } 1214 } 1215 if (!got_int && do_current && do_buffer(command, DOBUF_FIRST, 1216 FORWARD, do_current, forceit) == OK) 1217 ++deleted; 1218 1219 if (deleted == 0) 1220 { 1221 if (command == DOBUF_UNLOAD) 1222 STRCPY(IObuff, _("E515: No buffers were unloaded")); 1223 else if (command == DOBUF_DEL) 1224 STRCPY(IObuff, _("E516: No buffers were deleted")); 1225 else 1226 STRCPY(IObuff, _("E517: No buffers were wiped out")); 1227 errormsg = (char *)IObuff; 1228 } 1229 else if (deleted >= p_report) 1230 { 1231 if (command == DOBUF_UNLOAD) 1232 smsg(NGETTEXT("%d buffer unloaded", 1233 "%d buffers unloaded", deleted), deleted); 1234 else if (command == DOBUF_DEL) 1235 smsg(NGETTEXT("%d buffer deleted", 1236 "%d buffers deleted", deleted), deleted); 1237 else 1238 smsg(NGETTEXT("%d buffer wiped out", 1239 "%d buffers wiped out", deleted), deleted); 1240 } 1241 } 1242 1243 1244 return errormsg; 1245 } 1246 1247 /* 1248 * Make the current buffer empty. 1249 * Used when it is wiped out and it's the last buffer. 1250 */ 1251 static int 1252 empty_curbuf( 1253 int close_others, 1254 int forceit, 1255 int action) 1256 { 1257 int retval; 1258 buf_T *buf = curbuf; 1259 bufref_T bufref; 1260 1261 if (action == DOBUF_UNLOAD) 1262 { 1263 emsg(_("E90: Cannot unload last buffer")); 1264 return FAIL; 1265 } 1266 1267 set_bufref(&bufref, buf); 1268 if (close_others) 1269 /* Close any other windows on this buffer, then make it empty. */ 1270 close_windows(buf, TRUE); 1271 1272 setpcmark(); 1273 retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, 1274 forceit ? ECMD_FORCEIT : 0, curwin); 1275 1276 /* 1277 * do_ecmd() may create a new buffer, then we have to delete 1278 * the old one. But do_ecmd() may have done that already, check 1279 * if the buffer still exists. 1280 */ 1281 if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) 1282 close_buffer(NULL, buf, action, FALSE); 1283 if (!close_others) 1284 need_fileinfo = FALSE; 1285 return retval; 1286 } 1287 1288 /* 1289 * Implementation of the commands for the buffer list. 1290 * 1291 * action == DOBUF_GOTO go to specified buffer 1292 * action == DOBUF_SPLIT split window and go to specified buffer 1293 * action == DOBUF_UNLOAD unload specified buffer(s) 1294 * action == DOBUF_DEL delete specified buffer(s) from buffer list 1295 * action == DOBUF_WIPE delete specified buffer(s) really 1296 * action == DOBUF_WIPE_REUSE idem, and add number to "buf_reuse" 1297 * 1298 * start == DOBUF_CURRENT go to "count" buffer from current buffer 1299 * start == DOBUF_FIRST go to "count" buffer from first buffer 1300 * start == DOBUF_LAST go to "count" buffer from last buffer 1301 * start == DOBUF_MOD go to "count" modified buffer from current buffer 1302 * 1303 * Return FAIL or OK. 1304 */ 1305 int 1306 do_buffer( 1307 int action, 1308 int start, 1309 int dir, /* FORWARD or BACKWARD */ 1310 int count, /* buffer number or number of buffers */ 1311 int forceit) /* TRUE for :...! */ 1312 { 1313 buf_T *buf; 1314 buf_T *bp; 1315 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL 1316 || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); 1317 1318 switch (start) 1319 { 1320 case DOBUF_FIRST: buf = firstbuf; break; 1321 case DOBUF_LAST: buf = lastbuf; break; 1322 default: buf = curbuf; break; 1323 } 1324 if (start == DOBUF_MOD) /* find next modified buffer */ 1325 { 1326 while (count-- > 0) 1327 { 1328 do 1329 { 1330 buf = buf->b_next; 1331 if (buf == NULL) 1332 buf = firstbuf; 1333 } 1334 while (buf != curbuf && !bufIsChanged(buf)); 1335 } 1336 if (!bufIsChanged(buf)) 1337 { 1338 emsg(_("E84: No modified buffer found")); 1339 return FAIL; 1340 } 1341 } 1342 else if (start == DOBUF_FIRST && count) /* find specified buffer number */ 1343 { 1344 while (buf != NULL && buf->b_fnum != count) 1345 buf = buf->b_next; 1346 } 1347 else 1348 { 1349 bp = NULL; 1350 while (count > 0 || (!unload && !buf->b_p_bl && bp != buf)) 1351 { 1352 /* remember the buffer where we start, we come back there when all 1353 * buffers are unlisted. */ 1354 if (bp == NULL) 1355 bp = buf; 1356 if (dir == FORWARD) 1357 { 1358 buf = buf->b_next; 1359 if (buf == NULL) 1360 buf = firstbuf; 1361 } 1362 else 1363 { 1364 buf = buf->b_prev; 1365 if (buf == NULL) 1366 buf = lastbuf; 1367 } 1368 /* don't count unlisted buffers */ 1369 if (unload || buf->b_p_bl) 1370 { 1371 --count; 1372 bp = NULL; /* use this buffer as new starting point */ 1373 } 1374 if (bp == buf) 1375 { 1376 /* back where we started, didn't find anything. */ 1377 emsg(_("E85: There is no listed buffer")); 1378 return FAIL; 1379 } 1380 } 1381 } 1382 1383 if (buf == NULL) /* could not find it */ 1384 { 1385 if (start == DOBUF_FIRST) 1386 { 1387 /* don't warn when deleting */ 1388 if (!unload) 1389 semsg(_(e_nobufnr), count); 1390 } 1391 else if (dir == FORWARD) 1392 emsg(_("E87: Cannot go beyond last buffer")); 1393 else 1394 emsg(_("E88: Cannot go before first buffer")); 1395 return FAIL; 1396 } 1397 1398 #ifdef FEAT_GUI 1399 need_mouse_correct = TRUE; 1400 #endif 1401 1402 /* 1403 * delete buffer buf from memory and/or the list 1404 */ 1405 if (unload) 1406 { 1407 int forward; 1408 bufref_T bufref; 1409 1410 if (!can_unload_buffer(buf)) 1411 return FAIL; 1412 1413 set_bufref(&bufref, buf); 1414 1415 /* When unloading or deleting a buffer that's already unloaded and 1416 * unlisted: fail silently. */ 1417 if (action != DOBUF_WIPE && action != DOBUF_WIPE_REUSE 1418 && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl) 1419 return FAIL; 1420 1421 if (!forceit && bufIsChanged(buf)) 1422 { 1423 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1424 if ((p_confirm || cmdmod.confirm) && p_write) 1425 { 1426 dialog_changed(buf, FALSE); 1427 if (!bufref_valid(&bufref)) 1428 /* Autocommand deleted buffer, oops! It's not changed 1429 * now. */ 1430 return FAIL; 1431 /* If it's still changed fail silently, the dialog already 1432 * mentioned why it fails. */ 1433 if (bufIsChanged(buf)) 1434 return FAIL; 1435 } 1436 else 1437 #endif 1438 { 1439 semsg(_("E89: No write since last change for buffer %d (add ! to override)"), 1440 buf->b_fnum); 1441 return FAIL; 1442 } 1443 } 1444 1445 /* When closing the current buffer stop Visual mode. */ 1446 if (buf == curbuf && VIsual_active) 1447 end_visual_mode(); 1448 1449 /* 1450 * If deleting the last (listed) buffer, make it empty. 1451 * The last (listed) buffer cannot be unloaded. 1452 */ 1453 FOR_ALL_BUFFERS(bp) 1454 if (bp->b_p_bl && bp != buf) 1455 break; 1456 if (bp == NULL && buf == curbuf) 1457 return empty_curbuf(TRUE, forceit, action); 1458 1459 /* 1460 * If the deleted buffer is the current one, close the current window 1461 * (unless it's the only window). Repeat this so long as we end up in 1462 * a window with this buffer. 1463 */ 1464 while (buf == curbuf 1465 && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) 1466 && (!ONE_WINDOW || first_tabpage->tp_next != NULL)) 1467 { 1468 if (win_close(curwin, FALSE) == FAIL) 1469 break; 1470 } 1471 1472 /* 1473 * If the buffer to be deleted is not the current one, delete it here. 1474 */ 1475 if (buf != curbuf) 1476 { 1477 close_windows(buf, FALSE); 1478 if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) 1479 close_buffer(NULL, buf, action, FALSE); 1480 return OK; 1481 } 1482 1483 /* 1484 * Deleting the current buffer: Need to find another buffer to go to. 1485 * There should be another, otherwise it would have been handled 1486 * above. However, autocommands may have deleted all buffers. 1487 * First use au_new_curbuf.br_buf, if it is valid. 1488 * Then prefer the buffer we most recently visited. 1489 * Else try to find one that is loaded, after the current buffer, 1490 * then before the current buffer. 1491 * Finally use any buffer. 1492 */ 1493 buf = NULL; /* selected buffer */ 1494 bp = NULL; /* used when no loaded buffer found */ 1495 if (au_new_curbuf.br_buf != NULL && bufref_valid(&au_new_curbuf)) 1496 buf = au_new_curbuf.br_buf; 1497 #ifdef FEAT_JUMPLIST 1498 else if (curwin->w_jumplistlen > 0) 1499 { 1500 int jumpidx; 1501 1502 jumpidx = curwin->w_jumplistidx - 1; 1503 if (jumpidx < 0) 1504 jumpidx = curwin->w_jumplistlen - 1; 1505 1506 forward = jumpidx; 1507 while (jumpidx != curwin->w_jumplistidx) 1508 { 1509 buf = buflist_findnr(curwin->w_jumplist[jumpidx].fmark.fnum); 1510 if (buf != NULL) 1511 { 1512 if (buf == curbuf || !buf->b_p_bl) 1513 buf = NULL; /* skip current and unlisted bufs */ 1514 else if (buf->b_ml.ml_mfp == NULL) 1515 { 1516 /* skip unloaded buf, but may keep it for later */ 1517 if (bp == NULL) 1518 bp = buf; 1519 buf = NULL; 1520 } 1521 } 1522 if (buf != NULL) /* found a valid buffer: stop searching */ 1523 break; 1524 /* advance to older entry in jump list */ 1525 if (!jumpidx && curwin->w_jumplistidx == curwin->w_jumplistlen) 1526 break; 1527 if (--jumpidx < 0) 1528 jumpidx = curwin->w_jumplistlen - 1; 1529 if (jumpidx == forward) /* List exhausted for sure */ 1530 break; 1531 } 1532 } 1533 #endif 1534 1535 if (buf == NULL) /* No previous buffer, Try 2'nd approach */ 1536 { 1537 forward = TRUE; 1538 buf = curbuf->b_next; 1539 for (;;) 1540 { 1541 if (buf == NULL) 1542 { 1543 if (!forward) /* tried both directions */ 1544 break; 1545 buf = curbuf->b_prev; 1546 forward = FALSE; 1547 continue; 1548 } 1549 /* in non-help buffer, try to skip help buffers, and vv */ 1550 if (buf->b_help == curbuf->b_help && buf->b_p_bl) 1551 { 1552 if (buf->b_ml.ml_mfp != NULL) /* found loaded buffer */ 1553 break; 1554 if (bp == NULL) /* remember unloaded buf for later */ 1555 bp = buf; 1556 } 1557 if (forward) 1558 buf = buf->b_next; 1559 else 1560 buf = buf->b_prev; 1561 } 1562 } 1563 if (buf == NULL) /* No loaded buffer, use unloaded one */ 1564 buf = bp; 1565 if (buf == NULL) /* No loaded buffer, find listed one */ 1566 { 1567 FOR_ALL_BUFFERS(buf) 1568 if (buf->b_p_bl && buf != curbuf) 1569 break; 1570 } 1571 if (buf == NULL) /* Still no buffer, just take one */ 1572 { 1573 if (curbuf->b_next != NULL) 1574 buf = curbuf->b_next; 1575 else 1576 buf = curbuf->b_prev; 1577 } 1578 } 1579 1580 if (buf == NULL) 1581 { 1582 /* Autocommands must have wiped out all other buffers. Only option 1583 * now is to make the current buffer empty. */ 1584 return empty_curbuf(FALSE, forceit, action); 1585 } 1586 1587 /* 1588 * make buf current buffer 1589 */ 1590 if (action == DOBUF_SPLIT) /* split window first */ 1591 { 1592 /* If 'switchbuf' contains "useopen": jump to first window containing 1593 * "buf" if one exists */ 1594 if ((swb_flags & SWB_USEOPEN) && buf_jump_open_win(buf)) 1595 return OK; 1596 /* If 'switchbuf' contains "usetab": jump to first window in any tab 1597 * page containing "buf" if one exists */ 1598 if ((swb_flags & SWB_USETAB) && buf_jump_open_tab(buf)) 1599 return OK; 1600 if (win_split(0, 0) == FAIL) 1601 return FAIL; 1602 } 1603 1604 /* go to current buffer - nothing to do */ 1605 if (buf == curbuf) 1606 return OK; 1607 1608 /* 1609 * Check if the current buffer may be abandoned. 1610 */ 1611 if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit)) 1612 { 1613 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 1614 if ((p_confirm || cmdmod.confirm) && p_write) 1615 { 1616 bufref_T bufref; 1617 1618 set_bufref(&bufref, buf); 1619 dialog_changed(curbuf, FALSE); 1620 if (!bufref_valid(&bufref)) 1621 /* Autocommand deleted buffer, oops! */ 1622 return FAIL; 1623 } 1624 if (bufIsChanged(curbuf)) 1625 #endif 1626 { 1627 no_write_message(); 1628 return FAIL; 1629 } 1630 } 1631 1632 /* Go to the other buffer. */ 1633 set_curbuf(buf, action); 1634 1635 if (action == DOBUF_SPLIT) 1636 RESET_BINDING(curwin); /* reset 'scrollbind' and 'cursorbind' */ 1637 1638 #if defined(FEAT_EVAL) 1639 if (aborting()) /* autocmds may abort script processing */ 1640 return FAIL; 1641 #endif 1642 1643 return OK; 1644 } 1645 1646 /* 1647 * Set current buffer to "buf". Executes autocommands and closes current 1648 * buffer. "action" tells how to close the current buffer: 1649 * DOBUF_GOTO free or hide it 1650 * DOBUF_SPLIT nothing 1651 * DOBUF_UNLOAD unload it 1652 * DOBUF_DEL delete it 1653 * DOBUF_WIPE wipe it out 1654 * DOBUF_WIPE_REUSE wipe it out and add to "buf_reuse" 1655 */ 1656 void 1657 set_curbuf(buf_T *buf, int action) 1658 { 1659 buf_T *prevbuf; 1660 int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL 1661 || action == DOBUF_WIPE || action == DOBUF_WIPE_REUSE); 1662 #ifdef FEAT_SYN_HL 1663 long old_tw = curbuf->b_p_tw; 1664 #endif 1665 bufref_T newbufref; 1666 bufref_T prevbufref; 1667 1668 setpcmark(); 1669 if (!cmdmod.keepalt) 1670 curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */ 1671 buflist_altfpos(curwin); /* remember curpos */ 1672 1673 /* Don't restart Select mode after switching to another buffer. */ 1674 VIsual_reselect = FALSE; 1675 1676 /* close_windows() or apply_autocmds() may change curbuf and wipe out "buf" 1677 */ 1678 prevbuf = curbuf; 1679 set_bufref(&prevbufref, prevbuf); 1680 set_bufref(&newbufref, buf); 1681 1682 /* Autocommands may delete the curren buffer and/or the buffer we wan to go 1683 * to. In those cases don't close the buffer. */ 1684 if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf) 1685 || (bufref_valid(&prevbufref) 1686 && bufref_valid(&newbufref) 1687 #ifdef FEAT_EVAL 1688 && !aborting() 1689 #endif 1690 )) 1691 { 1692 #ifdef FEAT_SYN_HL 1693 if (prevbuf == curwin->w_buffer) 1694 reset_synblock(curwin); 1695 #endif 1696 if (unload) 1697 close_windows(prevbuf, FALSE); 1698 #if defined(FEAT_EVAL) 1699 if (bufref_valid(&prevbufref) && !aborting()) 1700 #else 1701 if (bufref_valid(&prevbufref)) 1702 #endif 1703 { 1704 win_T *previouswin = curwin; 1705 if (prevbuf == curbuf) 1706 u_sync(FALSE); 1707 close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, 1708 unload ? action : (action == DOBUF_GOTO 1709 && !buf_hide(prevbuf) 1710 && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); 1711 if (curwin != previouswin && win_valid(previouswin)) 1712 /* autocommands changed curwin, Grr! */ 1713 curwin = previouswin; 1714 } 1715 } 1716 /* An autocommand may have deleted "buf", already entered it (e.g., when 1717 * it did ":bunload") or aborted the script processing. 1718 * If curwin->w_buffer is null, enter_buffer() will make it valid again */ 1719 if ((buf_valid(buf) && buf != curbuf 1720 #ifdef FEAT_EVAL 1721 && !aborting() 1722 #endif 1723 ) || curwin->w_buffer == NULL) 1724 { 1725 enter_buffer(buf); 1726 #ifdef FEAT_SYN_HL 1727 if (old_tw != curbuf->b_p_tw) 1728 check_colorcolumn(curwin); 1729 #endif 1730 } 1731 } 1732 1733 /* 1734 * Enter a new current buffer. 1735 * Old curbuf must have been abandoned already! This also means "curbuf" may 1736 * be pointing to freed memory. 1737 */ 1738 static void 1739 enter_buffer(buf_T *buf) 1740 { 1741 /* Copy buffer and window local option values. Not for a help buffer. */ 1742 buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); 1743 if (!buf->b_help) 1744 get_winopts(buf); 1745 #ifdef FEAT_FOLDING 1746 else 1747 /* Remove all folds in the window. */ 1748 clearFolding(curwin); 1749 foldUpdateAll(curwin); /* update folds (later). */ 1750 #endif 1751 1752 /* Get the buffer in the current window. */ 1753 curwin->w_buffer = buf; 1754 curbuf = buf; 1755 ++curbuf->b_nwindows; 1756 1757 #ifdef FEAT_DIFF 1758 if (curwin->w_p_diff) 1759 diff_buf_add(curbuf); 1760 #endif 1761 1762 #ifdef FEAT_SYN_HL 1763 curwin->w_s = &(curbuf->b_s); 1764 #endif 1765 1766 /* Cursor on first line by default. */ 1767 curwin->w_cursor.lnum = 1; 1768 curwin->w_cursor.col = 0; 1769 curwin->w_cursor.coladd = 0; 1770 curwin->w_set_curswant = TRUE; 1771 curwin->w_topline_was_set = FALSE; 1772 1773 /* mark cursor position as being invalid */ 1774 curwin->w_valid = 0; 1775 1776 buflist_setfpos(curbuf, curwin, curbuf->b_last_cursor.lnum, 1777 curbuf->b_last_cursor.col, TRUE); 1778 1779 /* Make sure the buffer is loaded. */ 1780 if (curbuf->b_ml.ml_mfp == NULL) /* need to load the file */ 1781 { 1782 /* If there is no filetype, allow for detecting one. Esp. useful for 1783 * ":ball" used in a autocommand. If there already is a filetype we 1784 * might prefer to keep it. */ 1785 if (*curbuf->b_p_ft == NUL) 1786 did_filetype = FALSE; 1787 1788 open_buffer(FALSE, NULL, 0); 1789 } 1790 else 1791 { 1792 if (!msg_silent && !shortmess(SHM_FILEINFO)) 1793 need_fileinfo = TRUE; // display file info after redraw 1794 1795 // check if file changed 1796 (void)buf_check_timestamp(curbuf, FALSE); 1797 1798 curwin->w_topline = 1; 1799 #ifdef FEAT_DIFF 1800 curwin->w_topfill = 0; 1801 #endif 1802 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); 1803 apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf); 1804 } 1805 1806 /* If autocommands did not change the cursor position, restore cursor lnum 1807 * and possibly cursor col. */ 1808 if (curwin->w_cursor.lnum == 1 && inindent(0)) 1809 buflist_getfpos(); 1810 1811 check_arg_idx(curwin); /* check for valid arg_idx */ 1812 #ifdef FEAT_TITLE 1813 maketitle(); 1814 #endif 1815 /* when autocmds didn't change it */ 1816 if (curwin->w_topline == 1 && !curwin->w_topline_was_set) 1817 scroll_cursor_halfway(FALSE); /* redisplay at correct position */ 1818 1819 #ifdef FEAT_NETBEANS_INTG 1820 /* Send fileOpened event because we've changed buffers. */ 1821 netbeans_file_activated(curbuf); 1822 #endif 1823 1824 /* Change directories when the 'acd' option is set. */ 1825 DO_AUTOCHDIR; 1826 1827 #ifdef FEAT_KEYMAP 1828 if (curbuf->b_kmap_state & KEYMAP_INIT) 1829 (void)keymap_init(); 1830 #endif 1831 #ifdef FEAT_SPELL 1832 /* May need to set the spell language. Can only do this after the buffer 1833 * has been properly setup. */ 1834 if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) 1835 (void)did_set_spelllang(curwin); 1836 #endif 1837 #ifdef FEAT_VIMINFO 1838 curbuf->b_last_used = vim_time(); 1839 #endif 1840 1841 redraw_later(NOT_VALID); 1842 } 1843 1844 #if defined(FEAT_AUTOCHDIR) || defined(PROTO) 1845 /* 1846 * Change to the directory of the current buffer. 1847 * Don't do this while still starting up. 1848 */ 1849 void 1850 do_autochdir(void) 1851 { 1852 if ((starting == 0 || test_autochdir) 1853 && curbuf->b_ffname != NULL 1854 && vim_chdirfile(curbuf->b_ffname, "auto") == OK) 1855 shorten_fnames(TRUE); 1856 } 1857 #endif 1858 1859 void 1860 no_write_message(void) 1861 { 1862 #ifdef FEAT_TERMINAL 1863 if (term_job_running(curbuf->b_term)) 1864 emsg(_("E948: Job still running (add ! to end the job)")); 1865 else 1866 #endif 1867 emsg(_("E37: No write since last change (add ! to override)")); 1868 } 1869 1870 void 1871 no_write_message_nobang(buf_T *buf UNUSED) 1872 { 1873 #ifdef FEAT_TERMINAL 1874 if (term_job_running(buf->b_term)) 1875 emsg(_("E948: Job still running")); 1876 else 1877 #endif 1878 emsg(_("E37: No write since last change")); 1879 } 1880 1881 /* 1882 * functions for dealing with the buffer list 1883 */ 1884 1885 /* 1886 * Return TRUE if the current buffer is empty, unnamed, unmodified and used in 1887 * only one window. That means it can be re-used. 1888 */ 1889 int 1890 curbuf_reusable(void) 1891 { 1892 return (curbuf != NULL 1893 && curbuf->b_ffname == NULL 1894 && curbuf->b_nwindows <= 1 1895 && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY()) 1896 #if defined(FEAT_QUICKFIX) 1897 && !bt_quickfix(curbuf) 1898 #endif 1899 && !curbufIsChanged()); 1900 } 1901 1902 /* 1903 * Add a file name to the buffer list. Return a pointer to the buffer. 1904 * If the same file name already exists return a pointer to that buffer. 1905 * If it does not exist, or if fname == NULL, a new entry is created. 1906 * If (flags & BLN_CURBUF) is TRUE, may use current buffer. 1907 * If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list. 1908 * If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer. 1909 * If (flags & BLN_NEW) is TRUE, don't use an existing buffer. 1910 * If (flags & BLN_NOOPT) is TRUE, don't copy options from the current buffer 1911 * if the buffer already exists. 1912 * If (flags & BLN_REUSE) is TRUE, may use buffer number from "buf_reuse". 1913 * This is the ONLY way to create a new buffer. 1914 */ 1915 buf_T * 1916 buflist_new( 1917 char_u *ffname_arg, // full path of fname or relative 1918 char_u *sfname_arg, // short fname or NULL 1919 linenr_T lnum, // preferred cursor line 1920 int flags) // BLN_ defines 1921 { 1922 char_u *ffname = ffname_arg; 1923 char_u *sfname = sfname_arg; 1924 buf_T *buf; 1925 #ifdef UNIX 1926 stat_T st; 1927 #endif 1928 1929 if (top_file_num == 1) 1930 hash_init(&buf_hashtab); 1931 1932 fname_expand(curbuf, &ffname, &sfname); // will allocate ffname 1933 1934 /* 1935 * If file name already exists in the list, update the entry. 1936 */ 1937 #ifdef UNIX 1938 /* On Unix we can use inode numbers when the file exists. Works better 1939 * for hard links. */ 1940 if (sfname == NULL || mch_stat((char *)sfname, &st) < 0) 1941 st.st_dev = (dev_T)-1; 1942 #endif 1943 if (ffname != NULL && !(flags & (BLN_DUMMY | BLN_NEW)) && (buf = 1944 #ifdef UNIX 1945 buflist_findname_stat(ffname, &st) 1946 #else 1947 buflist_findname(ffname) 1948 #endif 1949 ) != NULL) 1950 { 1951 vim_free(ffname); 1952 if (lnum != 0) 1953 buflist_setfpos(buf, curwin, lnum, (colnr_T)0, FALSE); 1954 1955 if ((flags & BLN_NOOPT) == 0) 1956 /* copy the options now, if 'cpo' doesn't have 's' and not done 1957 * already */ 1958 buf_copy_options(buf, 0); 1959 1960 if ((flags & BLN_LISTED) && !buf->b_p_bl) 1961 { 1962 bufref_T bufref; 1963 1964 buf->b_p_bl = TRUE; 1965 set_bufref(&bufref, buf); 1966 if (!(flags & BLN_DUMMY)) 1967 { 1968 if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf) 1969 && !bufref_valid(&bufref)) 1970 return NULL; 1971 } 1972 } 1973 return buf; 1974 } 1975 1976 /* 1977 * If the current buffer has no name and no contents, use the current 1978 * buffer. Otherwise: Need to allocate a new buffer structure. 1979 * 1980 * This is the ONLY place where a new buffer structure is allocated! 1981 * (A spell file buffer is allocated in spell.c, but that's not a normal 1982 * buffer.) 1983 */ 1984 buf = NULL; 1985 if ((flags & BLN_CURBUF) && curbuf_reusable()) 1986 { 1987 buf = curbuf; 1988 /* It's like this buffer is deleted. Watch out for autocommands that 1989 * change curbuf! If that happens, allocate a new buffer anyway. */ 1990 if (curbuf->b_p_bl) 1991 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf); 1992 if (buf == curbuf) 1993 apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf); 1994 #ifdef FEAT_EVAL 1995 if (aborting()) /* autocmds may abort script processing */ 1996 return NULL; 1997 #endif 1998 if (buf == curbuf) 1999 { 2000 /* Make sure 'bufhidden' and 'buftype' are empty */ 2001 clear_string_option(&buf->b_p_bh); 2002 clear_string_option(&buf->b_p_bt); 2003 } 2004 } 2005 if (buf != curbuf || curbuf == NULL) 2006 { 2007 buf = ALLOC_CLEAR_ONE(buf_T); 2008 if (buf == NULL) 2009 { 2010 vim_free(ffname); 2011 return NULL; 2012 } 2013 #ifdef FEAT_EVAL 2014 /* init b: variables */ 2015 buf->b_vars = dict_alloc(); 2016 if (buf->b_vars == NULL) 2017 { 2018 vim_free(ffname); 2019 vim_free(buf); 2020 return NULL; 2021 } 2022 init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); 2023 #endif 2024 init_changedtick(buf); 2025 } 2026 2027 if (ffname != NULL) 2028 { 2029 buf->b_ffname = ffname; 2030 buf->b_sfname = vim_strsave(sfname); 2031 } 2032 2033 clear_wininfo(buf); 2034 buf->b_wininfo = ALLOC_CLEAR_ONE(wininfo_T); 2035 2036 if ((ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL)) 2037 || buf->b_wininfo == NULL) 2038 { 2039 if (buf->b_sfname != buf->b_ffname) 2040 VIM_CLEAR(buf->b_sfname); 2041 else 2042 buf->b_sfname = NULL; 2043 VIM_CLEAR(buf->b_ffname); 2044 if (buf != curbuf) 2045 free_buffer(buf); 2046 return NULL; 2047 } 2048 2049 if (buf == curbuf) 2050 { 2051 /* free all things allocated for this buffer */ 2052 buf_freeall(buf, 0); 2053 if (buf != curbuf) /* autocommands deleted the buffer! */ 2054 return NULL; 2055 #if defined(FEAT_EVAL) 2056 if (aborting()) /* autocmds may abort script processing */ 2057 return NULL; 2058 #endif 2059 free_buffer_stuff(buf, FALSE); /* delete local variables et al. */ 2060 2061 /* Init the options. */ 2062 buf->b_p_initialized = FALSE; 2063 buf_copy_options(buf, BCO_ENTER); 2064 2065 #ifdef FEAT_KEYMAP 2066 /* need to reload lmaps and set b:keymap_name */ 2067 curbuf->b_kmap_state |= KEYMAP_INIT; 2068 #endif 2069 } 2070 else 2071 { 2072 /* 2073 * put new buffer at the end of the buffer list 2074 */ 2075 buf->b_next = NULL; 2076 if (firstbuf == NULL) /* buffer list is empty */ 2077 { 2078 buf->b_prev = NULL; 2079 firstbuf = buf; 2080 } 2081 else /* append new buffer at end of list */ 2082 { 2083 lastbuf->b_next = buf; 2084 buf->b_prev = lastbuf; 2085 } 2086 lastbuf = buf; 2087 2088 if ((flags & BLN_REUSE) && buf_reuse.ga_len > 0) 2089 { 2090 // Recycle a previously used buffer number. Used for buffers which 2091 // are normally hidden, e.g. in a popup window. Avoids that the 2092 // buffer number grows rapidly. 2093 --buf_reuse.ga_len; 2094 buf->b_fnum = ((int *)buf_reuse.ga_data)[buf_reuse.ga_len]; 2095 } 2096 else 2097 buf->b_fnum = top_file_num++; 2098 if (top_file_num < 0) /* wrap around (may cause duplicates) */ 2099 { 2100 emsg(_("W14: Warning: List of file names overflow")); 2101 if (emsg_silent == 0) 2102 { 2103 out_flush(); 2104 ui_delay(3000L, TRUE); /* make sure it is noticed */ 2105 } 2106 top_file_num = 1; 2107 } 2108 buf_hashtab_add(buf); 2109 2110 /* 2111 * Always copy the options from the current buffer. 2112 */ 2113 buf_copy_options(buf, BCO_ALWAYS); 2114 } 2115 2116 buf->b_wininfo->wi_fpos.lnum = lnum; 2117 buf->b_wininfo->wi_win = curwin; 2118 2119 #ifdef FEAT_SYN_HL 2120 hash_init(&buf->b_s.b_keywtab); 2121 hash_init(&buf->b_s.b_keywtab_ic); 2122 #endif 2123 2124 buf->b_fname = buf->b_sfname; 2125 #ifdef UNIX 2126 if (st.st_dev == (dev_T)-1) 2127 buf->b_dev_valid = FALSE; 2128 else 2129 { 2130 buf->b_dev_valid = TRUE; 2131 buf->b_dev = st.st_dev; 2132 buf->b_ino = st.st_ino; 2133 } 2134 #endif 2135 buf->b_u_synced = TRUE; 2136 buf->b_flags = BF_CHECK_RO | BF_NEVERLOADED; 2137 if (flags & BLN_DUMMY) 2138 buf->b_flags |= BF_DUMMY; 2139 buf_clear_file(buf); 2140 clrallmarks(buf); /* clear marks */ 2141 fmarks_check_names(buf); /* check file marks for this file */ 2142 buf->b_p_bl = (flags & BLN_LISTED) ? TRUE : FALSE; /* init 'buflisted' */ 2143 if (!(flags & BLN_DUMMY)) 2144 { 2145 bufref_T bufref; 2146 2147 /* Tricky: these autocommands may change the buffer list. They could 2148 * also split the window with re-using the one empty buffer. This may 2149 * result in unexpectedly losing the empty buffer. */ 2150 set_bufref(&bufref, buf); 2151 if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf) 2152 && !bufref_valid(&bufref)) 2153 return NULL; 2154 if (flags & BLN_LISTED) 2155 { 2156 if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf) 2157 && !bufref_valid(&bufref)) 2158 return NULL; 2159 } 2160 #ifdef FEAT_EVAL 2161 if (aborting()) /* autocmds may abort script processing */ 2162 return NULL; 2163 #endif 2164 } 2165 2166 return buf; 2167 } 2168 2169 /* 2170 * Free the memory for the options of a buffer. 2171 * If "free_p_ff" is TRUE also free 'fileformat', 'buftype' and 2172 * 'fileencoding'. 2173 */ 2174 void 2175 free_buf_options( 2176 buf_T *buf, 2177 int free_p_ff) 2178 { 2179 if (free_p_ff) 2180 { 2181 clear_string_option(&buf->b_p_fenc); 2182 clear_string_option(&buf->b_p_ff); 2183 clear_string_option(&buf->b_p_bh); 2184 clear_string_option(&buf->b_p_bt); 2185 } 2186 #ifdef FEAT_FIND_ID 2187 clear_string_option(&buf->b_p_def); 2188 clear_string_option(&buf->b_p_inc); 2189 # ifdef FEAT_EVAL 2190 clear_string_option(&buf->b_p_inex); 2191 # endif 2192 #endif 2193 #if defined(FEAT_CINDENT) && defined(FEAT_EVAL) 2194 clear_string_option(&buf->b_p_inde); 2195 clear_string_option(&buf->b_p_indk); 2196 #endif 2197 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL) 2198 clear_string_option(&buf->b_p_bexpr); 2199 #endif 2200 #if defined(FEAT_CRYPT) 2201 clear_string_option(&buf->b_p_cm); 2202 #endif 2203 clear_string_option(&buf->b_p_fp); 2204 #if defined(FEAT_EVAL) 2205 clear_string_option(&buf->b_p_fex); 2206 #endif 2207 #ifdef FEAT_CRYPT 2208 clear_string_option(&buf->b_p_key); 2209 #endif 2210 clear_string_option(&buf->b_p_kp); 2211 clear_string_option(&buf->b_p_mps); 2212 clear_string_option(&buf->b_p_fo); 2213 clear_string_option(&buf->b_p_flp); 2214 clear_string_option(&buf->b_p_isk); 2215 #ifdef FEAT_VARTABS 2216 clear_string_option(&buf->b_p_vsts); 2217 vim_free(buf->b_p_vsts_nopaste); 2218 buf->b_p_vsts_nopaste = NULL; 2219 vim_free(buf->b_p_vsts_array); 2220 buf->b_p_vsts_array = NULL; 2221 clear_string_option(&buf->b_p_vts); 2222 VIM_CLEAR(buf->b_p_vts_array); 2223 #endif 2224 #ifdef FEAT_KEYMAP 2225 clear_string_option(&buf->b_p_keymap); 2226 keymap_clear(&buf->b_kmap_ga); 2227 ga_clear(&buf->b_kmap_ga); 2228 #endif 2229 #ifdef FEAT_COMMENTS 2230 clear_string_option(&buf->b_p_com); 2231 #endif 2232 #ifdef FEAT_FOLDING 2233 clear_string_option(&buf->b_p_cms); 2234 #endif 2235 clear_string_option(&buf->b_p_nf); 2236 #ifdef FEAT_SYN_HL 2237 clear_string_option(&buf->b_p_syn); 2238 clear_string_option(&buf->b_s.b_syn_isk); 2239 #endif 2240 #ifdef FEAT_SPELL 2241 clear_string_option(&buf->b_s.b_p_spc); 2242 clear_string_option(&buf->b_s.b_p_spf); 2243 vim_regfree(buf->b_s.b_cap_prog); 2244 buf->b_s.b_cap_prog = NULL; 2245 clear_string_option(&buf->b_s.b_p_spl); 2246 #endif 2247 #ifdef FEAT_SEARCHPATH 2248 clear_string_option(&buf->b_p_sua); 2249 #endif 2250 clear_string_option(&buf->b_p_ft); 2251 #ifdef FEAT_CINDENT 2252 clear_string_option(&buf->b_p_cink); 2253 clear_string_option(&buf->b_p_cino); 2254 #endif 2255 #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) 2256 clear_string_option(&buf->b_p_cinw); 2257 #endif 2258 clear_string_option(&buf->b_p_cpt); 2259 #ifdef FEAT_COMPL_FUNC 2260 clear_string_option(&buf->b_p_cfu); 2261 clear_string_option(&buf->b_p_ofu); 2262 #endif 2263 #ifdef FEAT_QUICKFIX 2264 clear_string_option(&buf->b_p_gp); 2265 clear_string_option(&buf->b_p_mp); 2266 clear_string_option(&buf->b_p_efm); 2267 #endif 2268 clear_string_option(&buf->b_p_ep); 2269 clear_string_option(&buf->b_p_path); 2270 clear_string_option(&buf->b_p_tags); 2271 clear_string_option(&buf->b_p_tc); 2272 #ifdef FEAT_EVAL 2273 clear_string_option(&buf->b_p_tfu); 2274 #endif 2275 clear_string_option(&buf->b_p_dict); 2276 clear_string_option(&buf->b_p_tsr); 2277 #ifdef FEAT_TEXTOBJ 2278 clear_string_option(&buf->b_p_qe); 2279 #endif 2280 buf->b_p_ar = -1; 2281 buf->b_p_ul = NO_LOCAL_UNDOLEVEL; 2282 #ifdef FEAT_LISP 2283 clear_string_option(&buf->b_p_lw); 2284 #endif 2285 clear_string_option(&buf->b_p_bkc); 2286 clear_string_option(&buf->b_p_menc); 2287 } 2288 2289 /* 2290 * Get alternate file "n". 2291 * Set linenr to "lnum" or altfpos.lnum if "lnum" == 0. 2292 * Also set cursor column to altfpos.col if 'startofline' is not set. 2293 * if (options & GETF_SETMARK) call setpcmark() 2294 * if (options & GETF_ALT) we are jumping to an alternate file. 2295 * if (options & GETF_SWITCH) respect 'switchbuf' settings when jumping 2296 * 2297 * Return FAIL for failure, OK for success. 2298 */ 2299 int 2300 buflist_getfile( 2301 int n, 2302 linenr_T lnum, 2303 int options, 2304 int forceit) 2305 { 2306 buf_T *buf; 2307 win_T *wp = NULL; 2308 pos_T *fpos; 2309 colnr_T col; 2310 2311 buf = buflist_findnr(n); 2312 if (buf == NULL) 2313 { 2314 if ((options & GETF_ALT) && n == 0) 2315 emsg(_(e_noalt)); 2316 else 2317 semsg(_("E92: Buffer %d not found"), n); 2318 return FAIL; 2319 } 2320 2321 /* if alternate file is the current buffer, nothing to do */ 2322 if (buf == curbuf) 2323 return OK; 2324 2325 if (text_locked()) 2326 { 2327 text_locked_msg(); 2328 return FAIL; 2329 } 2330 if (curbuf_locked()) 2331 return FAIL; 2332 2333 /* altfpos may be changed by getfile(), get it now */ 2334 if (lnum == 0) 2335 { 2336 fpos = buflist_findfpos(buf); 2337 lnum = fpos->lnum; 2338 col = fpos->col; 2339 } 2340 else 2341 col = 0; 2342 2343 if (options & GETF_SWITCH) 2344 { 2345 /* If 'switchbuf' contains "useopen": jump to first window containing 2346 * "buf" if one exists */ 2347 if (swb_flags & SWB_USEOPEN) 2348 wp = buf_jump_open_win(buf); 2349 2350 /* If 'switchbuf' contains "usetab": jump to first window in any tab 2351 * page containing "buf" if one exists */ 2352 if (wp == NULL && (swb_flags & SWB_USETAB)) 2353 wp = buf_jump_open_tab(buf); 2354 2355 /* If 'switchbuf' contains "split", "vsplit" or "newtab" and the 2356 * current buffer isn't empty: open new tab or window */ 2357 if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB)) 2358 && !BUFEMPTY()) 2359 { 2360 if (swb_flags & SWB_NEWTAB) 2361 tabpage_new(); 2362 else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0) 2363 == FAIL) 2364 return FAIL; 2365 RESET_BINDING(curwin); 2366 } 2367 } 2368 2369 ++RedrawingDisabled; 2370 if (GETFILE_SUCCESS(getfile(buf->b_fnum, NULL, NULL, 2371 (options & GETF_SETMARK), lnum, forceit))) 2372 { 2373 --RedrawingDisabled; 2374 2375 /* cursor is at to BOL and w_cursor.lnum is checked due to getfile() */ 2376 if (!p_sol && col != 0) 2377 { 2378 curwin->w_cursor.col = col; 2379 check_cursor_col(); 2380 curwin->w_cursor.coladd = 0; 2381 curwin->w_set_curswant = TRUE; 2382 } 2383 return OK; 2384 } 2385 --RedrawingDisabled; 2386 return FAIL; 2387 } 2388 2389 /* 2390 * go to the last know line number for the current buffer 2391 */ 2392 static void 2393 buflist_getfpos(void) 2394 { 2395 pos_T *fpos; 2396 2397 fpos = buflist_findfpos(curbuf); 2398 2399 curwin->w_cursor.lnum = fpos->lnum; 2400 check_cursor_lnum(); 2401 2402 if (p_sol) 2403 curwin->w_cursor.col = 0; 2404 else 2405 { 2406 curwin->w_cursor.col = fpos->col; 2407 check_cursor_col(); 2408 curwin->w_cursor.coladd = 0; 2409 curwin->w_set_curswant = TRUE; 2410 } 2411 } 2412 2413 #if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO) 2414 /* 2415 * Find file in buffer list by name (it has to be for the current window). 2416 * Returns NULL if not found. 2417 */ 2418 buf_T * 2419 buflist_findname_exp(char_u *fname) 2420 { 2421 char_u *ffname; 2422 buf_T *buf = NULL; 2423 2424 /* First make the name into a full path name */ 2425 ffname = FullName_save(fname, 2426 #ifdef UNIX 2427 TRUE /* force expansion, get rid of symbolic links */ 2428 #else 2429 FALSE 2430 #endif 2431 ); 2432 if (ffname != NULL) 2433 { 2434 buf = buflist_findname(ffname); 2435 vim_free(ffname); 2436 } 2437 return buf; 2438 } 2439 #endif 2440 2441 /* 2442 * Find file in buffer list by name (it has to be for the current window). 2443 * "ffname" must have a full path. 2444 * Skips dummy buffers. 2445 * Returns NULL if not found. 2446 */ 2447 buf_T * 2448 buflist_findname(char_u *ffname) 2449 { 2450 #ifdef UNIX 2451 stat_T st; 2452 2453 if (mch_stat((char *)ffname, &st) < 0) 2454 st.st_dev = (dev_T)-1; 2455 return buflist_findname_stat(ffname, &st); 2456 } 2457 2458 /* 2459 * Same as buflist_findname(), but pass the stat structure to avoid getting it 2460 * twice for the same file. 2461 * Returns NULL if not found. 2462 */ 2463 static buf_T * 2464 buflist_findname_stat( 2465 char_u *ffname, 2466 stat_T *stp) 2467 { 2468 #endif 2469 buf_T *buf; 2470 2471 /* Start at the last buffer, expect to find a match sooner. */ 2472 for (buf = lastbuf; buf != NULL; buf = buf->b_prev) 2473 if ((buf->b_flags & BF_DUMMY) == 0 && !otherfile_buf(buf, ffname 2474 #ifdef UNIX 2475 , stp 2476 #endif 2477 )) 2478 return buf; 2479 return NULL; 2480 } 2481 2482 /* 2483 * Find file in buffer list by a regexp pattern. 2484 * Return fnum of the found buffer. 2485 * Return < 0 for error. 2486 */ 2487 int 2488 buflist_findpat( 2489 char_u *pattern, 2490 char_u *pattern_end, /* pointer to first char after pattern */ 2491 int unlisted, /* find unlisted buffers */ 2492 int diffmode UNUSED, /* find diff-mode buffers only */ 2493 int curtab_only) /* find buffers in current tab only */ 2494 { 2495 buf_T *buf; 2496 int match = -1; 2497 int find_listed; 2498 char_u *pat; 2499 char_u *patend; 2500 int attempt; 2501 char_u *p; 2502 int toggledollar; 2503 2504 if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) 2505 { 2506 if (*pattern == '%') 2507 match = curbuf->b_fnum; 2508 else 2509 match = curwin->w_alt_fnum; 2510 #ifdef FEAT_DIFF 2511 if (diffmode && !diff_mode_buf(buflist_findnr(match))) 2512 match = -1; 2513 #endif 2514 } 2515 2516 /* 2517 * Try four ways of matching a listed buffer: 2518 * attempt == 0: without '^' or '$' (at any position) 2519 * attempt == 1: with '^' at start (only at position 0) 2520 * attempt == 2: with '$' at end (only match at end) 2521 * attempt == 3: with '^' at start and '$' at end (only full match) 2522 * Repeat this for finding an unlisted buffer if there was no matching 2523 * listed buffer. 2524 */ 2525 else 2526 { 2527 pat = file_pat_to_reg_pat(pattern, pattern_end, NULL, FALSE); 2528 if (pat == NULL) 2529 return -1; 2530 patend = pat + STRLEN(pat) - 1; 2531 toggledollar = (patend > pat && *patend == '$'); 2532 2533 /* First try finding a listed buffer. If not found and "unlisted" 2534 * is TRUE, try finding an unlisted buffer. */ 2535 find_listed = TRUE; 2536 for (;;) 2537 { 2538 for (attempt = 0; attempt <= 3; ++attempt) 2539 { 2540 regmatch_T regmatch; 2541 2542 /* may add '^' and '$' */ 2543 if (toggledollar) 2544 *patend = (attempt < 2) ? NUL : '$'; /* add/remove '$' */ 2545 p = pat; 2546 if (*p == '^' && !(attempt & 1)) /* add/remove '^' */ 2547 ++p; 2548 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); 2549 if (regmatch.regprog == NULL) 2550 { 2551 vim_free(pat); 2552 return -1; 2553 } 2554 2555 for (buf = lastbuf; buf != NULL; buf = buf->b_prev) 2556 if (buf->b_p_bl == find_listed 2557 #ifdef FEAT_DIFF 2558 && (!diffmode || diff_mode_buf(buf)) 2559 #endif 2560 && buflist_match(®match, buf, FALSE) != NULL) 2561 { 2562 if (curtab_only) 2563 { 2564 /* Ignore the match if the buffer is not open in 2565 * the current tab. */ 2566 win_T *wp; 2567 2568 FOR_ALL_WINDOWS(wp) 2569 if (wp->w_buffer == buf) 2570 break; 2571 if (wp == NULL) 2572 continue; 2573 } 2574 if (match >= 0) /* already found a match */ 2575 { 2576 match = -2; 2577 break; 2578 } 2579 match = buf->b_fnum; /* remember first match */ 2580 } 2581 2582 vim_regfree(regmatch.regprog); 2583 if (match >= 0) /* found one match */ 2584 break; 2585 } 2586 2587 /* Only search for unlisted buffers if there was no match with 2588 * a listed buffer. */ 2589 if (!unlisted || !find_listed || match != -1) 2590 break; 2591 find_listed = FALSE; 2592 } 2593 2594 vim_free(pat); 2595 } 2596 2597 if (match == -2) 2598 semsg(_("E93: More than one match for %s"), pattern); 2599 else if (match < 0) 2600 semsg(_("E94: No matching buffer for %s"), pattern); 2601 return match; 2602 } 2603 2604 /* 2605 * Find all buffer names that match. 2606 * For command line expansion of ":buf" and ":sbuf". 2607 * Return OK if matches found, FAIL otherwise. 2608 */ 2609 int 2610 ExpandBufnames( 2611 char_u *pat, 2612 int *num_file, 2613 char_u ***file, 2614 int options) 2615 { 2616 int count = 0; 2617 buf_T *buf; 2618 int round; 2619 char_u *p; 2620 int attempt; 2621 char_u *patc; 2622 2623 *num_file = 0; /* return values in case of FAIL */ 2624 *file = NULL; 2625 2626 /* Make a copy of "pat" and change "^" to "\(^\|[\/]\)". */ 2627 if (*pat == '^') 2628 { 2629 patc = alloc(STRLEN(pat) + 11); 2630 if (patc == NULL) 2631 return FAIL; 2632 STRCPY(patc, "\\(^\\|[\\/]\\)"); 2633 STRCPY(patc + 11, pat + 1); 2634 } 2635 else 2636 patc = pat; 2637 2638 /* 2639 * attempt == 0: try match with '\<', match at start of word 2640 * attempt == 1: try match without '\<', match anywhere 2641 */ 2642 for (attempt = 0; attempt <= 1; ++attempt) 2643 { 2644 regmatch_T regmatch; 2645 2646 if (attempt > 0 && patc == pat) 2647 break; /* there was no anchor, no need to try again */ 2648 regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC); 2649 if (regmatch.regprog == NULL) 2650 { 2651 if (patc != pat) 2652 vim_free(patc); 2653 return FAIL; 2654 } 2655 2656 /* 2657 * round == 1: Count the matches. 2658 * round == 2: Build the array to keep the matches. 2659 */ 2660 for (round = 1; round <= 2; ++round) 2661 { 2662 count = 0; 2663 FOR_ALL_BUFFERS(buf) 2664 { 2665 if (!buf->b_p_bl) /* skip unlisted buffers */ 2666 continue; 2667 p = buflist_match(®match, buf, p_wic); 2668 if (p != NULL) 2669 { 2670 if (round == 1) 2671 ++count; 2672 else 2673 { 2674 if (options & WILD_HOME_REPLACE) 2675 p = home_replace_save(buf, p); 2676 else 2677 p = vim_strsave(p); 2678 (*file)[count++] = p; 2679 } 2680 } 2681 } 2682 if (count == 0) /* no match found, break here */ 2683 break; 2684 if (round == 1) 2685 { 2686 *file = ALLOC_MULT(char_u *, count); 2687 if (*file == NULL) 2688 { 2689 vim_regfree(regmatch.regprog); 2690 if (patc != pat) 2691 vim_free(patc); 2692 return FAIL; 2693 } 2694 } 2695 } 2696 vim_regfree(regmatch.regprog); 2697 if (count) /* match(es) found, break here */ 2698 break; 2699 } 2700 2701 if (patc != pat) 2702 vim_free(patc); 2703 2704 *num_file = count; 2705 return (count == 0 ? FAIL : OK); 2706 } 2707 2708 /* 2709 * Check for a match on the file name for buffer "buf" with regprog "prog". 2710 */ 2711 static char_u * 2712 buflist_match( 2713 regmatch_T *rmp, 2714 buf_T *buf, 2715 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */ 2716 { 2717 char_u *match; 2718 2719 /* First try the short file name, then the long file name. */ 2720 match = fname_match(rmp, buf->b_sfname, ignore_case); 2721 if (match == NULL) 2722 match = fname_match(rmp, buf->b_ffname, ignore_case); 2723 2724 return match; 2725 } 2726 2727 /* 2728 * Try matching the regexp in "prog" with file name "name". 2729 * Return "name" when there is a match, NULL when not. 2730 */ 2731 static char_u * 2732 fname_match( 2733 regmatch_T *rmp, 2734 char_u *name, 2735 int ignore_case) /* when TRUE ignore case, when FALSE use 'fic' */ 2736 { 2737 char_u *match = NULL; 2738 char_u *p; 2739 2740 if (name != NULL) 2741 { 2742 /* Ignore case when 'fileignorecase' or the argument is set. */ 2743 rmp->rm_ic = p_fic || ignore_case; 2744 if (vim_regexec(rmp, name, (colnr_T)0)) 2745 match = name; 2746 else 2747 { 2748 /* Replace $(HOME) with '~' and try matching again. */ 2749 p = home_replace_save(NULL, name); 2750 if (p != NULL && vim_regexec(rmp, p, (colnr_T)0)) 2751 match = name; 2752 vim_free(p); 2753 } 2754 } 2755 2756 return match; 2757 } 2758 2759 /* 2760 * Find a file in the buffer list by buffer number. 2761 */ 2762 buf_T * 2763 buflist_findnr(int nr) 2764 { 2765 char_u key[VIM_SIZEOF_INT * 2 + 1]; 2766 hashitem_T *hi; 2767 2768 if (nr == 0) 2769 nr = curwin->w_alt_fnum; 2770 sprintf((char *)key, "%x", nr); 2771 hi = hash_find(&buf_hashtab, key); 2772 2773 if (!HASHITEM_EMPTY(hi)) 2774 return (buf_T *)(hi->hi_key 2775 - ((unsigned)(curbuf->b_key - (char_u *)curbuf))); 2776 return NULL; 2777 } 2778 2779 /* 2780 * Get name of file 'n' in the buffer list. 2781 * When the file has no name an empty string is returned. 2782 * home_replace() is used to shorten the file name (used for marks). 2783 * Returns a pointer to allocated memory, of NULL when failed. 2784 */ 2785 char_u * 2786 buflist_nr2name( 2787 int n, 2788 int fullname, 2789 int helptail) /* for help buffers return tail only */ 2790 { 2791 buf_T *buf; 2792 2793 buf = buflist_findnr(n); 2794 if (buf == NULL) 2795 return NULL; 2796 return home_replace_save(helptail ? buf : NULL, 2797 fullname ? buf->b_ffname : buf->b_fname); 2798 } 2799 2800 /* 2801 * Set the "lnum" and "col" for the buffer "buf" and the current window. 2802 * When "copy_options" is TRUE save the local window option values. 2803 * When "lnum" is 0 only do the options. 2804 */ 2805 void 2806 buflist_setfpos( 2807 buf_T *buf, 2808 win_T *win, 2809 linenr_T lnum, 2810 colnr_T col, 2811 int copy_options) 2812 { 2813 wininfo_T *wip; 2814 2815 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) 2816 if (wip->wi_win == win) 2817 break; 2818 if (wip == NULL) 2819 { 2820 /* allocate a new entry */ 2821 wip = ALLOC_CLEAR_ONE(wininfo_T); 2822 if (wip == NULL) 2823 return; 2824 wip->wi_win = win; 2825 if (lnum == 0) /* set lnum even when it's 0 */ 2826 lnum = 1; 2827 } 2828 else 2829 { 2830 /* remove the entry from the list */ 2831 if (wip->wi_prev) 2832 wip->wi_prev->wi_next = wip->wi_next; 2833 else 2834 buf->b_wininfo = wip->wi_next; 2835 if (wip->wi_next) 2836 wip->wi_next->wi_prev = wip->wi_prev; 2837 if (copy_options && wip->wi_optset) 2838 { 2839 clear_winopt(&wip->wi_opt); 2840 #ifdef FEAT_FOLDING 2841 deleteFoldRecurse(&wip->wi_folds); 2842 #endif 2843 } 2844 } 2845 if (lnum != 0) 2846 { 2847 wip->wi_fpos.lnum = lnum; 2848 wip->wi_fpos.col = col; 2849 } 2850 if (copy_options) 2851 { 2852 /* Save the window-specific option values. */ 2853 copy_winopt(&win->w_onebuf_opt, &wip->wi_opt); 2854 #ifdef FEAT_FOLDING 2855 wip->wi_fold_manual = win->w_fold_manual; 2856 cloneFoldGrowArray(&win->w_folds, &wip->wi_folds); 2857 #endif 2858 wip->wi_optset = TRUE; 2859 } 2860 2861 /* insert the entry in front of the list */ 2862 wip->wi_next = buf->b_wininfo; 2863 buf->b_wininfo = wip; 2864 wip->wi_prev = NULL; 2865 if (wip->wi_next) 2866 wip->wi_next->wi_prev = wip; 2867 2868 return; 2869 } 2870 2871 #ifdef FEAT_DIFF 2872 /* 2873 * Return TRUE when "wip" has 'diff' set and the diff is only for another tab 2874 * page. That's because a diff is local to a tab page. 2875 */ 2876 static int 2877 wininfo_other_tab_diff(wininfo_T *wip) 2878 { 2879 win_T *wp; 2880 2881 if (wip->wi_opt.wo_diff) 2882 { 2883 FOR_ALL_WINDOWS(wp) 2884 /* return FALSE when it's a window in the current tab page, thus 2885 * the buffer was in diff mode here */ 2886 if (wip->wi_win == wp) 2887 return FALSE; 2888 return TRUE; 2889 } 2890 return FALSE; 2891 } 2892 #endif 2893 2894 /* 2895 * Find info for the current window in buffer "buf". 2896 * If not found, return the info for the most recently used window. 2897 * When "skip_diff_buffer" is TRUE avoid windows with 'diff' set that is in 2898 * another tab page. 2899 * Returns NULL when there isn't any info. 2900 */ 2901 static wininfo_T * 2902 find_wininfo( 2903 buf_T *buf, 2904 int skip_diff_buffer UNUSED) 2905 { 2906 wininfo_T *wip; 2907 2908 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) 2909 if (wip->wi_win == curwin 2910 #ifdef FEAT_DIFF 2911 && (!skip_diff_buffer || !wininfo_other_tab_diff(wip)) 2912 #endif 2913 ) 2914 break; 2915 2916 /* If no wininfo for curwin, use the first in the list (that doesn't have 2917 * 'diff' set and is in another tab page). */ 2918 if (wip == NULL) 2919 { 2920 #ifdef FEAT_DIFF 2921 if (skip_diff_buffer) 2922 { 2923 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) 2924 if (!wininfo_other_tab_diff(wip)) 2925 break; 2926 } 2927 else 2928 #endif 2929 wip = buf->b_wininfo; 2930 } 2931 return wip; 2932 } 2933 2934 /* 2935 * Reset the local window options to the values last used in this window. 2936 * If the buffer wasn't used in this window before, use the values from 2937 * the most recently used window. If the values were never set, use the 2938 * global values for the window. 2939 */ 2940 void 2941 get_winopts(buf_T *buf) 2942 { 2943 wininfo_T *wip; 2944 2945 clear_winopt(&curwin->w_onebuf_opt); 2946 #ifdef FEAT_FOLDING 2947 clearFolding(curwin); 2948 #endif 2949 2950 wip = find_wininfo(buf, TRUE); 2951 if (wip != NULL && wip->wi_win != NULL 2952 && wip->wi_win != curwin && wip->wi_win->w_buffer == buf) 2953 { 2954 /* The buffer is currently displayed in the window: use the actual 2955 * option values instead of the saved (possibly outdated) values. */ 2956 win_T *wp = wip->wi_win; 2957 2958 copy_winopt(&wp->w_onebuf_opt, &curwin->w_onebuf_opt); 2959 #ifdef FEAT_FOLDING 2960 curwin->w_fold_manual = wp->w_fold_manual; 2961 curwin->w_foldinvalid = TRUE; 2962 cloneFoldGrowArray(&wp->w_folds, &curwin->w_folds); 2963 #endif 2964 } 2965 else if (wip != NULL && wip->wi_optset) 2966 { 2967 /* the buffer was displayed in the current window earlier */ 2968 copy_winopt(&wip->wi_opt, &curwin->w_onebuf_opt); 2969 #ifdef FEAT_FOLDING 2970 curwin->w_fold_manual = wip->wi_fold_manual; 2971 curwin->w_foldinvalid = TRUE; 2972 cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds); 2973 #endif 2974 } 2975 else 2976 copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt); 2977 2978 #ifdef FEAT_FOLDING 2979 /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */ 2980 if (p_fdls >= 0) 2981 curwin->w_p_fdl = p_fdls; 2982 #endif 2983 #ifdef FEAT_SYN_HL 2984 check_colorcolumn(curwin); 2985 #endif 2986 } 2987 2988 /* 2989 * Find the position (lnum and col) for the buffer 'buf' for the current 2990 * window. 2991 * Returns a pointer to no_position if no position is found. 2992 */ 2993 pos_T * 2994 buflist_findfpos(buf_T *buf) 2995 { 2996 wininfo_T *wip; 2997 static pos_T no_position = {1, 0, 0}; 2998 2999 wip = find_wininfo(buf, FALSE); 3000 if (wip != NULL) 3001 return &(wip->wi_fpos); 3002 else 3003 return &no_position; 3004 } 3005 3006 /* 3007 * Find the lnum for the buffer 'buf' for the current window. 3008 */ 3009 linenr_T 3010 buflist_findlnum(buf_T *buf) 3011 { 3012 return buflist_findfpos(buf)->lnum; 3013 } 3014 3015 /* 3016 * List all known file names (for :files and :buffers command). 3017 */ 3018 void 3019 buflist_list(exarg_T *eap) 3020 { 3021 buf_T *buf; 3022 int len; 3023 int i; 3024 int ro_char; 3025 int changed_char; 3026 #ifdef FEAT_TERMINAL 3027 int job_running; 3028 int job_none_open; 3029 #endif 3030 3031 for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next) 3032 { 3033 #ifdef FEAT_TERMINAL 3034 job_running = term_job_running(buf->b_term); 3035 job_none_open = job_running && term_none_open(buf->b_term); 3036 #endif 3037 /* skip unlisted buffers, unless ! was used */ 3038 if ((!buf->b_p_bl && !eap->forceit && !vim_strchr(eap->arg, 'u')) 3039 || (vim_strchr(eap->arg, 'u') && buf->b_p_bl) 3040 || (vim_strchr(eap->arg, '+') 3041 && ((buf->b_flags & BF_READERR) || !bufIsChanged(buf))) 3042 || (vim_strchr(eap->arg, 'a') 3043 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows == 0)) 3044 || (vim_strchr(eap->arg, 'h') 3045 && (buf->b_ml.ml_mfp == NULL || buf->b_nwindows != 0)) 3046 #ifdef FEAT_TERMINAL 3047 || (vim_strchr(eap->arg, 'R') 3048 && (!job_running || (job_running && job_none_open))) 3049 || (vim_strchr(eap->arg, '?') 3050 && (!job_running || (job_running && !job_none_open))) 3051 || (vim_strchr(eap->arg, 'F') 3052 && (job_running || buf->b_term == NULL)) 3053 #endif 3054 || (vim_strchr(eap->arg, '-') && buf->b_p_ma) 3055 || (vim_strchr(eap->arg, '=') && !buf->b_p_ro) 3056 || (vim_strchr(eap->arg, 'x') && !(buf->b_flags & BF_READERR)) 3057 || (vim_strchr(eap->arg, '%') && buf != curbuf) 3058 || (vim_strchr(eap->arg, '#') 3059 && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum))) 3060 continue; 3061 if (buf_spname(buf) != NULL) 3062 vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1); 3063 else 3064 home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE); 3065 if (message_filtered(NameBuff)) 3066 continue; 3067 3068 changed_char = (buf->b_flags & BF_READERR) ? 'x' 3069 : (bufIsChanged(buf) ? '+' : ' '); 3070 #ifdef FEAT_TERMINAL 3071 if (term_job_running(buf->b_term)) 3072 { 3073 if (term_none_open(buf->b_term)) 3074 ro_char = '?'; 3075 else 3076 ro_char = 'R'; 3077 changed_char = ' '; /* bufIsChanged() returns TRUE to avoid 3078 * closing, but it's not actually changed. */ 3079 } 3080 else if (buf->b_term != NULL) 3081 ro_char = 'F'; 3082 else 3083 #endif 3084 ro_char = !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' '); 3085 3086 msg_putchar('\n'); 3087 len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"", 3088 buf->b_fnum, 3089 buf->b_p_bl ? ' ' : 'u', 3090 buf == curbuf ? '%' : 3091 (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '), 3092 buf->b_ml.ml_mfp == NULL ? ' ' : 3093 (buf->b_nwindows == 0 ? 'h' : 'a'), 3094 ro_char, 3095 changed_char, 3096 NameBuff); 3097 if (len > IOSIZE - 20) 3098 len = IOSIZE - 20; 3099 3100 /* put "line 999" in column 40 or after the file name */ 3101 i = 40 - vim_strsize(IObuff); 3102 do 3103 IObuff[len++] = ' '; 3104 while (--i > 0 && len < IOSIZE - 18); 3105 vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), 3106 _("line %ld"), buf == curbuf ? curwin->w_cursor.lnum 3107 : (long)buflist_findlnum(buf)); 3108 msg_outtrans(IObuff); 3109 out_flush(); /* output one line at a time */ 3110 ui_breakcheck(); 3111 } 3112 } 3113 3114 /* 3115 * Get file name and line number for file 'fnum'. 3116 * Used by DoOneCmd() for translating '%' and '#'. 3117 * Used by insert_reg() and cmdline_paste() for '#' register. 3118 * Return FAIL if not found, OK for success. 3119 */ 3120 int 3121 buflist_name_nr( 3122 int fnum, 3123 char_u **fname, 3124 linenr_T *lnum) 3125 { 3126 buf_T *buf; 3127 3128 buf = buflist_findnr(fnum); 3129 if (buf == NULL || buf->b_fname == NULL) 3130 return FAIL; 3131 3132 *fname = buf->b_fname; 3133 *lnum = buflist_findlnum(buf); 3134 3135 return OK; 3136 } 3137 3138 /* 3139 * Set the file name for "buf"' to "ffname_arg", short file name to 3140 * "sfname_arg". 3141 * The file name with the full path is also remembered, for when :cd is used. 3142 * Returns FAIL for failure (file name already in use by other buffer) 3143 * OK otherwise. 3144 */ 3145 int 3146 setfname( 3147 buf_T *buf, 3148 char_u *ffname_arg, 3149 char_u *sfname_arg, 3150 int message) /* give message when buffer already exists */ 3151 { 3152 char_u *ffname = ffname_arg; 3153 char_u *sfname = sfname_arg; 3154 buf_T *obuf = NULL; 3155 #ifdef UNIX 3156 stat_T st; 3157 #endif 3158 3159 if (ffname == NULL || *ffname == NUL) 3160 { 3161 /* Removing the name. */ 3162 if (buf->b_sfname != buf->b_ffname) 3163 VIM_CLEAR(buf->b_sfname); 3164 else 3165 buf->b_sfname = NULL; 3166 VIM_CLEAR(buf->b_ffname); 3167 #ifdef UNIX 3168 st.st_dev = (dev_T)-1; 3169 #endif 3170 } 3171 else 3172 { 3173 fname_expand(buf, &ffname, &sfname); /* will allocate ffname */ 3174 if (ffname == NULL) /* out of memory */ 3175 return FAIL; 3176 3177 /* 3178 * if the file name is already used in another buffer: 3179 * - if the buffer is loaded, fail 3180 * - if the buffer is not loaded, delete it from the list 3181 */ 3182 #ifdef UNIX 3183 if (mch_stat((char *)ffname, &st) < 0) 3184 st.st_dev = (dev_T)-1; 3185 #endif 3186 if (!(buf->b_flags & BF_DUMMY)) 3187 #ifdef UNIX 3188 obuf = buflist_findname_stat(ffname, &st); 3189 #else 3190 obuf = buflist_findname(ffname); 3191 #endif 3192 if (obuf != NULL && obuf != buf) 3193 { 3194 if (obuf->b_ml.ml_mfp != NULL) /* it's loaded, fail */ 3195 { 3196 if (message) 3197 emsg(_("E95: Buffer with this name already exists")); 3198 vim_free(ffname); 3199 return FAIL; 3200 } 3201 /* delete from the list */ 3202 close_buffer(NULL, obuf, DOBUF_WIPE, FALSE); 3203 } 3204 sfname = vim_strsave(sfname); 3205 if (ffname == NULL || sfname == NULL) 3206 { 3207 vim_free(sfname); 3208 vim_free(ffname); 3209 return FAIL; 3210 } 3211 #ifdef USE_FNAME_CASE 3212 fname_case(sfname, 0); /* set correct case for short file name */ 3213 #endif 3214 if (buf->b_sfname != buf->b_ffname) 3215 vim_free(buf->b_sfname); 3216 vim_free(buf->b_ffname); 3217 buf->b_ffname = ffname; 3218 buf->b_sfname = sfname; 3219 } 3220 buf->b_fname = buf->b_sfname; 3221 #ifdef UNIX 3222 if (st.st_dev == (dev_T)-1) 3223 buf->b_dev_valid = FALSE; 3224 else 3225 { 3226 buf->b_dev_valid = TRUE; 3227 buf->b_dev = st.st_dev; 3228 buf->b_ino = st.st_ino; 3229 } 3230 #endif 3231 3232 buf->b_shortname = FALSE; 3233 3234 buf_name_changed(buf); 3235 return OK; 3236 } 3237 3238 /* 3239 * Crude way of changing the name of a buffer. Use with care! 3240 * The name should be relative to the current directory. 3241 */ 3242 void 3243 buf_set_name(int fnum, char_u *name) 3244 { 3245 buf_T *buf; 3246 3247 buf = buflist_findnr(fnum); 3248 if (buf != NULL) 3249 { 3250 if (buf->b_sfname != buf->b_ffname) 3251 vim_free(buf->b_sfname); 3252 vim_free(buf->b_ffname); 3253 buf->b_ffname = vim_strsave(name); 3254 buf->b_sfname = NULL; 3255 /* Allocate ffname and expand into full path. Also resolves .lnk 3256 * files on Win32. */ 3257 fname_expand(buf, &buf->b_ffname, &buf->b_sfname); 3258 buf->b_fname = buf->b_sfname; 3259 } 3260 } 3261 3262 /* 3263 * Take care of what needs to be done when the name of buffer "buf" has 3264 * changed. 3265 */ 3266 void 3267 buf_name_changed(buf_T *buf) 3268 { 3269 /* 3270 * If the file name changed, also change the name of the swapfile 3271 */ 3272 if (buf->b_ml.ml_mfp != NULL) 3273 ml_setname(buf); 3274 3275 if (curwin->w_buffer == buf) 3276 check_arg_idx(curwin); /* check file name for arg list */ 3277 #ifdef FEAT_TITLE 3278 maketitle(); /* set window title */ 3279 #endif 3280 status_redraw_all(); /* status lines need to be redrawn */ 3281 fmarks_check_names(buf); /* check named file marks */ 3282 ml_timestamp(buf); /* reset timestamp */ 3283 } 3284 3285 /* 3286 * set alternate file name for current window 3287 * 3288 * Used by do_one_cmd(), do_write() and do_ecmd(). 3289 * Return the buffer. 3290 */ 3291 buf_T * 3292 setaltfname( 3293 char_u *ffname, 3294 char_u *sfname, 3295 linenr_T lnum) 3296 { 3297 buf_T *buf; 3298 3299 /* Create a buffer. 'buflisted' is not set if it's a new buffer */ 3300 buf = buflist_new(ffname, sfname, lnum, 0); 3301 if (buf != NULL && !cmdmod.keepalt) 3302 curwin->w_alt_fnum = buf->b_fnum; 3303 return buf; 3304 } 3305 3306 /* 3307 * Get alternate file name for current window. 3308 * Return NULL if there isn't any, and give error message if requested. 3309 */ 3310 char_u * 3311 getaltfname( 3312 int errmsg) /* give error message */ 3313 { 3314 char_u *fname; 3315 linenr_T dummy; 3316 3317 if (buflist_name_nr(0, &fname, &dummy) == FAIL) 3318 { 3319 if (errmsg) 3320 emsg(_(e_noalt)); 3321 return NULL; 3322 } 3323 return fname; 3324 } 3325 3326 /* 3327 * Add a file name to the buflist and return its number. 3328 * Uses same flags as buflist_new(), except BLN_DUMMY. 3329 * 3330 * used by qf_init(), main() and doarglist() 3331 */ 3332 int 3333 buflist_add(char_u *fname, int flags) 3334 { 3335 buf_T *buf; 3336 3337 buf = buflist_new(fname, NULL, (linenr_T)0, flags); 3338 if (buf != NULL) 3339 return buf->b_fnum; 3340 return 0; 3341 } 3342 3343 #if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) 3344 /* 3345 * Adjust slashes in file names. Called after 'shellslash' was set. 3346 */ 3347 void 3348 buflist_slash_adjust(void) 3349 { 3350 buf_T *bp; 3351 3352 FOR_ALL_BUFFERS(bp) 3353 { 3354 if (bp->b_ffname != NULL) 3355 slash_adjust(bp->b_ffname); 3356 if (bp->b_sfname != NULL) 3357 slash_adjust(bp->b_sfname); 3358 } 3359 } 3360 #endif 3361 3362 /* 3363 * Set alternate cursor position for the current buffer and window "win". 3364 * Also save the local window option values. 3365 */ 3366 void 3367 buflist_altfpos(win_T *win) 3368 { 3369 buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE); 3370 } 3371 3372 /* 3373 * Return TRUE if 'ffname' is not the same file as current file. 3374 * Fname must have a full path (expanded by mch_FullName()). 3375 */ 3376 int 3377 otherfile(char_u *ffname) 3378 { 3379 return otherfile_buf(curbuf, ffname 3380 #ifdef UNIX 3381 , NULL 3382 #endif 3383 ); 3384 } 3385 3386 static int 3387 otherfile_buf( 3388 buf_T *buf, 3389 char_u *ffname 3390 #ifdef UNIX 3391 , stat_T *stp 3392 #endif 3393 ) 3394 { 3395 /* no name is different */ 3396 if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) 3397 return TRUE; 3398 if (fnamecmp(ffname, buf->b_ffname) == 0) 3399 return FALSE; 3400 #ifdef UNIX 3401 { 3402 stat_T st; 3403 3404 /* If no stat_T given, get it now */ 3405 if (stp == NULL) 3406 { 3407 if (!buf->b_dev_valid || mch_stat((char *)ffname, &st) < 0) 3408 st.st_dev = (dev_T)-1; 3409 stp = &st; 3410 } 3411 /* Use dev/ino to check if the files are the same, even when the names 3412 * are different (possible with links). Still need to compare the 3413 * name above, for when the file doesn't exist yet. 3414 * Problem: The dev/ino changes when a file is deleted (and created 3415 * again) and remains the same when renamed/moved. We don't want to 3416 * mch_stat() each buffer each time, that would be too slow. Get the 3417 * dev/ino again when they appear to match, but not when they appear 3418 * to be different: Could skip a buffer when it's actually the same 3419 * file. */ 3420 if (buf_same_ino(buf, stp)) 3421 { 3422 buf_setino(buf); 3423 if (buf_same_ino(buf, stp)) 3424 return FALSE; 3425 } 3426 } 3427 #endif 3428 return TRUE; 3429 } 3430 3431 #if defined(UNIX) || defined(PROTO) 3432 /* 3433 * Set inode and device number for a buffer. 3434 * Must always be called when b_fname is changed!. 3435 */ 3436 void 3437 buf_setino(buf_T *buf) 3438 { 3439 stat_T st; 3440 3441 if (buf->b_fname != NULL && mch_stat((char *)buf->b_fname, &st) >= 0) 3442 { 3443 buf->b_dev_valid = TRUE; 3444 buf->b_dev = st.st_dev; 3445 buf->b_ino = st.st_ino; 3446 } 3447 else 3448 buf->b_dev_valid = FALSE; 3449 } 3450 3451 /* 3452 * Return TRUE if dev/ino in buffer "buf" matches with "stp". 3453 */ 3454 static int 3455 buf_same_ino( 3456 buf_T *buf, 3457 stat_T *stp) 3458 { 3459 return (buf->b_dev_valid 3460 && stp->st_dev == buf->b_dev 3461 && stp->st_ino == buf->b_ino); 3462 } 3463 #endif 3464 3465 /* 3466 * Print info about the current buffer. 3467 */ 3468 void 3469 fileinfo( 3470 int fullname, /* when non-zero print full path */ 3471 int shorthelp, 3472 int dont_truncate) 3473 { 3474 char_u *name; 3475 int n; 3476 char *p; 3477 char *buffer; 3478 size_t len; 3479 3480 buffer = alloc(IOSIZE); 3481 if (buffer == NULL) 3482 return; 3483 3484 if (fullname > 1) /* 2 CTRL-G: include buffer number */ 3485 { 3486 vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum); 3487 p = buffer + STRLEN(buffer); 3488 } 3489 else 3490 p = buffer; 3491 3492 *p++ = '"'; 3493 if (buf_spname(curbuf) != NULL) 3494 vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1); 3495 else 3496 { 3497 if (!fullname && curbuf->b_fname != NULL) 3498 name = curbuf->b_fname; 3499 else 3500 name = curbuf->b_ffname; 3501 home_replace(shorthelp ? curbuf : NULL, name, (char_u *)p, 3502 (int)(IOSIZE - (p - buffer)), TRUE); 3503 } 3504 3505 vim_snprintf_add(buffer, IOSIZE, "\"%s%s%s%s%s%s", 3506 curbufIsChanged() ? (shortmess(SHM_MOD) 3507 ? " [+]" : _(" [Modified]")) : " ", 3508 (curbuf->b_flags & BF_NOTEDITED) 3509 #ifdef FEAT_QUICKFIX 3510 && !bt_dontwrite(curbuf) 3511 #endif 3512 ? _("[Not edited]") : "", 3513 (curbuf->b_flags & BF_NEW) 3514 #ifdef FEAT_QUICKFIX 3515 && !bt_dontwrite(curbuf) 3516 #endif 3517 ? _("[New file]") : "", 3518 (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "", 3519 curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]") 3520 : _("[readonly]")) : "", 3521 (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK) 3522 || curbuf->b_p_ro) ? 3523 " " : ""); 3524 /* With 32 bit longs and more than 21,474,836 lines multiplying by 100 3525 * causes an overflow, thus for large numbers divide instead. */ 3526 if (curwin->w_cursor.lnum > 1000000L) 3527 n = (int)(((long)curwin->w_cursor.lnum) / 3528 ((long)curbuf->b_ml.ml_line_count / 100L)); 3529 else 3530 n = (int)(((long)curwin->w_cursor.lnum * 100L) / 3531 (long)curbuf->b_ml.ml_line_count); 3532 if (curbuf->b_ml.ml_flags & ML_EMPTY) 3533 vim_snprintf_add(buffer, IOSIZE, "%s", _(no_lines_msg)); 3534 #ifdef FEAT_CMDL_INFO 3535 else if (p_ru) 3536 /* Current line and column are already on the screen -- webb */ 3537 vim_snprintf_add(buffer, IOSIZE, 3538 NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", 3539 curbuf->b_ml.ml_line_count), 3540 (long)curbuf->b_ml.ml_line_count, n); 3541 #endif 3542 else 3543 { 3544 vim_snprintf_add(buffer, IOSIZE, 3545 _("line %ld of %ld --%d%%-- col "), 3546 (long)curwin->w_cursor.lnum, 3547 (long)curbuf->b_ml.ml_line_count, 3548 n); 3549 validate_virtcol(); 3550 len = STRLEN(buffer); 3551 col_print((char_u *)buffer + len, IOSIZE - len, 3552 (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); 3553 } 3554 3555 (void)append_arg_number(curwin, (char_u *)buffer, IOSIZE, 3556 !shortmess(SHM_FILE)); 3557 3558 if (dont_truncate) 3559 { 3560 /* Temporarily set msg_scroll to avoid the message being truncated. 3561 * First call msg_start() to get the message in the right place. */ 3562 msg_start(); 3563 n = msg_scroll; 3564 msg_scroll = TRUE; 3565 msg(buffer); 3566 msg_scroll = n; 3567 } 3568 else 3569 { 3570 p = (char *)msg_trunc_attr(buffer, FALSE, 0); 3571 if (restart_edit != 0 || (msg_scrolled && !need_wait_return)) 3572 /* Need to repeat the message after redrawing when: 3573 * - When restart_edit is set (otherwise there will be a delay 3574 * before redrawing). 3575 * - When the screen was scrolled but there is no wait-return 3576 * prompt. */ 3577 set_keep_msg((char_u *)p, 0); 3578 } 3579 3580 vim_free(buffer); 3581 } 3582 3583 void 3584 col_print( 3585 char_u *buf, 3586 size_t buflen, 3587 int col, 3588 int vcol) 3589 { 3590 if (col == vcol) 3591 vim_snprintf((char *)buf, buflen, "%d", col); 3592 else 3593 vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol); 3594 } 3595 3596 #if defined(FEAT_TITLE) || defined(PROTO) 3597 static char_u *lasttitle = NULL; 3598 static char_u *lasticon = NULL; 3599 3600 /* 3601 * Put the file name in the title bar and icon of the window. 3602 */ 3603 void 3604 maketitle(void) 3605 { 3606 char_u *p; 3607 char_u *title_str = NULL; 3608 char_u *icon_str = NULL; 3609 int maxlen = 0; 3610 int len; 3611 int mustset; 3612 char_u buf[IOSIZE]; 3613 int off; 3614 3615 if (!redrawing()) 3616 { 3617 /* Postpone updating the title when 'lazyredraw' is set. */ 3618 need_maketitle = TRUE; 3619 return; 3620 } 3621 3622 need_maketitle = FALSE; 3623 if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL) 3624 return; // nothing to do 3625 3626 if (p_title) 3627 { 3628 if (p_titlelen > 0) 3629 { 3630 maxlen = p_titlelen * Columns / 100; 3631 if (maxlen < 10) 3632 maxlen = 10; 3633 } 3634 3635 title_str = buf; 3636 if (*p_titlestring != NUL) 3637 { 3638 #ifdef FEAT_STL_OPT 3639 if (stl_syntax & STL_IN_TITLE) 3640 { 3641 int use_sandbox = FALSE; 3642 int save_called_emsg = called_emsg; 3643 3644 # ifdef FEAT_EVAL 3645 use_sandbox = was_set_insecurely((char_u *)"titlestring", 0); 3646 # endif 3647 called_emsg = FALSE; 3648 build_stl_str_hl(curwin, title_str, sizeof(buf), 3649 p_titlestring, use_sandbox, 3650 0, maxlen, NULL, NULL); 3651 if (called_emsg) 3652 set_string_option_direct((char_u *)"titlestring", -1, 3653 (char_u *)"", OPT_FREE, SID_ERROR); 3654 called_emsg |= save_called_emsg; 3655 } 3656 else 3657 #endif 3658 title_str = p_titlestring; 3659 } 3660 else 3661 { 3662 /* format: "fname + (path) (1 of 2) - VIM" */ 3663 3664 #define SPACE_FOR_FNAME (IOSIZE - 100) 3665 #define SPACE_FOR_DIR (IOSIZE - 20) 3666 #define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */ 3667 if (curbuf->b_fname == NULL) 3668 vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME); 3669 #ifdef FEAT_TERMINAL 3670 else if (curbuf->b_term != NULL) 3671 { 3672 vim_strncpy(buf, term_get_status_text(curbuf->b_term), 3673 SPACE_FOR_FNAME); 3674 } 3675 #endif 3676 else 3677 { 3678 p = transstr(gettail(curbuf->b_fname)); 3679 vim_strncpy(buf, p, SPACE_FOR_FNAME); 3680 vim_free(p); 3681 } 3682 3683 #ifdef FEAT_TERMINAL 3684 if (curbuf->b_term == NULL) 3685 #endif 3686 switch (bufIsChanged(curbuf) 3687 + (curbuf->b_p_ro * 2) 3688 + (!curbuf->b_p_ma * 4)) 3689 { 3690 case 1: STRCAT(buf, " +"); break; 3691 case 2: STRCAT(buf, " ="); break; 3692 case 3: STRCAT(buf, " =+"); break; 3693 case 4: 3694 case 6: STRCAT(buf, " -"); break; 3695 case 5: 3696 case 7: STRCAT(buf, " -+"); break; 3697 } 3698 3699 if (curbuf->b_fname != NULL 3700 #ifdef FEAT_TERMINAL 3701 && curbuf->b_term == NULL 3702 #endif 3703 ) 3704 { 3705 /* Get path of file, replace home dir with ~ */ 3706 off = (int)STRLEN(buf); 3707 buf[off++] = ' '; 3708 buf[off++] = '('; 3709 home_replace(curbuf, curbuf->b_ffname, 3710 buf + off, SPACE_FOR_DIR - off, TRUE); 3711 #ifdef BACKSLASH_IN_FILENAME 3712 /* avoid "c:/name" to be reduced to "c" */ 3713 if (isalpha(buf[off]) && buf[off + 1] == ':') 3714 off += 2; 3715 #endif 3716 /* remove the file name */ 3717 p = gettail_sep(buf + off); 3718 if (p == buf + off) 3719 { 3720 /* must be a help buffer */ 3721 vim_strncpy(buf + off, (char_u *)_("help"), 3722 (size_t)(SPACE_FOR_DIR - off - 1)); 3723 } 3724 else 3725 *p = NUL; 3726 3727 /* Translate unprintable chars and concatenate. Keep some 3728 * room for the server name. When there is no room (very long 3729 * file name) use (...). */ 3730 if (off < SPACE_FOR_DIR) 3731 { 3732 p = transstr(buf + off); 3733 vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off)); 3734 vim_free(p); 3735 } 3736 else 3737 { 3738 vim_strncpy(buf + off, (char_u *)"...", 3739 (size_t)(SPACE_FOR_ARGNR - off)); 3740 } 3741 STRCAT(buf, ")"); 3742 } 3743 3744 append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE); 3745 3746 #if defined(FEAT_CLIENTSERVER) 3747 if (serverName != NULL) 3748 { 3749 STRCAT(buf, " - "); 3750 vim_strcat(buf, serverName, IOSIZE); 3751 } 3752 else 3753 #endif 3754 STRCAT(buf, " - VIM"); 3755 3756 if (maxlen > 0) 3757 { 3758 /* make it shorter by removing a bit in the middle */ 3759 if (vim_strsize(buf) > maxlen) 3760 trunc_string(buf, buf, maxlen, IOSIZE); 3761 } 3762 } 3763 } 3764 mustset = value_changed(title_str, &lasttitle); 3765 3766 if (p_icon) 3767 { 3768 icon_str = buf; 3769 if (*p_iconstring != NUL) 3770 { 3771 #ifdef FEAT_STL_OPT 3772 if (stl_syntax & STL_IN_ICON) 3773 { 3774 int use_sandbox = FALSE; 3775 int save_called_emsg = called_emsg; 3776 3777 # ifdef FEAT_EVAL 3778 use_sandbox = was_set_insecurely((char_u *)"iconstring", 0); 3779 # endif 3780 called_emsg = FALSE; 3781 build_stl_str_hl(curwin, icon_str, sizeof(buf), 3782 p_iconstring, use_sandbox, 3783 0, 0, NULL, NULL); 3784 if (called_emsg) 3785 set_string_option_direct((char_u *)"iconstring", -1, 3786 (char_u *)"", OPT_FREE, SID_ERROR); 3787 called_emsg |= save_called_emsg; 3788 } 3789 else 3790 #endif 3791 icon_str = p_iconstring; 3792 } 3793 else 3794 { 3795 if (buf_spname(curbuf) != NULL) 3796 p = buf_spname(curbuf); 3797 else /* use file name only in icon */ 3798 p = gettail(curbuf->b_ffname); 3799 *icon_str = NUL; 3800 /* Truncate name at 100 bytes. */ 3801 len = (int)STRLEN(p); 3802 if (len > 100) 3803 { 3804 len -= 100; 3805 if (has_mbyte) 3806 len += (*mb_tail_off)(p, p + len) + 1; 3807 p += len; 3808 } 3809 STRCPY(icon_str, p); 3810 trans_characters(icon_str, IOSIZE); 3811 } 3812 } 3813 3814 mustset |= value_changed(icon_str, &lasticon); 3815 3816 if (mustset) 3817 resettitle(); 3818 } 3819 3820 /* 3821 * Used for title and icon: Check if "str" differs from "*last". Set "*last" 3822 * from "str" if it does. 3823 * Return TRUE if resettitle() is to be called. 3824 */ 3825 static int 3826 value_changed(char_u *str, char_u **last) 3827 { 3828 if ((str == NULL) != (*last == NULL) 3829 || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) 3830 { 3831 vim_free(*last); 3832 if (str == NULL) 3833 { 3834 *last = NULL; 3835 mch_restore_title( 3836 last == &lasttitle ? SAVE_RESTORE_TITLE : SAVE_RESTORE_ICON); 3837 } 3838 else 3839 { 3840 *last = vim_strsave(str); 3841 return TRUE; 3842 } 3843 } 3844 return FALSE; 3845 } 3846 3847 /* 3848 * Put current window title back (used after calling a shell) 3849 */ 3850 void 3851 resettitle(void) 3852 { 3853 mch_settitle(lasttitle, lasticon); 3854 } 3855 3856 # if defined(EXITFREE) || defined(PROTO) 3857 void 3858 free_titles(void) 3859 { 3860 vim_free(lasttitle); 3861 vim_free(lasticon); 3862 } 3863 # endif 3864 3865 #endif /* FEAT_TITLE */ 3866 3867 #if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO) 3868 /* 3869 * Build a string from the status line items in "fmt". 3870 * Return length of string in screen cells. 3871 * 3872 * Normally works for window "wp", except when working for 'tabline' then it 3873 * is "curwin". 3874 * 3875 * Items are drawn interspersed with the text that surrounds it 3876 * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation 3877 * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional 3878 * 3879 * If maxwidth is not zero, the string will be filled at any middle marker 3880 * or truncated if too long, fillchar is used for all whitespace. 3881 */ 3882 int 3883 build_stl_str_hl( 3884 win_T *wp, 3885 char_u *out, /* buffer to write into != NameBuff */ 3886 size_t outlen, /* length of out[] */ 3887 char_u *fmt, 3888 int use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */ 3889 int fillchar, 3890 int maxwidth, 3891 struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */ 3892 struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */ 3893 { 3894 linenr_T lnum; 3895 size_t len; 3896 char_u *p; 3897 char_u *s; 3898 char_u *t; 3899 int byteval; 3900 #ifdef FEAT_EVAL 3901 win_T *save_curwin; 3902 buf_T *save_curbuf; 3903 #endif 3904 int empty_line; 3905 colnr_T virtcol; 3906 long l; 3907 long n; 3908 int prevchar_isflag; 3909 int prevchar_isitem; 3910 int itemisflag; 3911 int fillable; 3912 char_u *str; 3913 long num; 3914 int width; 3915 int itemcnt; 3916 int curitem; 3917 int group_end_userhl; 3918 int group_start_userhl; 3919 int groupitem[STL_MAX_ITEM]; 3920 int groupdepth; 3921 struct stl_item 3922 { 3923 char_u *start; 3924 int minwid; 3925 int maxwid; 3926 enum 3927 { 3928 Normal, 3929 Empty, 3930 Group, 3931 Middle, 3932 Highlight, 3933 TabPage, 3934 Trunc 3935 } type; 3936 } item[STL_MAX_ITEM]; 3937 int minwid; 3938 int maxwid; 3939 int zeropad; 3940 char_u base; 3941 char_u opt; 3942 #define TMPLEN 70 3943 char_u buf_tmp[TMPLEN]; 3944 char_u win_tmp[TMPLEN]; 3945 char_u *usefmt = fmt; 3946 struct stl_hlrec *sp; 3947 int save_must_redraw = must_redraw; 3948 int save_redr_type = curwin->w_redr_type; 3949 3950 #ifdef FEAT_EVAL 3951 /* 3952 * When the format starts with "%!" then evaluate it as an expression and 3953 * use the result as the actual format string. 3954 */ 3955 if (fmt[0] == '%' && fmt[1] == '!') 3956 { 3957 typval_T tv; 3958 3959 tv.v_type = VAR_NUMBER; 3960 tv.vval.v_number = wp->w_id; 3961 set_var((char_u *)"g:statusline_winid", &tv, FALSE); 3962 3963 usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); 3964 if (usefmt == NULL) 3965 usefmt = fmt; 3966 3967 do_unlet((char_u *)"g:statusline_winid", TRUE); 3968 } 3969 #endif 3970 3971 if (fillchar == 0) 3972 fillchar = ' '; 3973 /* Can't handle a multi-byte fill character yet. */ 3974 else if (mb_char2len(fillchar) > 1) 3975 fillchar = '-'; 3976 3977 // The cursor in windows other than the current one isn't always 3978 // up-to-date, esp. because of autocommands and timers. 3979 lnum = wp->w_cursor.lnum; 3980 if (lnum > wp->w_buffer->b_ml.ml_line_count) 3981 { 3982 lnum = wp->w_buffer->b_ml.ml_line_count; 3983 wp->w_cursor.lnum = lnum; 3984 } 3985 3986 // Get line & check if empty (cursorpos will show "0-1"). Note that 3987 // p will become invalid when getting another buffer line. 3988 p = ml_get_buf(wp->w_buffer, lnum, FALSE); 3989 empty_line = (*p == NUL); 3990 3991 // Get the byte value now, in case we need it below. This is more efficient 3992 // than making a copy of the line. 3993 len = STRLEN(p); 3994 if (wp->w_cursor.col > (colnr_T)len) 3995 { 3996 // Line may have changed since checking the cursor column, or the lnum 3997 // was adjusted above. 3998 wp->w_cursor.col = (colnr_T)len; 3999 wp->w_cursor.coladd = 0; 4000 byteval = 0; 4001 } 4002 else 4003 byteval = (*mb_ptr2char)(p + wp->w_cursor.col); 4004 4005 groupdepth = 0; 4006 p = out; 4007 curitem = 0; 4008 prevchar_isflag = TRUE; 4009 prevchar_isitem = FALSE; 4010 for (s = usefmt; *s; ) 4011 { 4012 if (curitem == STL_MAX_ITEM) 4013 { 4014 /* There are too many items. Add the error code to the statusline 4015 * to give the user a hint about what went wrong. */ 4016 if (p + 6 < out + outlen) 4017 { 4018 mch_memmove(p, " E541", (size_t)5); 4019 p += 5; 4020 } 4021 break; 4022 } 4023 4024 if (*s != NUL && *s != '%') 4025 prevchar_isflag = prevchar_isitem = FALSE; 4026 4027 /* 4028 * Handle up to the next '%' or the end. 4029 */ 4030 while (*s != NUL && *s != '%' && p + 1 < out + outlen) 4031 *p++ = *s++; 4032 if (*s == NUL || p + 1 >= out + outlen) 4033 break; 4034 4035 /* 4036 * Handle one '%' item. 4037 */ 4038 s++; 4039 if (*s == NUL) /* ignore trailing % */ 4040 break; 4041 if (*s == '%') 4042 { 4043 if (p + 1 >= out + outlen) 4044 break; 4045 *p++ = *s++; 4046 prevchar_isflag = prevchar_isitem = FALSE; 4047 continue; 4048 } 4049 if (*s == STL_MIDDLEMARK) 4050 { 4051 s++; 4052 if (groupdepth > 0) 4053 continue; 4054 item[curitem].type = Middle; 4055 item[curitem++].start = p; 4056 continue; 4057 } 4058 if (*s == STL_TRUNCMARK) 4059 { 4060 s++; 4061 item[curitem].type = Trunc; 4062 item[curitem++].start = p; 4063 continue; 4064 } 4065 if (*s == ')') 4066 { 4067 s++; 4068 if (groupdepth < 1) 4069 continue; 4070 groupdepth--; 4071 4072 t = item[groupitem[groupdepth]].start; 4073 *p = NUL; 4074 l = vim_strsize(t); 4075 if (curitem > groupitem[groupdepth] + 1 4076 && item[groupitem[groupdepth]].minwid == 0) 4077 { 4078 /* remove group if all items are empty and highlight group 4079 * doesn't change */ 4080 group_start_userhl = group_end_userhl = 0; 4081 for (n = groupitem[groupdepth] - 1; n >= 0; n--) 4082 { 4083 if (item[n].type == Highlight) 4084 { 4085 group_start_userhl = group_end_userhl = item[n].minwid; 4086 break; 4087 } 4088 } 4089 for (n = groupitem[groupdepth] + 1; n < curitem; n++) 4090 { 4091 if (item[n].type == Normal) 4092 break; 4093 if (item[n].type == Highlight) 4094 group_end_userhl = item[n].minwid; 4095 } 4096 if (n == curitem && group_start_userhl == group_end_userhl) 4097 { 4098 p = t; 4099 l = 0; 4100 } 4101 } 4102 if (l > item[groupitem[groupdepth]].maxwid) 4103 { 4104 /* truncate, remove n bytes of text at the start */ 4105 if (has_mbyte) 4106 { 4107 /* Find the first character that should be included. */ 4108 n = 0; 4109 while (l >= item[groupitem[groupdepth]].maxwid) 4110 { 4111 l -= ptr2cells(t + n); 4112 n += (*mb_ptr2len)(t + n); 4113 } 4114 } 4115 else 4116 n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1; 4117 4118 *t = '<'; 4119 mch_memmove(t + 1, t + n, (size_t)(p - (t + n))); 4120 p = p - n + 1; 4121 4122 // Fill up space left over by half a double-wide char. 4123 while (++l < item[groupitem[groupdepth]].minwid) 4124 *p++ = fillchar; 4125 4126 /* correct the start of the items for the truncation */ 4127 for (l = groupitem[groupdepth] + 1; l < curitem; l++) 4128 { 4129 item[l].start -= n; 4130 if (item[l].start < t) 4131 item[l].start = t; 4132 } 4133 } 4134 else if (abs(item[groupitem[groupdepth]].minwid) > l) 4135 { 4136 /* fill */ 4137 n = item[groupitem[groupdepth]].minwid; 4138 if (n < 0) 4139 { 4140 /* fill by appending characters */ 4141 n = 0 - n; 4142 while (l++ < n && p + 1 < out + outlen) 4143 *p++ = fillchar; 4144 } 4145 else 4146 { 4147 /* fill by inserting characters */ 4148 mch_memmove(t + n - l, t, (size_t)(p - t)); 4149 l = n - l; 4150 if (p + l >= out + outlen) 4151 l = (long)((out + outlen) - p - 1); 4152 p += l; 4153 for (n = groupitem[groupdepth] + 1; n < curitem; n++) 4154 item[n].start += l; 4155 for ( ; l > 0; l--) 4156 *t++ = fillchar; 4157 } 4158 } 4159 continue; 4160 } 4161 minwid = 0; 4162 maxwid = 9999; 4163 zeropad = FALSE; 4164 l = 1; 4165 if (*s == '0') 4166 { 4167 s++; 4168 zeropad = TRUE; 4169 } 4170 if (*s == '-') 4171 { 4172 s++; 4173 l = -1; 4174 } 4175 if (VIM_ISDIGIT(*s)) 4176 { 4177 minwid = (int)getdigits(&s); 4178 if (minwid < 0) /* overflow */ 4179 minwid = 0; 4180 } 4181 if (*s == STL_USER_HL) 4182 { 4183 item[curitem].type = Highlight; 4184 item[curitem].start = p; 4185 item[curitem].minwid = minwid > 9 ? 1 : minwid; 4186 s++; 4187 curitem++; 4188 continue; 4189 } 4190 if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR) 4191 { 4192 if (*s == STL_TABCLOSENR) 4193 { 4194 if (minwid == 0) 4195 { 4196 /* %X ends the close label, go back to the previously 4197 * define tab label nr. */ 4198 for (n = curitem - 1; n >= 0; --n) 4199 if (item[n].type == TabPage && item[n].minwid >= 0) 4200 { 4201 minwid = item[n].minwid; 4202 break; 4203 } 4204 } 4205 else 4206 /* close nrs are stored as negative values */ 4207 minwid = - minwid; 4208 } 4209 item[curitem].type = TabPage; 4210 item[curitem].start = p; 4211 item[curitem].minwid = minwid; 4212 s++; 4213 curitem++; 4214 continue; 4215 } 4216 if (*s == '.') 4217 { 4218 s++; 4219 if (VIM_ISDIGIT(*s)) 4220 { 4221 maxwid = (int)getdigits(&s); 4222 if (maxwid <= 0) /* overflow */ 4223 maxwid = 50; 4224 } 4225 } 4226 minwid = (minwid > 50 ? 50 : minwid) * l; 4227 if (*s == '(') 4228 { 4229 groupitem[groupdepth++] = curitem; 4230 item[curitem].type = Group; 4231 item[curitem].start = p; 4232 item[curitem].minwid = minwid; 4233 item[curitem].maxwid = maxwid; 4234 s++; 4235 curitem++; 4236 continue; 4237 } 4238 if (vim_strchr(STL_ALL, *s) == NULL) 4239 { 4240 s++; 4241 continue; 4242 } 4243 opt = *s++; 4244 4245 /* OK - now for the real work */ 4246 base = 'D'; 4247 itemisflag = FALSE; 4248 fillable = TRUE; 4249 num = -1; 4250 str = NULL; 4251 switch (opt) 4252 { 4253 case STL_FILEPATH: 4254 case STL_FULLPATH: 4255 case STL_FILENAME: 4256 fillable = FALSE; /* don't change ' ' to fillchar */ 4257 if (buf_spname(wp->w_buffer) != NULL) 4258 vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1); 4259 else 4260 { 4261 t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname 4262 : wp->w_buffer->b_fname; 4263 home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); 4264 } 4265 trans_characters(NameBuff, MAXPATHL); 4266 if (opt != STL_FILENAME) 4267 str = NameBuff; 4268 else 4269 str = gettail(NameBuff); 4270 break; 4271 4272 case STL_VIM_EXPR: /* '{' */ 4273 itemisflag = TRUE; 4274 t = p; 4275 while (*s != '}' && *s != NUL && p + 1 < out + outlen) 4276 *p++ = *s++; 4277 if (*s != '}') /* missing '}' or out of space */ 4278 break; 4279 s++; 4280 *p = 0; 4281 p = t; 4282 4283 #ifdef FEAT_EVAL 4284 vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), 4285 "%d", curbuf->b_fnum); 4286 set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp); 4287 vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id); 4288 set_internal_string_var((char_u *)"g:actual_curwin", win_tmp); 4289 4290 save_curbuf = curbuf; 4291 save_curwin = curwin; 4292 curwin = wp; 4293 curbuf = wp->w_buffer; 4294 4295 str = eval_to_string_safe(p, &t, use_sandbox); 4296 4297 curwin = save_curwin; 4298 curbuf = save_curbuf; 4299 do_unlet((char_u *)"g:actual_curbuf", TRUE); 4300 do_unlet((char_u *)"g:actual_curwin", TRUE); 4301 4302 if (str != NULL && *str != 0) 4303 { 4304 if (*skipdigits(str) == NUL) 4305 { 4306 num = atoi((char *)str); 4307 VIM_CLEAR(str); 4308 itemisflag = FALSE; 4309 } 4310 } 4311 #endif 4312 break; 4313 4314 case STL_LINE: 4315 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) 4316 ? 0L : (long)(wp->w_cursor.lnum); 4317 break; 4318 4319 case STL_NUMLINES: 4320 num = wp->w_buffer->b_ml.ml_line_count; 4321 break; 4322 4323 case STL_COLUMN: 4324 num = !(State & INSERT) && empty_line 4325 ? 0 : (int)wp->w_cursor.col + 1; 4326 break; 4327 4328 case STL_VIRTCOL: 4329 case STL_VIRTCOL_ALT: 4330 /* In list mode virtcol needs to be recomputed */ 4331 virtcol = wp->w_virtcol; 4332 if (wp->w_p_list && lcs_tab1 == NUL) 4333 { 4334 wp->w_p_list = FALSE; 4335 getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); 4336 wp->w_p_list = TRUE; 4337 } 4338 ++virtcol; 4339 /* Don't display %V if it's the same as %c. */ 4340 if (opt == STL_VIRTCOL_ALT 4341 && (virtcol == (colnr_T)(!(State & INSERT) && empty_line 4342 ? 0 : (int)wp->w_cursor.col + 1))) 4343 break; 4344 num = (long)virtcol; 4345 break; 4346 4347 case STL_PERCENTAGE: 4348 num = (int)(((long)wp->w_cursor.lnum * 100L) / 4349 (long)wp->w_buffer->b_ml.ml_line_count); 4350 break; 4351 4352 case STL_ALTPERCENT: 4353 str = buf_tmp; 4354 get_rel_pos(wp, str, TMPLEN); 4355 break; 4356 4357 case STL_ARGLISTSTAT: 4358 fillable = FALSE; 4359 buf_tmp[0] = 0; 4360 if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE)) 4361 str = buf_tmp; 4362 break; 4363 4364 case STL_KEYMAP: 4365 fillable = FALSE; 4366 if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN)) 4367 str = buf_tmp; 4368 break; 4369 case STL_PAGENUM: 4370 #if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE) 4371 num = printer_page_num; 4372 #else 4373 num = 0; 4374 #endif 4375 break; 4376 4377 case STL_BUFNO: 4378 num = wp->w_buffer->b_fnum; 4379 break; 4380 4381 case STL_OFFSET_X: 4382 base = 'X'; 4383 /* FALLTHROUGH */ 4384 case STL_OFFSET: 4385 #ifdef FEAT_BYTEOFF 4386 l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); 4387 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? 4388 0L : l + 1 + (!(State & INSERT) && empty_line ? 4389 0 : (int)wp->w_cursor.col); 4390 #endif 4391 break; 4392 4393 case STL_BYTEVAL_X: 4394 base = 'X'; 4395 /* FALLTHROUGH */ 4396 case STL_BYTEVAL: 4397 num = byteval; 4398 if (num == NL) 4399 num = 0; 4400 else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC) 4401 num = NL; 4402 break; 4403 4404 case STL_ROFLAG: 4405 case STL_ROFLAG_ALT: 4406 itemisflag = TRUE; 4407 if (wp->w_buffer->b_p_ro) 4408 str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]")); 4409 break; 4410 4411 case STL_HELPFLAG: 4412 case STL_HELPFLAG_ALT: 4413 itemisflag = TRUE; 4414 if (wp->w_buffer->b_help) 4415 str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP" 4416 : _("[Help]")); 4417 break; 4418 4419 case STL_FILETYPE: 4420 if (*wp->w_buffer->b_p_ft != NUL 4421 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) 4422 { 4423 vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]", 4424 wp->w_buffer->b_p_ft); 4425 str = buf_tmp; 4426 } 4427 break; 4428 4429 case STL_FILETYPE_ALT: 4430 itemisflag = TRUE; 4431 if (*wp->w_buffer->b_p_ft != NUL 4432 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) 4433 { 4434 vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s", 4435 wp->w_buffer->b_p_ft); 4436 for (t = buf_tmp; *t != 0; t++) 4437 *t = TOUPPER_LOC(*t); 4438 str = buf_tmp; 4439 } 4440 break; 4441 4442 #if defined(FEAT_QUICKFIX) 4443 case STL_PREVIEWFLAG: 4444 case STL_PREVIEWFLAG_ALT: 4445 itemisflag = TRUE; 4446 if (wp->w_p_pvw) 4447 str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV" 4448 : _("[Preview]")); 4449 break; 4450 4451 case STL_QUICKFIX: 4452 if (bt_quickfix(wp->w_buffer)) 4453 str = (char_u *)(wp->w_llist_ref 4454 ? _(msg_loclist) 4455 : _(msg_qflist)); 4456 break; 4457 #endif 4458 4459 case STL_MODIFIED: 4460 case STL_MODIFIED_ALT: 4461 itemisflag = TRUE; 4462 switch ((opt == STL_MODIFIED_ALT) 4463 + bufIsChanged(wp->w_buffer) * 2 4464 + (!wp->w_buffer->b_p_ma) * 4) 4465 { 4466 case 2: str = (char_u *)"[+]"; break; 4467 case 3: str = (char_u *)",+"; break; 4468 case 4: str = (char_u *)"[-]"; break; 4469 case 5: str = (char_u *)",-"; break; 4470 case 6: str = (char_u *)"[+-]"; break; 4471 case 7: str = (char_u *)",+-"; break; 4472 } 4473 break; 4474 4475 case STL_HIGHLIGHT: 4476 t = s; 4477 while (*s != '#' && *s != NUL) 4478 ++s; 4479 if (*s == '#') 4480 { 4481 item[curitem].type = Highlight; 4482 item[curitem].start = p; 4483 item[curitem].minwid = -syn_namen2id(t, (int)(s - t)); 4484 curitem++; 4485 } 4486 if (*s != NUL) 4487 ++s; 4488 continue; 4489 } 4490 4491 item[curitem].start = p; 4492 item[curitem].type = Normal; 4493 if (str != NULL && *str) 4494 { 4495 t = str; 4496 if (itemisflag) 4497 { 4498 if ((t[0] && t[1]) 4499 && ((!prevchar_isitem && *t == ',') 4500 || (prevchar_isflag && *t == ' '))) 4501 t++; 4502 prevchar_isflag = TRUE; 4503 } 4504 l = vim_strsize(t); 4505 if (l > 0) 4506 prevchar_isitem = TRUE; 4507 if (l > maxwid) 4508 { 4509 while (l >= maxwid) 4510 if (has_mbyte) 4511 { 4512 l -= ptr2cells(t); 4513 t += (*mb_ptr2len)(t); 4514 } 4515 else 4516 l -= byte2cells(*t++); 4517 if (p + 1 >= out + outlen) 4518 break; 4519 *p++ = '<'; 4520 } 4521 if (minwid > 0) 4522 { 4523 for (; l < minwid && p + 1 < out + outlen; l++) 4524 { 4525 /* Don't put a "-" in front of a digit. */ 4526 if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t)) 4527 *p++ = ' '; 4528 else 4529 *p++ = fillchar; 4530 } 4531 minwid = 0; 4532 } 4533 else 4534 minwid *= -1; 4535 while (*t && p + 1 < out + outlen) 4536 { 4537 *p++ = *t++; 4538 /* Change a space by fillchar, unless fillchar is '-' and a 4539 * digit follows. */ 4540 if (fillable && p[-1] == ' ' 4541 && (!VIM_ISDIGIT(*t) || fillchar != '-')) 4542 p[-1] = fillchar; 4543 } 4544 for (; l < minwid && p + 1 < out + outlen; l++) 4545 *p++ = fillchar; 4546 } 4547 else if (num >= 0) 4548 { 4549 int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); 4550 char_u nstr[20]; 4551 4552 if (p + 20 >= out + outlen) 4553 break; /* not sufficient space */ 4554 prevchar_isitem = TRUE; 4555 t = nstr; 4556 if (opt == STL_VIRTCOL_ALT) 4557 { 4558 *t++ = '-'; 4559 minwid--; 4560 } 4561 *t++ = '%'; 4562 if (zeropad) 4563 *t++ = '0'; 4564 *t++ = '*'; 4565 *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); 4566 *t = 0; 4567 4568 for (n = num, l = 1; n >= nbase; n /= nbase) 4569 l++; 4570 if (opt == STL_VIRTCOL_ALT) 4571 l++; 4572 if (l > maxwid) 4573 { 4574 l += 2; 4575 n = l - maxwid; 4576 while (l-- > maxwid) 4577 num /= nbase; 4578 *t++ = '>'; 4579 *t++ = '%'; 4580 *t = t[-3]; 4581 *++t = 0; 4582 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, 4583 0, num, n); 4584 } 4585 else 4586 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, 4587 minwid, num); 4588 p += STRLEN(p); 4589 } 4590 else 4591 item[curitem].type = Empty; 4592 4593 if (opt == STL_VIM_EXPR) 4594 vim_free(str); 4595 4596 if (num >= 0 || (!itemisflag && str && *str)) 4597 prevchar_isflag = FALSE; /* Item not NULL, but not a flag */ 4598 curitem++; 4599 } 4600 *p = NUL; 4601 itemcnt = curitem; 4602 4603 #ifdef FEAT_EVAL 4604 if (usefmt != fmt) 4605 vim_free(usefmt); 4606 #endif 4607 4608 width = vim_strsize(out); 4609 if (maxwidth > 0 && width > maxwidth) 4610 { 4611 /* Result is too long, must truncate somewhere. */ 4612 l = 0; 4613 if (itemcnt == 0) 4614 s = out; 4615 else 4616 { 4617 for ( ; l < itemcnt; l++) 4618 if (item[l].type == Trunc) 4619 { 4620 /* Truncate at %< item. */ 4621 s = item[l].start; 4622 break; 4623 } 4624 if (l == itemcnt) 4625 { 4626 /* No %< item, truncate first item. */ 4627 s = item[0].start; 4628 l = 0; 4629 } 4630 } 4631 4632 if (width - vim_strsize(s) >= maxwidth) 4633 { 4634 /* Truncation mark is beyond max length */ 4635 if (has_mbyte) 4636 { 4637 s = out; 4638 width = 0; 4639 for (;;) 4640 { 4641 width += ptr2cells(s); 4642 if (width >= maxwidth) 4643 break; 4644 s += (*mb_ptr2len)(s); 4645 } 4646 /* Fill up for half a double-wide character. */ 4647 while (++width < maxwidth) 4648 *s++ = fillchar; 4649 } 4650 else 4651 s = out + maxwidth - 1; 4652 for (l = 0; l < itemcnt; l++) 4653 if (item[l].start > s) 4654 break; 4655 itemcnt = l; 4656 *s++ = '>'; 4657 *s = 0; 4658 } 4659 else 4660 { 4661 if (has_mbyte) 4662 { 4663 n = 0; 4664 while (width >= maxwidth) 4665 { 4666 width -= ptr2cells(s + n); 4667 n += (*mb_ptr2len)(s + n); 4668 } 4669 } 4670 else 4671 n = width - maxwidth + 1; 4672 p = s + n; 4673 STRMOVE(s + 1, p); 4674 *s = '<'; 4675 4676 /* Fill up for half a double-wide character. */ 4677 while (++width < maxwidth) 4678 { 4679 s = s + STRLEN(s); 4680 *s++ = fillchar; 4681 *s = NUL; 4682 } 4683 4684 --n; /* count the '<' */ 4685 for (; l < itemcnt; l++) 4686 { 4687 if (item[l].start - n >= s) 4688 item[l].start -= n; 4689 else 4690 item[l].start = s; 4691 } 4692 } 4693 width = maxwidth; 4694 } 4695 else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen) 4696 { 4697 /* Apply STL_MIDDLE if any */ 4698 for (l = 0; l < itemcnt; l++) 4699 if (item[l].type == Middle) 4700 break; 4701 if (l < itemcnt) 4702 { 4703 p = item[l].start + maxwidth - width; 4704 STRMOVE(p, item[l].start); 4705 for (s = item[l].start; s < p; s++) 4706 *s = fillchar; 4707 for (l++; l < itemcnt; l++) 4708 item[l].start += maxwidth - width; 4709 width = maxwidth; 4710 } 4711 } 4712 4713 /* Store the info about highlighting. */ 4714 if (hltab != NULL) 4715 { 4716 sp = hltab; 4717 for (l = 0; l < itemcnt; l++) 4718 { 4719 if (item[l].type == Highlight) 4720 { 4721 sp->start = item[l].start; 4722 sp->userhl = item[l].minwid; 4723 sp++; 4724 } 4725 } 4726 sp->start = NULL; 4727 sp->userhl = 0; 4728 } 4729 4730 /* Store the info about tab pages labels. */ 4731 if (tabtab != NULL) 4732 { 4733 sp = tabtab; 4734 for (l = 0; l < itemcnt; l++) 4735 { 4736 if (item[l].type == TabPage) 4737 { 4738 sp->start = item[l].start; 4739 sp->userhl = item[l].minwid; 4740 sp++; 4741 } 4742 } 4743 sp->start = NULL; 4744 sp->userhl = 0; 4745 } 4746 4747 /* When inside update_screen we do not want redrawing a stausline, ruler, 4748 * title, etc. to trigger another redraw, it may cause an endless loop. */ 4749 if (updating_screen) 4750 { 4751 must_redraw = save_must_redraw; 4752 curwin->w_redr_type = save_redr_type; 4753 } 4754 4755 return width; 4756 } 4757 #endif /* FEAT_STL_OPT */ 4758 4759 #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \ 4760 || defined(FEAT_GUI_TABLINE) || defined(PROTO) 4761 /* 4762 * Get relative cursor position in window into "buf[buflen]", in the form 99%, 4763 * using "Top", "Bot" or "All" when appropriate. 4764 */ 4765 void 4766 get_rel_pos( 4767 win_T *wp, 4768 char_u *buf, 4769 int buflen) 4770 { 4771 long above; /* number of lines above window */ 4772 long below; /* number of lines below window */ 4773 4774 if (buflen < 3) /* need at least 3 chars for writing */ 4775 return; 4776 above = wp->w_topline - 1; 4777 #ifdef FEAT_DIFF 4778 above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill; 4779 if (wp->w_topline == 1 && wp->w_topfill >= 1) 4780 above = 0; /* All buffer lines are displayed and there is an 4781 * indication of filler lines, that can be considered 4782 * seeing all lines. */ 4783 #endif 4784 below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; 4785 if (below <= 0) 4786 vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")), 4787 (size_t)(buflen - 1)); 4788 else if (above <= 0) 4789 vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1)); 4790 else 4791 vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L 4792 ? (int)(above / ((above + below) / 100L)) 4793 : (int)(above * 100L / (above + below))); 4794 } 4795 #endif 4796 4797 /* 4798 * Append (file 2 of 8) to "buf[buflen]", if editing more than one file. 4799 * Return TRUE if it was appended. 4800 */ 4801 static int 4802 append_arg_number( 4803 win_T *wp, 4804 char_u *buf, 4805 int buflen, 4806 int add_file) /* Add "file" before the arg number */ 4807 { 4808 char_u *p; 4809 4810 if (ARGCOUNT <= 1) /* nothing to do */ 4811 return FALSE; 4812 4813 p = buf + STRLEN(buf); /* go to the end of the buffer */ 4814 if (p - buf + 35 >= buflen) /* getting too long */ 4815 return FALSE; 4816 *p++ = ' '; 4817 *p++ = '('; 4818 if (add_file) 4819 { 4820 STRCPY(p, "file "); 4821 p += 5; 4822 } 4823 vim_snprintf((char *)p, (size_t)(buflen - (p - buf)), 4824 wp->w_arg_idx_invalid ? "(%d) of %d)" 4825 : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT); 4826 return TRUE; 4827 } 4828 4829 /* 4830 * If fname is not a full path, make it a full path. 4831 * Returns pointer to allocated memory (NULL for failure). 4832 */ 4833 char_u * 4834 fix_fname(char_u *fname) 4835 { 4836 /* 4837 * Force expanding the path always for Unix, because symbolic links may 4838 * mess up the full path name, even though it starts with a '/'. 4839 * Also expand when there is ".." in the file name, try to remove it, 4840 * because "c:/src/../README" is equal to "c:/README". 4841 * Similarly "c:/src//file" is equal to "c:/src/file". 4842 * For MS-Windows also expand names like "longna~1" to "longname". 4843 */ 4844 #ifdef UNIX 4845 return FullName_save(fname, TRUE); 4846 #else 4847 if (!vim_isAbsName(fname) 4848 || strstr((char *)fname, "..") != NULL 4849 || strstr((char *)fname, "//") != NULL 4850 # ifdef BACKSLASH_IN_FILENAME 4851 || strstr((char *)fname, "\\\\") != NULL 4852 # endif 4853 # if defined(MSWIN) 4854 || vim_strchr(fname, '~') != NULL 4855 # endif 4856 ) 4857 return FullName_save(fname, FALSE); 4858 4859 fname = vim_strsave(fname); 4860 4861 # ifdef USE_FNAME_CASE 4862 if (fname != NULL) 4863 fname_case(fname, 0); /* set correct case for file name */ 4864 # endif 4865 4866 return fname; 4867 #endif 4868 } 4869 4870 /* 4871 * Make "*ffname" a full file name, set "*sfname" to "*ffname" if not NULL. 4872 * "*ffname" becomes a pointer to allocated memory (or NULL). 4873 * When resolving a link both "*sfname" and "*ffname" will point to the same 4874 * allocated memory. 4875 * The "*ffname" and "*sfname" pointer values on call will not be freed. 4876 * Note that the resulting "*ffname" pointer should be considered not allocaed. 4877 */ 4878 void 4879 fname_expand( 4880 buf_T *buf UNUSED, 4881 char_u **ffname, 4882 char_u **sfname) 4883 { 4884 if (*ffname == NULL) // no file name given, nothing to do 4885 return; 4886 if (*sfname == NULL) // no short file name given, use ffname 4887 *sfname = *ffname; 4888 *ffname = fix_fname(*ffname); // expand to full path 4889 4890 #ifdef FEAT_SHORTCUT 4891 if (!buf->b_p_bin) 4892 { 4893 char_u *rfname; 4894 4895 // If the file name is a shortcut file, use the file it links to. 4896 rfname = mch_resolve_path(*ffname, FALSE); 4897 if (rfname != NULL) 4898 { 4899 vim_free(*ffname); 4900 *ffname = rfname; 4901 *sfname = rfname; 4902 } 4903 } 4904 #endif 4905 } 4906 4907 /* 4908 * Open a window for a number of buffers. 4909 */ 4910 void 4911 ex_buffer_all(exarg_T *eap) 4912 { 4913 buf_T *buf; 4914 win_T *wp, *wpnext; 4915 int split_ret = OK; 4916 int p_ea_save; 4917 int open_wins = 0; 4918 int r; 4919 int count; /* Maximum number of windows to open. */ 4920 int all; /* When TRUE also load inactive buffers. */ 4921 int had_tab = cmdmod.tab; 4922 tabpage_T *tpnext; 4923 4924 if (eap->addr_count == 0) /* make as many windows as possible */ 4925 count = 9999; 4926 else 4927 count = eap->line2; /* make as many windows as specified */ 4928 if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide) 4929 all = FALSE; 4930 else 4931 all = TRUE; 4932 4933 setpcmark(); 4934 4935 #ifdef FEAT_GUI 4936 need_mouse_correct = TRUE; 4937 #endif 4938 4939 /* 4940 * Close superfluous windows (two windows for the same buffer). 4941 * Also close windows that are not full-width. 4942 */ 4943 if (had_tab > 0) 4944 goto_tabpage_tp(first_tabpage, TRUE, TRUE); 4945 for (;;) 4946 { 4947 tpnext = curtab->tp_next; 4948 for (wp = firstwin; wp != NULL; wp = wpnext) 4949 { 4950 wpnext = wp->w_next; 4951 if ((wp->w_buffer->b_nwindows > 1 4952 || ((cmdmod.split & WSP_VERT) 4953 ? wp->w_height + wp->w_status_height < Rows - p_ch 4954 - tabline_height() 4955 : wp->w_width != Columns) 4956 || (had_tab > 0 && wp != firstwin)) && !ONE_WINDOW 4957 && !(wp->w_closing || wp->w_buffer->b_locked > 0)) 4958 { 4959 win_close(wp, FALSE); 4960 wpnext = firstwin; /* just in case an autocommand does 4961 something strange with windows */ 4962 tpnext = first_tabpage; /* start all over... */ 4963 open_wins = 0; 4964 } 4965 else 4966 ++open_wins; 4967 } 4968 4969 /* Without the ":tab" modifier only do the current tab page. */ 4970 if (had_tab == 0 || tpnext == NULL) 4971 break; 4972 goto_tabpage_tp(tpnext, TRUE, TRUE); 4973 } 4974 4975 /* 4976 * Go through the buffer list. When a buffer doesn't have a window yet, 4977 * open one. Otherwise move the window to the right position. 4978 * Watch out for autocommands that delete buffers or windows! 4979 */ 4980 /* Don't execute Win/Buf Enter/Leave autocommands here. */ 4981 ++autocmd_no_enter; 4982 win_enter(lastwin, FALSE); 4983 ++autocmd_no_leave; 4984 for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) 4985 { 4986 /* Check if this buffer needs a window */ 4987 if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl) 4988 continue; 4989 4990 if (had_tab != 0) 4991 { 4992 /* With the ":tab" modifier don't move the window. */ 4993 if (buf->b_nwindows > 0) 4994 wp = lastwin; /* buffer has a window, skip it */ 4995 else 4996 wp = NULL; 4997 } 4998 else 4999 { 5000 /* Check if this buffer already has a window */ 5001 FOR_ALL_WINDOWS(wp) 5002 if (wp->w_buffer == buf) 5003 break; 5004 /* If the buffer already has a window, move it */ 5005 if (wp != NULL) 5006 win_move_after(wp, curwin); 5007 } 5008 5009 if (wp == NULL && split_ret == OK) 5010 { 5011 bufref_T bufref; 5012 5013 set_bufref(&bufref, buf); 5014 5015 /* Split the window and put the buffer in it */ 5016 p_ea_save = p_ea; 5017 p_ea = TRUE; /* use space from all windows */ 5018 split_ret = win_split(0, WSP_ROOM | WSP_BELOW); 5019 ++open_wins; 5020 p_ea = p_ea_save; 5021 if (split_ret == FAIL) 5022 continue; 5023 5024 /* Open the buffer in this window. */ 5025 swap_exists_action = SEA_DIALOG; 5026 set_curbuf(buf, DOBUF_GOTO); 5027 if (!bufref_valid(&bufref)) 5028 { 5029 /* autocommands deleted the buffer!!! */ 5030 swap_exists_action = SEA_NONE; 5031 break; 5032 } 5033 if (swap_exists_action == SEA_QUIT) 5034 { 5035 #if defined(FEAT_EVAL) 5036 cleanup_T cs; 5037 5038 /* Reset the error/interrupt/exception state here so that 5039 * aborting() returns FALSE when closing a window. */ 5040 enter_cleanup(&cs); 5041 #endif 5042 5043 /* User selected Quit at ATTENTION prompt; close this window. */ 5044 win_close(curwin, TRUE); 5045 --open_wins; 5046 swap_exists_action = SEA_NONE; 5047 swap_exists_did_quit = TRUE; 5048 5049 #if defined(FEAT_EVAL) 5050 /* Restore the error/interrupt/exception state if not 5051 * discarded by a new aborting error, interrupt, or uncaught 5052 * exception. */ 5053 leave_cleanup(&cs); 5054 #endif 5055 } 5056 else 5057 handle_swap_exists(NULL); 5058 } 5059 5060 ui_breakcheck(); 5061 if (got_int) 5062 { 5063 (void)vgetc(); /* only break the file loading, not the rest */ 5064 break; 5065 } 5066 #ifdef FEAT_EVAL 5067 /* Autocommands deleted the buffer or aborted script processing!!! */ 5068 if (aborting()) 5069 break; 5070 #endif 5071 /* When ":tab" was used open a new tab for a new window repeatedly. */ 5072 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) 5073 cmdmod.tab = 9999; 5074 } 5075 --autocmd_no_enter; 5076 win_enter(firstwin, FALSE); /* back to first window */ 5077 --autocmd_no_leave; 5078 5079 /* 5080 * Close superfluous windows. 5081 */ 5082 for (wp = lastwin; open_wins > count; ) 5083 { 5084 r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer) 5085 || autowrite(wp->w_buffer, FALSE) == OK); 5086 if (!win_valid(wp)) 5087 { 5088 /* BufWrite Autocommands made the window invalid, start over */ 5089 wp = lastwin; 5090 } 5091 else if (r) 5092 { 5093 win_close(wp, !buf_hide(wp->w_buffer)); 5094 --open_wins; 5095 wp = lastwin; 5096 } 5097 else 5098 { 5099 wp = wp->w_prev; 5100 if (wp == NULL) 5101 break; 5102 } 5103 } 5104 } 5105 5106 5107 static int chk_modeline(linenr_T, int); 5108 5109 /* 5110 * do_modelines() - process mode lines for the current file 5111 * 5112 * "flags" can be: 5113 * OPT_WINONLY only set options local to window 5114 * OPT_NOWIN don't set options local to window 5115 * 5116 * Returns immediately if the "ml" option isn't set. 5117 */ 5118 void 5119 do_modelines(int flags) 5120 { 5121 linenr_T lnum; 5122 int nmlines; 5123 static int entered = 0; 5124 5125 if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0) 5126 return; 5127 5128 /* Disallow recursive entry here. Can happen when executing a modeline 5129 * triggers an autocommand, which reloads modelines with a ":do". */ 5130 if (entered) 5131 return; 5132 5133 ++entered; 5134 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines; 5135 ++lnum) 5136 if (chk_modeline(lnum, flags) == FAIL) 5137 nmlines = 0; 5138 5139 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines 5140 && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum) 5141 if (chk_modeline(lnum, flags) == FAIL) 5142 nmlines = 0; 5143 --entered; 5144 } 5145 5146 #include "version.h" /* for version number */ 5147 5148 /* 5149 * chk_modeline() - check a single line for a mode string 5150 * Return FAIL if an error encountered. 5151 */ 5152 static int 5153 chk_modeline( 5154 linenr_T lnum, 5155 int flags) /* Same as for do_modelines(). */ 5156 { 5157 char_u *s; 5158 char_u *e; 5159 char_u *linecopy; /* local copy of any modeline found */ 5160 int prev; 5161 int vers; 5162 int end; 5163 int retval = OK; 5164 char_u *save_sourcing_name; 5165 linenr_T save_sourcing_lnum; 5166 #ifdef FEAT_EVAL 5167 sctx_T save_current_sctx; 5168 #endif 5169 5170 prev = -1; 5171 for (s = ml_get(lnum); *s != NUL; ++s) 5172 { 5173 if (prev == -1 || vim_isspace(prev)) 5174 { 5175 if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) 5176 || STRNCMP(s, "vi:", (size_t)3) == 0) 5177 break; 5178 /* Accept both "vim" and "Vim". */ 5179 if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') 5180 { 5181 if (s[3] == '<' || s[3] == '=' || s[3] == '>') 5182 e = s + 4; 5183 else 5184 e = s + 3; 5185 vers = getdigits(&e); 5186 if (*e == ':' 5187 && (s[0] != 'V' 5188 || STRNCMP(skipwhite(e + 1), "set", 3) == 0) 5189 && (s[3] == ':' 5190 || (VIM_VERSION_100 >= vers && isdigit(s[3])) 5191 || (VIM_VERSION_100 < vers && s[3] == '<') 5192 || (VIM_VERSION_100 > vers && s[3] == '>') 5193 || (VIM_VERSION_100 == vers && s[3] == '='))) 5194 break; 5195 } 5196 } 5197 prev = *s; 5198 } 5199 5200 if (*s) 5201 { 5202 do /* skip over "ex:", "vi:" or "vim:" */ 5203 ++s; 5204 while (s[-1] != ':'); 5205 5206 s = linecopy = vim_strsave(s); /* copy the line, it will change */ 5207 if (linecopy == NULL) 5208 return FAIL; 5209 5210 save_sourcing_lnum = sourcing_lnum; 5211 save_sourcing_name = sourcing_name; 5212 sourcing_lnum = lnum; /* prepare for emsg() */ 5213 sourcing_name = (char_u *)"modelines"; 5214 5215 end = FALSE; 5216 while (end == FALSE) 5217 { 5218 s = skipwhite(s); 5219 if (*s == NUL) 5220 break; 5221 5222 /* 5223 * Find end of set command: ':' or end of line. 5224 * Skip over "\:", replacing it with ":". 5225 */ 5226 for (e = s; *e != ':' && *e != NUL; ++e) 5227 if (e[0] == '\\' && e[1] == ':') 5228 STRMOVE(e, e + 1); 5229 if (*e == NUL) 5230 end = TRUE; 5231 5232 /* 5233 * If there is a "set" command, require a terminating ':' and 5234 * ignore the stuff after the ':'. 5235 * "vi:set opt opt opt: foo" -- foo not interpreted 5236 * "vi:opt opt opt: foo" -- foo interpreted 5237 * Accept "se" for compatibility with Elvis. 5238 */ 5239 if (STRNCMP(s, "set ", (size_t)4) == 0 5240 || STRNCMP(s, "se ", (size_t)3) == 0) 5241 { 5242 if (*e != ':') /* no terminating ':'? */ 5243 break; 5244 end = TRUE; 5245 s = vim_strchr(s, ' ') + 1; 5246 } 5247 *e = NUL; /* truncate the set command */ 5248 5249 if (*s != NUL) /* skip over an empty "::" */ 5250 { 5251 int secure_save = secure; 5252 #ifdef FEAT_EVAL 5253 save_current_sctx = current_sctx; 5254 current_sctx.sc_sid = SID_MODELINE; 5255 current_sctx.sc_seq = 0; 5256 current_sctx.sc_lnum = 0; 5257 current_sctx.sc_version = 1; 5258 #endif 5259 // Make sure no risky things are executed as a side effect. 5260 secure = 1; 5261 5262 retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); 5263 5264 secure = secure_save; 5265 #ifdef FEAT_EVAL 5266 current_sctx = save_current_sctx; 5267 #endif 5268 if (retval == FAIL) /* stop if error found */ 5269 break; 5270 } 5271 s = e + 1; /* advance to next part */ 5272 } 5273 5274 sourcing_lnum = save_sourcing_lnum; 5275 sourcing_name = save_sourcing_name; 5276 5277 vim_free(linecopy); 5278 } 5279 return retval; 5280 } 5281 5282 /* 5283 * Return TRUE if "buf" is a normal buffer, 'buftype' is empty. 5284 */ 5285 int 5286 bt_normal(buf_T *buf) 5287 { 5288 return buf != NULL && buf->b_p_bt[0] == NUL; 5289 } 5290 5291 #if defined(FEAT_QUICKFIX) || defined(PROTO) 5292 /* 5293 * Return TRUE if "buf" is the quickfix buffer. 5294 */ 5295 int 5296 bt_quickfix(buf_T *buf) 5297 { 5298 return buf != NULL && buf->b_p_bt[0] == 'q'; 5299 } 5300 #endif 5301 5302 #if defined(FEAT_TERMINAL) || defined(PROTO) 5303 /* 5304 * Return TRUE if "buf" is a terminal buffer. 5305 */ 5306 int 5307 bt_terminal(buf_T *buf) 5308 { 5309 return buf != NULL && buf->b_p_bt[0] == 't'; 5310 } 5311 #endif 5312 5313 /* 5314 * Return TRUE if "buf" is a help buffer. 5315 */ 5316 int 5317 bt_help(buf_T *buf) 5318 { 5319 return buf != NULL && buf->b_help; 5320 } 5321 5322 /* 5323 * Return TRUE if "buf" is a prompt buffer. 5324 */ 5325 int 5326 bt_prompt(buf_T *buf) 5327 { 5328 return buf != NULL && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'r'; 5329 } 5330 5331 /* 5332 * Return TRUE if "buf" is a buffer for a popup window. 5333 */ 5334 int 5335 bt_popup(buf_T *buf) 5336 { 5337 return buf != NULL && buf->b_p_bt != NULL 5338 && buf->b_p_bt[0] == 'p' && buf->b_p_bt[1] == 'o'; 5339 } 5340 5341 /* 5342 * Return TRUE if "buf" is a "nofile", "acwrite", "terminal" or "prompt" 5343 * buffer. This means the buffer name is not a file name. 5344 */ 5345 int 5346 bt_nofilename(buf_T *buf) 5347 { 5348 return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') 5349 || buf->b_p_bt[0] == 'a' 5350 || buf->b_p_bt[0] == 't' 5351 || buf->b_p_bt[0] == 'p'); 5352 } 5353 5354 /* 5355 * Return TRUE if "buf" has 'buftype' set to "nofile". 5356 */ 5357 int 5358 bt_nofile(buf_T *buf) 5359 { 5360 return buf != NULL && buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f'; 5361 } 5362 5363 /* 5364 * Return TRUE if "buf" is a "nowrite", "nofile", "terminal" or "prompt" 5365 * buffer. 5366 */ 5367 int 5368 bt_dontwrite(buf_T *buf) 5369 { 5370 return buf != NULL && (buf->b_p_bt[0] == 'n' 5371 || buf->b_p_bt[0] == 't' 5372 || buf->b_p_bt[0] == 'p'); 5373 } 5374 5375 #if defined(FEAT_QUICKFIX) || defined(PROTO) 5376 int 5377 bt_dontwrite_msg(buf_T *buf) 5378 { 5379 if (bt_dontwrite(buf)) 5380 { 5381 emsg(_("E382: Cannot write, 'buftype' option is set")); 5382 return TRUE; 5383 } 5384 return FALSE; 5385 } 5386 #endif 5387 5388 /* 5389 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" 5390 * and 'bufhidden'. 5391 */ 5392 int 5393 buf_hide(buf_T *buf) 5394 { 5395 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ 5396 switch (buf->b_p_bh[0]) 5397 { 5398 case 'u': /* "unload" */ 5399 case 'w': /* "wipe" */ 5400 case 'd': return FALSE; /* "delete" */ 5401 case 'h': return TRUE; /* "hide" */ 5402 } 5403 return (p_hid || cmdmod.hide); 5404 } 5405 5406 /* 5407 * Return special buffer name. 5408 * Returns NULL when the buffer has a normal file name. 5409 */ 5410 char_u * 5411 buf_spname(buf_T *buf) 5412 { 5413 #if defined(FEAT_QUICKFIX) 5414 if (bt_quickfix(buf)) 5415 { 5416 /* 5417 * Differentiate between the quickfix and location list buffers using 5418 * the buffer number stored in the global quickfix stack. 5419 */ 5420 if (buf->b_fnum == qf_stack_get_bufnr()) 5421 return (char_u *)_(msg_qflist); 5422 else 5423 return (char_u *)_(msg_loclist); 5424 } 5425 #endif 5426 5427 /* There is no _file_ when 'buftype' is "nofile", b_sfname 5428 * contains the name as specified by the user. */ 5429 if (bt_nofilename(buf)) 5430 { 5431 #ifdef FEAT_TERMINAL 5432 if (buf->b_term != NULL) 5433 return term_get_status_text(buf->b_term); 5434 #endif 5435 if (buf->b_fname != NULL) 5436 return buf->b_fname; 5437 #ifdef FEAT_JOB_CHANNEL 5438 if (bt_prompt(buf)) 5439 return (char_u *)_("[Prompt]"); 5440 #endif 5441 #ifdef FEAT_TEXT_PROP 5442 if (bt_popup(buf)) 5443 return (char_u *)_("[Popup]"); 5444 #endif 5445 return (char_u *)_("[Scratch]"); 5446 } 5447 5448 if (buf->b_fname == NULL) 5449 return (char_u *)_("[No Name]"); 5450 return NULL; 5451 } 5452 5453 /* 5454 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. 5455 */ 5456 void 5457 set_buflisted(int on) 5458 { 5459 if (on != curbuf->b_p_bl) 5460 { 5461 curbuf->b_p_bl = on; 5462 if (on) 5463 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf); 5464 else 5465 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf); 5466 } 5467 } 5468 5469 /* 5470 * Read the file for "buf" again and check if the contents changed. 5471 * Return TRUE if it changed or this could not be checked. 5472 */ 5473 int 5474 buf_contents_changed(buf_T *buf) 5475 { 5476 buf_T *newbuf; 5477 int differ = TRUE; 5478 linenr_T lnum; 5479 aco_save_T aco; 5480 exarg_T ea; 5481 5482 /* Allocate a buffer without putting it in the buffer list. */ 5483 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); 5484 if (newbuf == NULL) 5485 return TRUE; 5486 5487 /* Force the 'fileencoding' and 'fileformat' to be equal. */ 5488 if (prep_exarg(&ea, buf) == FAIL) 5489 { 5490 wipe_buffer(newbuf, FALSE); 5491 return TRUE; 5492 } 5493 5494 /* set curwin/curbuf to buf and save a few things */ 5495 aucmd_prepbuf(&aco, newbuf); 5496 5497 if (ml_open(curbuf) == OK 5498 && readfile(buf->b_ffname, buf->b_fname, 5499 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, 5500 &ea, READ_NEW | READ_DUMMY) == OK) 5501 { 5502 /* compare the two files line by line */ 5503 if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) 5504 { 5505 differ = FALSE; 5506 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) 5507 if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0) 5508 { 5509 differ = TRUE; 5510 break; 5511 } 5512 } 5513 } 5514 vim_free(ea.cmd); 5515 5516 /* restore curwin/curbuf and a few other things */ 5517 aucmd_restbuf(&aco); 5518 5519 if (curbuf != newbuf) /* safety check */ 5520 wipe_buffer(newbuf, FALSE); 5521 5522 return differ; 5523 } 5524 5525 /* 5526 * Wipe out a buffer and decrement the last buffer number if it was used for 5527 * this buffer. Call this to wipe out a temp buffer that does not contain any 5528 * marks. 5529 */ 5530 void 5531 wipe_buffer( 5532 buf_T *buf, 5533 int aucmd UNUSED) /* When TRUE trigger autocommands. */ 5534 { 5535 if (buf->b_fnum == top_file_num - 1) 5536 --top_file_num; 5537 5538 if (!aucmd) /* Don't trigger BufDelete autocommands here. */ 5539 block_autocmds(); 5540 5541 close_buffer(NULL, buf, DOBUF_WIPE, FALSE); 5542 5543 if (!aucmd) 5544 unblock_autocmds(); 5545 } 5546