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