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