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