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