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