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 else 3630 { 3631 p = transstr(gettail(curbuf->b_fname)); 3632 vim_strncpy(buf, p, SPACE_FOR_FNAME); 3633 vim_free(p); 3634 } 3635 3636 switch (bufIsChanged(curbuf) 3637 + (curbuf->b_p_ro * 2) 3638 + (!curbuf->b_p_ma * 4)) 3639 { 3640 case 1: STRCAT(buf, " +"); break; 3641 case 2: STRCAT(buf, " ="); break; 3642 case 3: STRCAT(buf, " =+"); break; 3643 case 4: 3644 case 6: STRCAT(buf, " -"); break; 3645 case 5: 3646 case 7: STRCAT(buf, " -+"); break; 3647 } 3648 3649 if (curbuf->b_fname != NULL) 3650 { 3651 /* Get path of file, replace home dir with ~ */ 3652 off = (int)STRLEN(buf); 3653 buf[off++] = ' '; 3654 buf[off++] = '('; 3655 home_replace(curbuf, curbuf->b_ffname, 3656 buf + off, SPACE_FOR_DIR - off, TRUE); 3657 #ifdef BACKSLASH_IN_FILENAME 3658 /* avoid "c:/name" to be reduced to "c" */ 3659 if (isalpha(buf[off]) && buf[off + 1] == ':') 3660 off += 2; 3661 #endif 3662 /* remove the file name */ 3663 p = gettail_sep(buf + off); 3664 if (p == buf + off) 3665 { 3666 char *txt; 3667 3668 #ifdef FEAT_TERMINAL 3669 if (curbuf->b_term != NULL) 3670 txt = term_job_running(curbuf) 3671 ? _("running") : _("finished"); 3672 else 3673 #endif 3674 txt = _("help"); 3675 3676 /* must be a help or terminal buffer */ 3677 vim_strncpy(buf + off, (char_u *)txt, 3678 (size_t)(SPACE_FOR_DIR - off - 1)); 3679 } 3680 else 3681 *p = NUL; 3682 3683 /* Translate unprintable chars and concatenate. Keep some 3684 * room for the server name. When there is no room (very long 3685 * file name) use (...). */ 3686 if (off < SPACE_FOR_DIR) 3687 { 3688 p = transstr(buf + off); 3689 vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off)); 3690 vim_free(p); 3691 } 3692 else 3693 { 3694 vim_strncpy(buf + off, (char_u *)"...", 3695 (size_t)(SPACE_FOR_ARGNR - off)); 3696 } 3697 STRCAT(buf, ")"); 3698 } 3699 3700 append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE); 3701 3702 #if defined(FEAT_CLIENTSERVER) 3703 if (serverName != NULL) 3704 { 3705 STRCAT(buf, " - "); 3706 vim_strcat(buf, serverName, IOSIZE); 3707 } 3708 else 3709 #endif 3710 STRCAT(buf, " - VIM"); 3711 3712 if (maxlen > 0) 3713 { 3714 /* make it shorter by removing a bit in the middle */ 3715 if (vim_strsize(buf) > maxlen) 3716 trunc_string(buf, buf, maxlen, IOSIZE); 3717 } 3718 } 3719 } 3720 mustset = ti_change(t_str, &lasttitle); 3721 3722 if (p_icon) 3723 { 3724 i_str = buf; 3725 if (*p_iconstring != NUL) 3726 { 3727 #ifdef FEAT_STL_OPT 3728 if (stl_syntax & STL_IN_ICON) 3729 { 3730 int use_sandbox = FALSE; 3731 int save_called_emsg = called_emsg; 3732 3733 # ifdef FEAT_EVAL 3734 use_sandbox = was_set_insecurely((char_u *)"iconstring", 0); 3735 # endif 3736 called_emsg = FALSE; 3737 build_stl_str_hl(curwin, i_str, sizeof(buf), 3738 p_iconstring, use_sandbox, 3739 0, 0, NULL, NULL); 3740 if (called_emsg) 3741 set_string_option_direct((char_u *)"iconstring", -1, 3742 (char_u *)"", OPT_FREE, SID_ERROR); 3743 called_emsg |= save_called_emsg; 3744 } 3745 else 3746 #endif 3747 i_str = p_iconstring; 3748 } 3749 else 3750 { 3751 if (buf_spname(curbuf) != NULL) 3752 i_name = buf_spname(curbuf); 3753 else /* use file name only in icon */ 3754 i_name = gettail(curbuf->b_ffname); 3755 *i_str = NUL; 3756 /* Truncate name at 100 bytes. */ 3757 len = (int)STRLEN(i_name); 3758 if (len > 100) 3759 { 3760 len -= 100; 3761 #ifdef FEAT_MBYTE 3762 if (has_mbyte) 3763 len += (*mb_tail_off)(i_name, i_name + len) + 1; 3764 #endif 3765 i_name += len; 3766 } 3767 STRCPY(i_str, i_name); 3768 trans_characters(i_str, IOSIZE); 3769 } 3770 } 3771 3772 mustset |= ti_change(i_str, &lasticon); 3773 3774 if (mustset) 3775 resettitle(); 3776 } 3777 3778 /* 3779 * Used for title and icon: Check if "str" differs from "*last". Set "*last" 3780 * from "str" if it does. 3781 * Return TRUE when "*last" changed. 3782 */ 3783 static int 3784 ti_change(char_u *str, char_u **last) 3785 { 3786 if ((str == NULL) != (*last == NULL) 3787 || (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) 3788 { 3789 vim_free(*last); 3790 if (str == NULL) 3791 *last = NULL; 3792 else 3793 *last = vim_strsave(str); 3794 return TRUE; 3795 } 3796 return FALSE; 3797 } 3798 3799 /* 3800 * Put current window title back (used after calling a shell) 3801 */ 3802 void 3803 resettitle(void) 3804 { 3805 mch_settitle(lasttitle, lasticon); 3806 } 3807 3808 # if defined(EXITFREE) || defined(PROTO) 3809 void 3810 free_titles(void) 3811 { 3812 vim_free(lasttitle); 3813 vim_free(lasticon); 3814 } 3815 # endif 3816 3817 #endif /* FEAT_TITLE */ 3818 3819 #if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO) 3820 /* 3821 * Build a string from the status line items in "fmt". 3822 * Return length of string in screen cells. 3823 * 3824 * Normally works for window "wp", except when working for 'tabline' then it 3825 * is "curwin". 3826 * 3827 * Items are drawn interspersed with the text that surrounds it 3828 * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation 3829 * Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional 3830 * 3831 * If maxwidth is not zero, the string will be filled at any middle marker 3832 * or truncated if too long, fillchar is used for all whitespace. 3833 */ 3834 int 3835 build_stl_str_hl( 3836 win_T *wp, 3837 char_u *out, /* buffer to write into != NameBuff */ 3838 size_t outlen, /* length of out[] */ 3839 char_u *fmt, 3840 int use_sandbox UNUSED, /* "fmt" was set insecurely, use sandbox */ 3841 int fillchar, 3842 int maxwidth, 3843 struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */ 3844 struct stl_hlrec *tabtab) /* return: tab page nrs (can be NULL) */ 3845 { 3846 char_u *p; 3847 char_u *s; 3848 char_u *t; 3849 int byteval; 3850 #ifdef FEAT_EVAL 3851 win_T *o_curwin; 3852 buf_T *o_curbuf; 3853 #endif 3854 int empty_line; 3855 colnr_T virtcol; 3856 long l; 3857 long n; 3858 int prevchar_isflag; 3859 int prevchar_isitem; 3860 int itemisflag; 3861 int fillable; 3862 char_u *str; 3863 long num; 3864 int width; 3865 int itemcnt; 3866 int curitem; 3867 int groupitem[STL_MAX_ITEM]; 3868 int groupdepth; 3869 struct stl_item 3870 { 3871 char_u *start; 3872 int minwid; 3873 int maxwid; 3874 enum 3875 { 3876 Normal, 3877 Empty, 3878 Group, 3879 Middle, 3880 Highlight, 3881 TabPage, 3882 Trunc 3883 } type; 3884 } item[STL_MAX_ITEM]; 3885 int minwid; 3886 int maxwid; 3887 int zeropad; 3888 char_u base; 3889 char_u opt; 3890 #define TMPLEN 70 3891 char_u tmp[TMPLEN]; 3892 char_u *usefmt = fmt; 3893 struct stl_hlrec *sp; 3894 3895 #ifdef FEAT_EVAL 3896 /* 3897 * When the format starts with "%!" then evaluate it as an expression and 3898 * use the result as the actual format string. 3899 */ 3900 if (fmt[0] == '%' && fmt[1] == '!') 3901 { 3902 usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); 3903 if (usefmt == NULL) 3904 usefmt = fmt; 3905 } 3906 #endif 3907 3908 if (fillchar == 0) 3909 fillchar = ' '; 3910 #ifdef FEAT_MBYTE 3911 /* Can't handle a multi-byte fill character yet. */ 3912 else if (mb_char2len(fillchar) > 1) 3913 fillchar = '-'; 3914 #endif 3915 3916 /* Get line & check if empty (cursorpos will show "0-1"). Note that 3917 * p will become invalid when getting another buffer line. */ 3918 p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE); 3919 empty_line = (*p == NUL); 3920 3921 /* Get the byte value now, in case we need it below. This is more 3922 * efficient than making a copy of the line. */ 3923 if (wp->w_cursor.col > (colnr_T)STRLEN(p)) 3924 byteval = 0; 3925 else 3926 #ifdef FEAT_MBYTE 3927 byteval = (*mb_ptr2char)(p + wp->w_cursor.col); 3928 #else 3929 byteval = p[wp->w_cursor.col]; 3930 #endif 3931 3932 groupdepth = 0; 3933 p = out; 3934 curitem = 0; 3935 prevchar_isflag = TRUE; 3936 prevchar_isitem = FALSE; 3937 for (s = usefmt; *s; ) 3938 { 3939 if (curitem == STL_MAX_ITEM) 3940 { 3941 /* There are too many items. Add the error code to the statusline 3942 * to give the user a hint about what went wrong. */ 3943 if (p + 6 < out + outlen) 3944 { 3945 mch_memmove(p, " E541", (size_t)5); 3946 p += 5; 3947 } 3948 break; 3949 } 3950 3951 if (*s != NUL && *s != '%') 3952 prevchar_isflag = prevchar_isitem = FALSE; 3953 3954 /* 3955 * Handle up to the next '%' or the end. 3956 */ 3957 while (*s != NUL && *s != '%' && p + 1 < out + outlen) 3958 *p++ = *s++; 3959 if (*s == NUL || p + 1 >= out + outlen) 3960 break; 3961 3962 /* 3963 * Handle one '%' item. 3964 */ 3965 s++; 3966 if (*s == NUL) /* ignore trailing % */ 3967 break; 3968 if (*s == '%') 3969 { 3970 if (p + 1 >= out + outlen) 3971 break; 3972 *p++ = *s++; 3973 prevchar_isflag = prevchar_isitem = FALSE; 3974 continue; 3975 } 3976 if (*s == STL_MIDDLEMARK) 3977 { 3978 s++; 3979 if (groupdepth > 0) 3980 continue; 3981 item[curitem].type = Middle; 3982 item[curitem++].start = p; 3983 continue; 3984 } 3985 if (*s == STL_TRUNCMARK) 3986 { 3987 s++; 3988 item[curitem].type = Trunc; 3989 item[curitem++].start = p; 3990 continue; 3991 } 3992 if (*s == ')') 3993 { 3994 s++; 3995 if (groupdepth < 1) 3996 continue; 3997 groupdepth--; 3998 3999 t = item[groupitem[groupdepth]].start; 4000 *p = NUL; 4001 l = vim_strsize(t); 4002 if (curitem > groupitem[groupdepth] + 1 4003 && item[groupitem[groupdepth]].minwid == 0) 4004 { 4005 /* remove group if all items are empty */ 4006 for (n = groupitem[groupdepth] + 1; n < curitem; n++) 4007 if (item[n].type == Normal || item[n].type == Highlight) 4008 break; 4009 if (n == curitem) 4010 { 4011 p = t; 4012 l = 0; 4013 } 4014 } 4015 if (l > item[groupitem[groupdepth]].maxwid) 4016 { 4017 /* truncate, remove n bytes of text at the start */ 4018 #ifdef FEAT_MBYTE 4019 if (has_mbyte) 4020 { 4021 /* Find the first character that should be included. */ 4022 n = 0; 4023 while (l >= item[groupitem[groupdepth]].maxwid) 4024 { 4025 l -= ptr2cells(t + n); 4026 n += (*mb_ptr2len)(t + n); 4027 } 4028 } 4029 else 4030 #endif 4031 n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1; 4032 4033 *t = '<'; 4034 mch_memmove(t + 1, t + n, (size_t)(p - (t + n))); 4035 p = p - n + 1; 4036 #ifdef FEAT_MBYTE 4037 /* Fill up space left over by half a double-wide char. */ 4038 while (++l < item[groupitem[groupdepth]].minwid) 4039 *p++ = fillchar; 4040 #endif 4041 4042 /* correct the start of the items for the truncation */ 4043 for (l = groupitem[groupdepth] + 1; l < curitem; l++) 4044 { 4045 item[l].start -= n; 4046 if (item[l].start < t) 4047 item[l].start = t; 4048 } 4049 } 4050 else if (abs(item[groupitem[groupdepth]].minwid) > l) 4051 { 4052 /* fill */ 4053 n = item[groupitem[groupdepth]].minwid; 4054 if (n < 0) 4055 { 4056 /* fill by appending characters */ 4057 n = 0 - n; 4058 while (l++ < n && p + 1 < out + outlen) 4059 *p++ = fillchar; 4060 } 4061 else 4062 { 4063 /* fill by inserting characters */ 4064 mch_memmove(t + n - l, t, (size_t)(p - t)); 4065 l = n - l; 4066 if (p + l >= out + outlen) 4067 l = (long)((out + outlen) - p - 1); 4068 p += l; 4069 for (n = groupitem[groupdepth] + 1; n < curitem; n++) 4070 item[n].start += l; 4071 for ( ; l > 0; l--) 4072 *t++ = fillchar; 4073 } 4074 } 4075 continue; 4076 } 4077 minwid = 0; 4078 maxwid = 9999; 4079 zeropad = FALSE; 4080 l = 1; 4081 if (*s == '0') 4082 { 4083 s++; 4084 zeropad = TRUE; 4085 } 4086 if (*s == '-') 4087 { 4088 s++; 4089 l = -1; 4090 } 4091 if (VIM_ISDIGIT(*s)) 4092 { 4093 minwid = (int)getdigits(&s); 4094 if (minwid < 0) /* overflow */ 4095 minwid = 0; 4096 } 4097 if (*s == STL_USER_HL) 4098 { 4099 item[curitem].type = Highlight; 4100 item[curitem].start = p; 4101 item[curitem].minwid = minwid > 9 ? 1 : minwid; 4102 s++; 4103 curitem++; 4104 continue; 4105 } 4106 if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR) 4107 { 4108 if (*s == STL_TABCLOSENR) 4109 { 4110 if (minwid == 0) 4111 { 4112 /* %X ends the close label, go back to the previously 4113 * define tab label nr. */ 4114 for (n = curitem - 1; n >= 0; --n) 4115 if (item[n].type == TabPage && item[n].minwid >= 0) 4116 { 4117 minwid = item[n].minwid; 4118 break; 4119 } 4120 } 4121 else 4122 /* close nrs are stored as negative values */ 4123 minwid = - minwid; 4124 } 4125 item[curitem].type = TabPage; 4126 item[curitem].start = p; 4127 item[curitem].minwid = minwid; 4128 s++; 4129 curitem++; 4130 continue; 4131 } 4132 if (*s == '.') 4133 { 4134 s++; 4135 if (VIM_ISDIGIT(*s)) 4136 { 4137 maxwid = (int)getdigits(&s); 4138 if (maxwid <= 0) /* overflow */ 4139 maxwid = 50; 4140 } 4141 } 4142 minwid = (minwid > 50 ? 50 : minwid) * l; 4143 if (*s == '(') 4144 { 4145 groupitem[groupdepth++] = curitem; 4146 item[curitem].type = Group; 4147 item[curitem].start = p; 4148 item[curitem].minwid = minwid; 4149 item[curitem].maxwid = maxwid; 4150 s++; 4151 curitem++; 4152 continue; 4153 } 4154 if (vim_strchr(STL_ALL, *s) == NULL) 4155 { 4156 s++; 4157 continue; 4158 } 4159 opt = *s++; 4160 4161 /* OK - now for the real work */ 4162 base = 'D'; 4163 itemisflag = FALSE; 4164 fillable = TRUE; 4165 num = -1; 4166 str = NULL; 4167 switch (opt) 4168 { 4169 case STL_FILEPATH: 4170 case STL_FULLPATH: 4171 case STL_FILENAME: 4172 fillable = FALSE; /* don't change ' ' to fillchar */ 4173 if (buf_spname(wp->w_buffer) != NULL) 4174 vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1); 4175 else 4176 { 4177 t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname 4178 : wp->w_buffer->b_fname; 4179 home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); 4180 } 4181 trans_characters(NameBuff, MAXPATHL); 4182 if (opt != STL_FILENAME) 4183 str = NameBuff; 4184 else 4185 str = gettail(NameBuff); 4186 break; 4187 4188 case STL_VIM_EXPR: /* '{' */ 4189 itemisflag = TRUE; 4190 t = p; 4191 while (*s != '}' && *s != NUL && p + 1 < out + outlen) 4192 *p++ = *s++; 4193 if (*s != '}') /* missing '}' or out of space */ 4194 break; 4195 s++; 4196 *p = 0; 4197 p = t; 4198 4199 #ifdef FEAT_EVAL 4200 vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum); 4201 set_internal_string_var((char_u *)"actual_curbuf", tmp); 4202 4203 o_curbuf = curbuf; 4204 o_curwin = curwin; 4205 curwin = wp; 4206 curbuf = wp->w_buffer; 4207 4208 str = eval_to_string_safe(p, &t, use_sandbox); 4209 4210 curwin = o_curwin; 4211 curbuf = o_curbuf; 4212 do_unlet((char_u *)"g:actual_curbuf", TRUE); 4213 4214 if (str != NULL && *str != 0) 4215 { 4216 if (*skipdigits(str) == NUL) 4217 { 4218 num = atoi((char *)str); 4219 vim_free(str); 4220 str = NULL; 4221 itemisflag = FALSE; 4222 } 4223 } 4224 #endif 4225 break; 4226 4227 case STL_LINE: 4228 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) 4229 ? 0L : (long)(wp->w_cursor.lnum); 4230 break; 4231 4232 case STL_NUMLINES: 4233 num = wp->w_buffer->b_ml.ml_line_count; 4234 break; 4235 4236 case STL_COLUMN: 4237 num = !(State & INSERT) && empty_line 4238 ? 0 : (int)wp->w_cursor.col + 1; 4239 break; 4240 4241 case STL_VIRTCOL: 4242 case STL_VIRTCOL_ALT: 4243 /* In list mode virtcol needs to be recomputed */ 4244 virtcol = wp->w_virtcol; 4245 if (wp->w_p_list && lcs_tab1 == NUL) 4246 { 4247 wp->w_p_list = FALSE; 4248 getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); 4249 wp->w_p_list = TRUE; 4250 } 4251 ++virtcol; 4252 /* Don't display %V if it's the same as %c. */ 4253 if (opt == STL_VIRTCOL_ALT 4254 && (virtcol == (colnr_T)(!(State & INSERT) && empty_line 4255 ? 0 : (int)wp->w_cursor.col + 1))) 4256 break; 4257 num = (long)virtcol; 4258 break; 4259 4260 case STL_PERCENTAGE: 4261 num = (int)(((long)wp->w_cursor.lnum * 100L) / 4262 (long)wp->w_buffer->b_ml.ml_line_count); 4263 break; 4264 4265 case STL_ALTPERCENT: 4266 str = tmp; 4267 get_rel_pos(wp, str, TMPLEN); 4268 break; 4269 4270 case STL_ARGLISTSTAT: 4271 fillable = FALSE; 4272 tmp[0] = 0; 4273 if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE)) 4274 str = tmp; 4275 break; 4276 4277 case STL_KEYMAP: 4278 fillable = FALSE; 4279 if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN)) 4280 str = tmp; 4281 break; 4282 case STL_PAGENUM: 4283 #if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE) 4284 num = printer_page_num; 4285 #else 4286 num = 0; 4287 #endif 4288 break; 4289 4290 case STL_BUFNO: 4291 num = wp->w_buffer->b_fnum; 4292 break; 4293 4294 case STL_OFFSET_X: 4295 base = 'X'; 4296 case STL_OFFSET: 4297 #ifdef FEAT_BYTEOFF 4298 l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); 4299 num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? 4300 0L : l + 1 + (!(State & INSERT) && empty_line ? 4301 0 : (int)wp->w_cursor.col); 4302 #endif 4303 break; 4304 4305 case STL_BYTEVAL_X: 4306 base = 'X'; 4307 case STL_BYTEVAL: 4308 num = byteval; 4309 if (num == NL) 4310 num = 0; 4311 else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC) 4312 num = NL; 4313 break; 4314 4315 case STL_ROFLAG: 4316 case STL_ROFLAG_ALT: 4317 itemisflag = TRUE; 4318 if (wp->w_buffer->b_p_ro) 4319 str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]")); 4320 break; 4321 4322 case STL_HELPFLAG: 4323 case STL_HELPFLAG_ALT: 4324 itemisflag = TRUE; 4325 if (wp->w_buffer->b_help) 4326 str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP" 4327 : _("[Help]")); 4328 break; 4329 4330 #ifdef FEAT_AUTOCMD 4331 case STL_FILETYPE: 4332 if (*wp->w_buffer->b_p_ft != NUL 4333 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) 4334 { 4335 vim_snprintf((char *)tmp, sizeof(tmp), "[%s]", 4336 wp->w_buffer->b_p_ft); 4337 str = tmp; 4338 } 4339 break; 4340 4341 case STL_FILETYPE_ALT: 4342 itemisflag = TRUE; 4343 if (*wp->w_buffer->b_p_ft != NUL 4344 && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) 4345 { 4346 vim_snprintf((char *)tmp, sizeof(tmp), ",%s", 4347 wp->w_buffer->b_p_ft); 4348 for (t = tmp; *t != 0; t++) 4349 *t = TOUPPER_LOC(*t); 4350 str = tmp; 4351 } 4352 break; 4353 #endif 4354 4355 #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) 4356 case STL_PREVIEWFLAG: 4357 case STL_PREVIEWFLAG_ALT: 4358 itemisflag = TRUE; 4359 if (wp->w_p_pvw) 4360 str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV" 4361 : _("[Preview]")); 4362 break; 4363 4364 case STL_QUICKFIX: 4365 if (bt_quickfix(wp->w_buffer)) 4366 str = (char_u *)(wp->w_llist_ref 4367 ? _(msg_loclist) 4368 : _(msg_qflist)); 4369 break; 4370 #endif 4371 4372 case STL_MODIFIED: 4373 case STL_MODIFIED_ALT: 4374 itemisflag = TRUE; 4375 switch ((opt == STL_MODIFIED_ALT) 4376 + bufIsChanged(wp->w_buffer) * 2 4377 + (!wp->w_buffer->b_p_ma) * 4) 4378 { 4379 case 2: str = (char_u *)"[+]"; break; 4380 case 3: str = (char_u *)",+"; break; 4381 case 4: str = (char_u *)"[-]"; break; 4382 case 5: str = (char_u *)",-"; break; 4383 case 6: str = (char_u *)"[+-]"; break; 4384 case 7: str = (char_u *)",+-"; break; 4385 } 4386 break; 4387 4388 case STL_HIGHLIGHT: 4389 t = s; 4390 while (*s != '#' && *s != NUL) 4391 ++s; 4392 if (*s == '#') 4393 { 4394 item[curitem].type = Highlight; 4395 item[curitem].start = p; 4396 item[curitem].minwid = -syn_namen2id(t, (int)(s - t)); 4397 curitem++; 4398 } 4399 if (*s != NUL) 4400 ++s; 4401 continue; 4402 } 4403 4404 item[curitem].start = p; 4405 item[curitem].type = Normal; 4406 if (str != NULL && *str) 4407 { 4408 t = str; 4409 if (itemisflag) 4410 { 4411 if ((t[0] && t[1]) 4412 && ((!prevchar_isitem && *t == ',') 4413 || (prevchar_isflag && *t == ' '))) 4414 t++; 4415 prevchar_isflag = TRUE; 4416 } 4417 l = vim_strsize(t); 4418 if (l > 0) 4419 prevchar_isitem = TRUE; 4420 if (l > maxwid) 4421 { 4422 while (l >= maxwid) 4423 #ifdef FEAT_MBYTE 4424 if (has_mbyte) 4425 { 4426 l -= ptr2cells(t); 4427 t += (*mb_ptr2len)(t); 4428 } 4429 else 4430 #endif 4431 l -= byte2cells(*t++); 4432 if (p + 1 >= out + outlen) 4433 break; 4434 *p++ = '<'; 4435 } 4436 if (minwid > 0) 4437 { 4438 for (; l < minwid && p + 1 < out + outlen; l++) 4439 { 4440 /* Don't put a "-" in front of a digit. */ 4441 if (l + 1 == minwid && fillchar == '-' && VIM_ISDIGIT(*t)) 4442 *p++ = ' '; 4443 else 4444 *p++ = fillchar; 4445 } 4446 minwid = 0; 4447 } 4448 else 4449 minwid *= -1; 4450 while (*t && p + 1 < out + outlen) 4451 { 4452 *p++ = *t++; 4453 /* Change a space by fillchar, unless fillchar is '-' and a 4454 * digit follows. */ 4455 if (fillable && p[-1] == ' ' 4456 && (!VIM_ISDIGIT(*t) || fillchar != '-')) 4457 p[-1] = fillchar; 4458 } 4459 for (; l < minwid && p + 1 < out + outlen; l++) 4460 *p++ = fillchar; 4461 } 4462 else if (num >= 0) 4463 { 4464 int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); 4465 char_u nstr[20]; 4466 4467 if (p + 20 >= out + outlen) 4468 break; /* not sufficient space */ 4469 prevchar_isitem = TRUE; 4470 t = nstr; 4471 if (opt == STL_VIRTCOL_ALT) 4472 { 4473 *t++ = '-'; 4474 minwid--; 4475 } 4476 *t++ = '%'; 4477 if (zeropad) 4478 *t++ = '0'; 4479 *t++ = '*'; 4480 *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); 4481 *t = 0; 4482 4483 for (n = num, l = 1; n >= nbase; n /= nbase) 4484 l++; 4485 if (opt == STL_VIRTCOL_ALT) 4486 l++; 4487 if (l > maxwid) 4488 { 4489 l += 2; 4490 n = l - maxwid; 4491 while (l-- > maxwid) 4492 num /= nbase; 4493 *t++ = '>'; 4494 *t++ = '%'; 4495 *t = t[-3]; 4496 *++t = 0; 4497 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, 4498 0, num, n); 4499 } 4500 else 4501 vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, 4502 minwid, num); 4503 p += STRLEN(p); 4504 } 4505 else 4506 item[curitem].type = Empty; 4507 4508 if (opt == STL_VIM_EXPR) 4509 vim_free(str); 4510 4511 if (num >= 0 || (!itemisflag && str && *str)) 4512 prevchar_isflag = FALSE; /* Item not NULL, but not a flag */ 4513 curitem++; 4514 } 4515 *p = NUL; 4516 itemcnt = curitem; 4517 4518 #ifdef FEAT_EVAL 4519 if (usefmt != fmt) 4520 vim_free(usefmt); 4521 #endif 4522 4523 width = vim_strsize(out); 4524 if (maxwidth > 0 && width > maxwidth) 4525 { 4526 /* Result is too long, must truncate somewhere. */ 4527 l = 0; 4528 if (itemcnt == 0) 4529 s = out; 4530 else 4531 { 4532 for ( ; l < itemcnt; l++) 4533 if (item[l].type == Trunc) 4534 { 4535 /* Truncate at %< item. */ 4536 s = item[l].start; 4537 break; 4538 } 4539 if (l == itemcnt) 4540 { 4541 /* No %< item, truncate first item. */ 4542 s = item[0].start; 4543 l = 0; 4544 } 4545 } 4546 4547 if (width - vim_strsize(s) >= maxwidth) 4548 { 4549 /* Truncation mark is beyond max length */ 4550 #ifdef FEAT_MBYTE 4551 if (has_mbyte) 4552 { 4553 s = out; 4554 width = 0; 4555 for (;;) 4556 { 4557 width += ptr2cells(s); 4558 if (width >= maxwidth) 4559 break; 4560 s += (*mb_ptr2len)(s); 4561 } 4562 /* Fill up for half a double-wide character. */ 4563 while (++width < maxwidth) 4564 *s++ = fillchar; 4565 } 4566 else 4567 #endif 4568 s = out + maxwidth - 1; 4569 for (l = 0; l < itemcnt; l++) 4570 if (item[l].start > s) 4571 break; 4572 itemcnt = l; 4573 *s++ = '>'; 4574 *s = 0; 4575 } 4576 else 4577 { 4578 #ifdef FEAT_MBYTE 4579 if (has_mbyte) 4580 { 4581 n = 0; 4582 while (width >= maxwidth) 4583 { 4584 width -= ptr2cells(s + n); 4585 n += (*mb_ptr2len)(s + n); 4586 } 4587 } 4588 else 4589 #endif 4590 n = width - maxwidth + 1; 4591 p = s + n; 4592 STRMOVE(s + 1, p); 4593 *s = '<'; 4594 4595 /* Fill up for half a double-wide character. */ 4596 while (++width < maxwidth) 4597 { 4598 s = s + STRLEN(s); 4599 *s++ = fillchar; 4600 *s = NUL; 4601 } 4602 4603 --n; /* count the '<' */ 4604 for (; l < itemcnt; l++) 4605 { 4606 if (item[l].start - n >= s) 4607 item[l].start -= n; 4608 else 4609 item[l].start = s; 4610 } 4611 } 4612 width = maxwidth; 4613 } 4614 else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen) 4615 { 4616 /* Apply STL_MIDDLE if any */ 4617 for (l = 0; l < itemcnt; l++) 4618 if (item[l].type == Middle) 4619 break; 4620 if (l < itemcnt) 4621 { 4622 p = item[l].start + maxwidth - width; 4623 STRMOVE(p, item[l].start); 4624 for (s = item[l].start; s < p; s++) 4625 *s = fillchar; 4626 for (l++; l < itemcnt; l++) 4627 item[l].start += maxwidth - width; 4628 width = maxwidth; 4629 } 4630 } 4631 4632 /* Store the info about highlighting. */ 4633 if (hltab != NULL) 4634 { 4635 sp = hltab; 4636 for (l = 0; l < itemcnt; l++) 4637 { 4638 if (item[l].type == Highlight) 4639 { 4640 sp->start = item[l].start; 4641 sp->userhl = item[l].minwid; 4642 sp++; 4643 } 4644 } 4645 sp->start = NULL; 4646 sp->userhl = 0; 4647 } 4648 4649 /* Store the info about tab pages labels. */ 4650 if (tabtab != NULL) 4651 { 4652 sp = tabtab; 4653 for (l = 0; l < itemcnt; l++) 4654 { 4655 if (item[l].type == TabPage) 4656 { 4657 sp->start = item[l].start; 4658 sp->userhl = item[l].minwid; 4659 sp++; 4660 } 4661 } 4662 sp->start = NULL; 4663 sp->userhl = 0; 4664 } 4665 4666 return width; 4667 } 4668 #endif /* FEAT_STL_OPT */ 4669 4670 #if defined(FEAT_STL_OPT) || defined(FEAT_CMDL_INFO) \ 4671 || defined(FEAT_GUI_TABLINE) || defined(PROTO) 4672 /* 4673 * Get relative cursor position in window into "buf[buflen]", in the form 99%, 4674 * using "Top", "Bot" or "All" when appropriate. 4675 */ 4676 void 4677 get_rel_pos( 4678 win_T *wp, 4679 char_u *buf, 4680 int buflen) 4681 { 4682 long above; /* number of lines above window */ 4683 long below; /* number of lines below window */ 4684 4685 if (buflen < 3) /* need at least 3 chars for writing */ 4686 return; 4687 above = wp->w_topline - 1; 4688 #ifdef FEAT_DIFF 4689 above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill; 4690 if (wp->w_topline == 1 && wp->w_topfill >= 1) 4691 above = 0; /* All buffer lines are displayed and there is an 4692 * indication of filler lines, that can be considered 4693 * seeing all lines. */ 4694 #endif 4695 below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1; 4696 if (below <= 0) 4697 vim_strncpy(buf, (char_u *)(above == 0 ? _("All") : _("Bot")), 4698 (size_t)(buflen - 1)); 4699 else if (above <= 0) 4700 vim_strncpy(buf, (char_u *)_("Top"), (size_t)(buflen - 1)); 4701 else 4702 vim_snprintf((char *)buf, (size_t)buflen, "%2d%%", above > 1000000L 4703 ? (int)(above / ((above + below) / 100L)) 4704 : (int)(above * 100L / (above + below))); 4705 } 4706 #endif 4707 4708 /* 4709 * Append (file 2 of 8) to "buf[buflen]", if editing more than one file. 4710 * Return TRUE if it was appended. 4711 */ 4712 static int 4713 append_arg_number( 4714 win_T *wp, 4715 char_u *buf, 4716 int buflen, 4717 int add_file) /* Add "file" before the arg number */ 4718 { 4719 char_u *p; 4720 4721 if (ARGCOUNT <= 1) /* nothing to do */ 4722 return FALSE; 4723 4724 p = buf + STRLEN(buf); /* go to the end of the buffer */ 4725 if (p - buf + 35 >= buflen) /* getting too long */ 4726 return FALSE; 4727 *p++ = ' '; 4728 *p++ = '('; 4729 if (add_file) 4730 { 4731 STRCPY(p, "file "); 4732 p += 5; 4733 } 4734 vim_snprintf((char *)p, (size_t)(buflen - (p - buf)), 4735 wp->w_arg_idx_invalid ? "(%d) of %d)" 4736 : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT); 4737 return TRUE; 4738 } 4739 4740 /* 4741 * If fname is not a full path, make it a full path. 4742 * Returns pointer to allocated memory (NULL for failure). 4743 */ 4744 char_u * 4745 fix_fname(char_u *fname) 4746 { 4747 /* 4748 * Force expanding the path always for Unix, because symbolic links may 4749 * mess up the full path name, even though it starts with a '/'. 4750 * Also expand when there is ".." in the file name, try to remove it, 4751 * because "c:/src/../README" is equal to "c:/README". 4752 * Similarly "c:/src//file" is equal to "c:/src/file". 4753 * For MS-Windows also expand names like "longna~1" to "longname". 4754 */ 4755 #ifdef UNIX 4756 return FullName_save(fname, TRUE); 4757 #else 4758 if (!vim_isAbsName(fname) 4759 || strstr((char *)fname, "..") != NULL 4760 || strstr((char *)fname, "//") != NULL 4761 # ifdef BACKSLASH_IN_FILENAME 4762 || strstr((char *)fname, "\\\\") != NULL 4763 # endif 4764 # if defined(MSWIN) 4765 || vim_strchr(fname, '~') != NULL 4766 # endif 4767 ) 4768 return FullName_save(fname, FALSE); 4769 4770 fname = vim_strsave(fname); 4771 4772 # ifdef USE_FNAME_CASE 4773 # ifdef USE_LONG_FNAME 4774 if (USE_LONG_FNAME) 4775 # endif 4776 { 4777 if (fname != NULL) 4778 fname_case(fname, 0); /* set correct case for file name */ 4779 } 4780 # endif 4781 4782 return fname; 4783 #endif 4784 } 4785 4786 /* 4787 * Make "ffname" a full file name, set "sfname" to "ffname" if not NULL. 4788 * "ffname" becomes a pointer to allocated memory (or NULL). 4789 */ 4790 void 4791 fname_expand( 4792 buf_T *buf UNUSED, 4793 char_u **ffname, 4794 char_u **sfname) 4795 { 4796 if (*ffname == NULL) /* if no file name given, nothing to do */ 4797 return; 4798 if (*sfname == NULL) /* if no short file name given, use ffname */ 4799 *sfname = *ffname; 4800 *ffname = fix_fname(*ffname); /* expand to full path */ 4801 4802 #ifdef FEAT_SHORTCUT 4803 if (!buf->b_p_bin) 4804 { 4805 char_u *rfname; 4806 4807 /* If the file name is a shortcut file, use the file it links to. */ 4808 rfname = mch_resolve_shortcut(*ffname); 4809 if (rfname != NULL) 4810 { 4811 vim_free(*ffname); 4812 *ffname = rfname; 4813 *sfname = rfname; 4814 } 4815 } 4816 #endif 4817 } 4818 4819 /* 4820 * Get the file name for an argument list entry. 4821 */ 4822 char_u * 4823 alist_name(aentry_T *aep) 4824 { 4825 buf_T *bp; 4826 4827 /* Use the name from the associated buffer if it exists. */ 4828 bp = buflist_findnr(aep->ae_fnum); 4829 if (bp == NULL || bp->b_fname == NULL) 4830 return aep->ae_fname; 4831 return bp->b_fname; 4832 } 4833 4834 #if defined(FEAT_WINDOWS) || defined(PROTO) 4835 /* 4836 * do_arg_all(): Open up to 'count' windows, one for each argument. 4837 */ 4838 void 4839 do_arg_all( 4840 int count, 4841 int forceit, /* hide buffers in current windows */ 4842 int keep_tabs) /* keep current tabs, for ":tab drop file" */ 4843 { 4844 int i; 4845 win_T *wp, *wpnext; 4846 char_u *opened; /* Array of weight for which args are open: 4847 * 0: not opened 4848 * 1: opened in other tab 4849 * 2: opened in curtab 4850 * 3: opened in curtab and curwin 4851 */ 4852 int opened_len; /* length of opened[] */ 4853 int use_firstwin = FALSE; /* use first window for arglist */ 4854 int split_ret = OK; 4855 int p_ea_save; 4856 alist_T *alist; /* argument list to be used */ 4857 buf_T *buf; 4858 tabpage_T *tpnext; 4859 int had_tab = cmdmod.tab; 4860 win_T *old_curwin, *last_curwin; 4861 tabpage_T *old_curtab, *last_curtab; 4862 win_T *new_curwin = NULL; 4863 tabpage_T *new_curtab = NULL; 4864 4865 if (ARGCOUNT <= 0) 4866 { 4867 /* Don't give an error message. We don't want it when the ":all" 4868 * command is in the .vimrc. */ 4869 return; 4870 } 4871 setpcmark(); 4872 4873 opened_len = ARGCOUNT; 4874 opened = alloc_clear((unsigned)opened_len); 4875 if (opened == NULL) 4876 return; 4877 4878 /* Autocommands may do anything to the argument list. Make sure it's not 4879 * freed while we are working here by "locking" it. We still have to 4880 * watch out for its size to be changed. */ 4881 alist = curwin->w_alist; 4882 ++alist->al_refcount; 4883 4884 old_curwin = curwin; 4885 old_curtab = curtab; 4886 4887 # ifdef FEAT_GUI 4888 need_mouse_correct = TRUE; 4889 # endif 4890 4891 /* 4892 * Try closing all windows that are not in the argument list. 4893 * Also close windows that are not full width; 4894 * When 'hidden' or "forceit" set the buffer becomes hidden. 4895 * Windows that have a changed buffer and can't be hidden won't be closed. 4896 * When the ":tab" modifier was used do this for all tab pages. 4897 */ 4898 if (had_tab > 0) 4899 goto_tabpage_tp(first_tabpage, TRUE, TRUE); 4900 for (;;) 4901 { 4902 tpnext = curtab->tp_next; 4903 for (wp = firstwin; wp != NULL; wp = wpnext) 4904 { 4905 wpnext = wp->w_next; 4906 buf = wp->w_buffer; 4907 if (buf->b_ffname == NULL 4908 || (!keep_tabs && (buf->b_nwindows > 1 4909 || wp->w_width != Columns))) 4910 i = opened_len; 4911 else 4912 { 4913 /* check if the buffer in this window is in the arglist */ 4914 for (i = 0; i < opened_len; ++i) 4915 { 4916 if (i < alist->al_ga.ga_len 4917 && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum 4918 || fullpathcmp(alist_name(&AARGLIST(alist)[i]), 4919 buf->b_ffname, TRUE) & FPC_SAME)) 4920 { 4921 int weight = 1; 4922 4923 if (old_curtab == curtab) 4924 { 4925 ++weight; 4926 if (old_curwin == wp) 4927 ++weight; 4928 } 4929 4930 if (weight > (int)opened[i]) 4931 { 4932 opened[i] = (char_u)weight; 4933 if (i == 0) 4934 { 4935 if (new_curwin != NULL) 4936 new_curwin->w_arg_idx = opened_len; 4937 new_curwin = wp; 4938 new_curtab = curtab; 4939 } 4940 } 4941 else if (keep_tabs) 4942 i = opened_len; 4943 4944 if (wp->w_alist != alist) 4945 { 4946 /* Use the current argument list for all windows 4947 * containing a file from it. */ 4948 alist_unlink(wp->w_alist); 4949 wp->w_alist = alist; 4950 ++wp->w_alist->al_refcount; 4951 } 4952 break; 4953 } 4954 } 4955 } 4956 wp->w_arg_idx = i; 4957 4958 if (i == opened_len && !keep_tabs)/* close this window */ 4959 { 4960 if (P_HID(buf) || forceit || buf->b_nwindows > 1 4961 || !bufIsChanged(buf)) 4962 { 4963 /* If the buffer was changed, and we would like to hide it, 4964 * try autowriting. */ 4965 if (!P_HID(buf) && buf->b_nwindows <= 1 4966 && bufIsChanged(buf)) 4967 { 4968 #ifdef FEAT_AUTOCMD 4969 bufref_T bufref; 4970 4971 set_bufref(&bufref, buf); 4972 #endif 4973 (void)autowrite(buf, FALSE); 4974 #ifdef FEAT_AUTOCMD 4975 /* check if autocommands removed the window */ 4976 if (!win_valid(wp) || !bufref_valid(&bufref)) 4977 { 4978 wpnext = firstwin; /* start all over... */ 4979 continue; 4980 } 4981 #endif 4982 } 4983 #ifdef FEAT_WINDOWS 4984 /* don't close last window */ 4985 if (ONE_WINDOW 4986 && (first_tabpage->tp_next == NULL || !had_tab)) 4987 #endif 4988 use_firstwin = TRUE; 4989 #ifdef FEAT_WINDOWS 4990 else 4991 { 4992 win_close(wp, !P_HID(buf) && !bufIsChanged(buf)); 4993 # ifdef FEAT_AUTOCMD 4994 /* check if autocommands removed the next window */ 4995 if (!win_valid(wpnext)) 4996 wpnext = firstwin; /* start all over... */ 4997 # endif 4998 } 4999 #endif 5000 } 5001 } 5002 } 5003 5004 /* Without the ":tab" modifier only do the current tab page. */ 5005 if (had_tab == 0 || tpnext == NULL) 5006 break; 5007 5008 # ifdef FEAT_AUTOCMD 5009 /* check if autocommands removed the next tab page */ 5010 if (!valid_tabpage(tpnext)) 5011 tpnext = first_tabpage; /* start all over...*/ 5012 # endif 5013 goto_tabpage_tp(tpnext, TRUE, TRUE); 5014 } 5015 5016 /* 5017 * Open a window for files in the argument list that don't have one. 5018 * ARGCOUNT may change while doing this, because of autocommands. 5019 */ 5020 if (count > opened_len || count <= 0) 5021 count = opened_len; 5022 5023 #ifdef FEAT_AUTOCMD 5024 /* Don't execute Win/Buf Enter/Leave autocommands here. */ 5025 ++autocmd_no_enter; 5026 ++autocmd_no_leave; 5027 #endif 5028 last_curwin = curwin; 5029 last_curtab = curtab; 5030 win_enter(lastwin, FALSE); 5031 #ifdef FEAT_WINDOWS 5032 /* ":drop all" should re-use an empty window to avoid "--remote-tab" 5033 * leaving an empty tab page when executed locally. */ 5034 if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 5035 && curbuf->b_ffname == NULL && !curbuf->b_changed) 5036 use_firstwin = TRUE; 5037 #endif 5038 5039 for (i = 0; i < count && i < opened_len && !got_int; ++i) 5040 { 5041 if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) 5042 arg_had_last = TRUE; 5043 if (opened[i] > 0) 5044 { 5045 /* Move the already present window to below the current window */ 5046 if (curwin->w_arg_idx != i) 5047 { 5048 for (wpnext = firstwin; wpnext != NULL; wpnext = wpnext->w_next) 5049 { 5050 if (wpnext->w_arg_idx == i) 5051 { 5052 if (keep_tabs) 5053 { 5054 new_curwin = wpnext; 5055 new_curtab = curtab; 5056 } 5057 else 5058 win_move_after(wpnext, curwin); 5059 break; 5060 } 5061 } 5062 } 5063 } 5064 else if (split_ret == OK) 5065 { 5066 if (!use_firstwin) /* split current window */ 5067 { 5068 p_ea_save = p_ea; 5069 p_ea = TRUE; /* use space from all windows */ 5070 split_ret = win_split(0, WSP_ROOM | WSP_BELOW); 5071 p_ea = p_ea_save; 5072 if (split_ret == FAIL) 5073 continue; 5074 } 5075 #ifdef FEAT_AUTOCMD 5076 else /* first window: do autocmd for leaving this buffer */ 5077 --autocmd_no_leave; 5078 #endif 5079 5080 /* 5081 * edit file "i" 5082 */ 5083 curwin->w_arg_idx = i; 5084 if (i == 0) 5085 { 5086 new_curwin = curwin; 5087 new_curtab = curtab; 5088 } 5089 (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, 5090 ECMD_ONE, 5091 ((P_HID(curwin->w_buffer) 5092 || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) 5093 + ECMD_OLDBUF, curwin); 5094 #ifdef FEAT_AUTOCMD 5095 if (use_firstwin) 5096 ++autocmd_no_leave; 5097 #endif 5098 use_firstwin = FALSE; 5099 } 5100 ui_breakcheck(); 5101 5102 /* When ":tab" was used open a new tab for a new window repeatedly. */ 5103 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) 5104 cmdmod.tab = 9999; 5105 } 5106 5107 /* Remove the "lock" on the argument list. */ 5108 alist_unlink(alist); 5109 5110 #ifdef FEAT_AUTOCMD 5111 --autocmd_no_enter; 5112 #endif 5113 /* restore last referenced tabpage's curwin */ 5114 if (last_curtab != new_curtab) 5115 { 5116 if (valid_tabpage(last_curtab)) 5117 goto_tabpage_tp(last_curtab, TRUE, TRUE); 5118 if (win_valid(last_curwin)) 5119 win_enter(last_curwin, FALSE); 5120 } 5121 /* to window with first arg */ 5122 if (valid_tabpage(new_curtab)) 5123 goto_tabpage_tp(new_curtab, TRUE, TRUE); 5124 if (win_valid(new_curwin)) 5125 win_enter(new_curwin, FALSE); 5126 5127 #ifdef FEAT_AUTOCMD 5128 --autocmd_no_leave; 5129 #endif 5130 vim_free(opened); 5131 } 5132 5133 # if defined(FEAT_LISTCMDS) || defined(PROTO) 5134 /* 5135 * Open a window for a number of buffers. 5136 */ 5137 void 5138 ex_buffer_all(exarg_T *eap) 5139 { 5140 buf_T *buf; 5141 win_T *wp, *wpnext; 5142 int split_ret = OK; 5143 int p_ea_save; 5144 int open_wins = 0; 5145 int r; 5146 int count; /* Maximum number of windows to open. */ 5147 int all; /* When TRUE also load inactive buffers. */ 5148 #ifdef FEAT_WINDOWS 5149 int had_tab = cmdmod.tab; 5150 tabpage_T *tpnext; 5151 #endif 5152 5153 if (eap->addr_count == 0) /* make as many windows as possible */ 5154 count = 9999; 5155 else 5156 count = eap->line2; /* make as many windows as specified */ 5157 if (eap->cmdidx == CMD_unhide || eap->cmdidx == CMD_sunhide) 5158 all = FALSE; 5159 else 5160 all = TRUE; 5161 5162 setpcmark(); 5163 5164 #ifdef FEAT_GUI 5165 need_mouse_correct = TRUE; 5166 #endif 5167 5168 /* 5169 * Close superfluous windows (two windows for the same buffer). 5170 * Also close windows that are not full-width. 5171 */ 5172 #ifdef FEAT_WINDOWS 5173 if (had_tab > 0) 5174 goto_tabpage_tp(first_tabpage, TRUE, TRUE); 5175 for (;;) 5176 { 5177 #endif 5178 tpnext = curtab->tp_next; 5179 for (wp = firstwin; wp != NULL; wp = wpnext) 5180 { 5181 wpnext = wp->w_next; 5182 if ((wp->w_buffer->b_nwindows > 1 5183 #ifdef FEAT_WINDOWS 5184 || ((cmdmod.split & WSP_VERT) 5185 ? wp->w_height + wp->w_status_height < Rows - p_ch 5186 - tabline_height() 5187 : wp->w_width != Columns) 5188 || (had_tab > 0 && wp != firstwin) 5189 #endif 5190 ) && !ONE_WINDOW 5191 #ifdef FEAT_AUTOCMD 5192 && !(wp->w_closing || wp->w_buffer->b_locked > 0) 5193 #endif 5194 ) 5195 { 5196 win_close(wp, FALSE); 5197 #ifdef FEAT_AUTOCMD 5198 wpnext = firstwin; /* just in case an autocommand does 5199 something strange with windows */ 5200 tpnext = first_tabpage; /* start all over...*/ 5201 open_wins = 0; 5202 #endif 5203 } 5204 else 5205 ++open_wins; 5206 } 5207 5208 #ifdef FEAT_WINDOWS 5209 /* Without the ":tab" modifier only do the current tab page. */ 5210 if (had_tab == 0 || tpnext == NULL) 5211 break; 5212 goto_tabpage_tp(tpnext, TRUE, TRUE); 5213 } 5214 #endif 5215 5216 /* 5217 * Go through the buffer list. When a buffer doesn't have a window yet, 5218 * open one. Otherwise move the window to the right position. 5219 * Watch out for autocommands that delete buffers or windows! 5220 */ 5221 #ifdef FEAT_AUTOCMD 5222 /* Don't execute Win/Buf Enter/Leave autocommands here. */ 5223 ++autocmd_no_enter; 5224 #endif 5225 win_enter(lastwin, FALSE); 5226 #ifdef FEAT_AUTOCMD 5227 ++autocmd_no_leave; 5228 #endif 5229 for (buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) 5230 { 5231 /* Check if this buffer needs a window */ 5232 if ((!all && buf->b_ml.ml_mfp == NULL) || !buf->b_p_bl) 5233 continue; 5234 5235 #ifdef FEAT_WINDOWS 5236 if (had_tab != 0) 5237 { 5238 /* With the ":tab" modifier don't move the window. */ 5239 if (buf->b_nwindows > 0) 5240 wp = lastwin; /* buffer has a window, skip it */ 5241 else 5242 wp = NULL; 5243 } 5244 else 5245 #endif 5246 { 5247 /* Check if this buffer already has a window */ 5248 FOR_ALL_WINDOWS(wp) 5249 if (wp->w_buffer == buf) 5250 break; 5251 /* If the buffer already has a window, move it */ 5252 if (wp != NULL) 5253 win_move_after(wp, curwin); 5254 } 5255 5256 if (wp == NULL && split_ret == OK) 5257 { 5258 #ifdef FEAT_AUTOCMD 5259 bufref_T bufref; 5260 5261 set_bufref(&bufref, buf); 5262 #endif 5263 /* Split the window and put the buffer in it */ 5264 p_ea_save = p_ea; 5265 p_ea = TRUE; /* use space from all windows */ 5266 split_ret = win_split(0, WSP_ROOM | WSP_BELOW); 5267 ++open_wins; 5268 p_ea = p_ea_save; 5269 if (split_ret == FAIL) 5270 continue; 5271 5272 /* Open the buffer in this window. */ 5273 #if defined(HAS_SWAP_EXISTS_ACTION) 5274 swap_exists_action = SEA_DIALOG; 5275 #endif 5276 set_curbuf(buf, DOBUF_GOTO); 5277 #ifdef FEAT_AUTOCMD 5278 if (!bufref_valid(&bufref)) 5279 { 5280 /* autocommands deleted the buffer!!! */ 5281 #if defined(HAS_SWAP_EXISTS_ACTION) 5282 swap_exists_action = SEA_NONE; 5283 # endif 5284 break; 5285 } 5286 #endif 5287 #if defined(HAS_SWAP_EXISTS_ACTION) 5288 if (swap_exists_action == SEA_QUIT) 5289 { 5290 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 5291 cleanup_T cs; 5292 5293 /* Reset the error/interrupt/exception state here so that 5294 * aborting() returns FALSE when closing a window. */ 5295 enter_cleanup(&cs); 5296 # endif 5297 5298 /* User selected Quit at ATTENTION prompt; close this window. */ 5299 win_close(curwin, TRUE); 5300 --open_wins; 5301 swap_exists_action = SEA_NONE; 5302 swap_exists_did_quit = TRUE; 5303 5304 # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) 5305 /* Restore the error/interrupt/exception state if not 5306 * discarded by a new aborting error, interrupt, or uncaught 5307 * exception. */ 5308 leave_cleanup(&cs); 5309 # endif 5310 } 5311 else 5312 handle_swap_exists(NULL); 5313 #endif 5314 } 5315 5316 ui_breakcheck(); 5317 if (got_int) 5318 { 5319 (void)vgetc(); /* only break the file loading, not the rest */ 5320 break; 5321 } 5322 #ifdef FEAT_EVAL 5323 /* Autocommands deleted the buffer or aborted script processing!!! */ 5324 if (aborting()) 5325 break; 5326 #endif 5327 #ifdef FEAT_WINDOWS 5328 /* When ":tab" was used open a new tab for a new window repeatedly. */ 5329 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) 5330 cmdmod.tab = 9999; 5331 #endif 5332 } 5333 #ifdef FEAT_AUTOCMD 5334 --autocmd_no_enter; 5335 #endif 5336 win_enter(firstwin, FALSE); /* back to first window */ 5337 #ifdef FEAT_AUTOCMD 5338 --autocmd_no_leave; 5339 #endif 5340 5341 /* 5342 * Close superfluous windows. 5343 */ 5344 for (wp = lastwin; open_wins > count; ) 5345 { 5346 r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer) 5347 || autowrite(wp->w_buffer, FALSE) == OK); 5348 #ifdef FEAT_AUTOCMD 5349 if (!win_valid(wp)) 5350 { 5351 /* BufWrite Autocommands made the window invalid, start over */ 5352 wp = lastwin; 5353 } 5354 else 5355 #endif 5356 if (r) 5357 { 5358 win_close(wp, !P_HID(wp->w_buffer)); 5359 --open_wins; 5360 wp = lastwin; 5361 } 5362 else 5363 { 5364 wp = wp->w_prev; 5365 if (wp == NULL) 5366 break; 5367 } 5368 } 5369 } 5370 # endif /* FEAT_LISTCMDS */ 5371 5372 #endif /* FEAT_WINDOWS */ 5373 5374 static int chk_modeline(linenr_T, int); 5375 5376 /* 5377 * do_modelines() - process mode lines for the current file 5378 * 5379 * "flags" can be: 5380 * OPT_WINONLY only set options local to window 5381 * OPT_NOWIN don't set options local to window 5382 * 5383 * Returns immediately if the "ml" option isn't set. 5384 */ 5385 void 5386 do_modelines(int flags) 5387 { 5388 linenr_T lnum; 5389 int nmlines; 5390 static int entered = 0; 5391 5392 if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0) 5393 return; 5394 5395 /* Disallow recursive entry here. Can happen when executing a modeline 5396 * triggers an autocommand, which reloads modelines with a ":do". */ 5397 if (entered) 5398 return; 5399 5400 ++entered; 5401 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines; 5402 ++lnum) 5403 if (chk_modeline(lnum, flags) == FAIL) 5404 nmlines = 0; 5405 5406 for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines 5407 && lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum) 5408 if (chk_modeline(lnum, flags) == FAIL) 5409 nmlines = 0; 5410 --entered; 5411 } 5412 5413 #include "version.h" /* for version number */ 5414 5415 /* 5416 * chk_modeline() - check a single line for a mode string 5417 * Return FAIL if an error encountered. 5418 */ 5419 static int 5420 chk_modeline( 5421 linenr_T lnum, 5422 int flags) /* Same as for do_modelines(). */ 5423 { 5424 char_u *s; 5425 char_u *e; 5426 char_u *linecopy; /* local copy of any modeline found */ 5427 int prev; 5428 int vers; 5429 int end; 5430 int retval = OK; 5431 char_u *save_sourcing_name; 5432 linenr_T save_sourcing_lnum; 5433 #ifdef FEAT_EVAL 5434 scid_T save_SID; 5435 #endif 5436 5437 prev = -1; 5438 for (s = ml_get(lnum); *s != NUL; ++s) 5439 { 5440 if (prev == -1 || vim_isspace(prev)) 5441 { 5442 if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) 5443 || STRNCMP(s, "vi:", (size_t)3) == 0) 5444 break; 5445 /* Accept both "vim" and "Vim". */ 5446 if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') 5447 { 5448 if (s[3] == '<' || s[3] == '=' || s[3] == '>') 5449 e = s + 4; 5450 else 5451 e = s + 3; 5452 vers = getdigits(&e); 5453 if (*e == ':' 5454 && (s[0] != 'V' 5455 || STRNCMP(skipwhite(e + 1), "set", 3) == 0) 5456 && (s[3] == ':' 5457 || (VIM_VERSION_100 >= vers && isdigit(s[3])) 5458 || (VIM_VERSION_100 < vers && s[3] == '<') 5459 || (VIM_VERSION_100 > vers && s[3] == '>') 5460 || (VIM_VERSION_100 == vers && s[3] == '='))) 5461 break; 5462 } 5463 } 5464 prev = *s; 5465 } 5466 5467 if (*s) 5468 { 5469 do /* skip over "ex:", "vi:" or "vim:" */ 5470 ++s; 5471 while (s[-1] != ':'); 5472 5473 s = linecopy = vim_strsave(s); /* copy the line, it will change */ 5474 if (linecopy == NULL) 5475 return FAIL; 5476 5477 save_sourcing_lnum = sourcing_lnum; 5478 save_sourcing_name = sourcing_name; 5479 sourcing_lnum = lnum; /* prepare for emsg() */ 5480 sourcing_name = (char_u *)"modelines"; 5481 5482 end = FALSE; 5483 while (end == FALSE) 5484 { 5485 s = skipwhite(s); 5486 if (*s == NUL) 5487 break; 5488 5489 /* 5490 * Find end of set command: ':' or end of line. 5491 * Skip over "\:", replacing it with ":". 5492 */ 5493 for (e = s; *e != ':' && *e != NUL; ++e) 5494 if (e[0] == '\\' && e[1] == ':') 5495 STRMOVE(e, e + 1); 5496 if (*e == NUL) 5497 end = TRUE; 5498 5499 /* 5500 * If there is a "set" command, require a terminating ':' and 5501 * ignore the stuff after the ':'. 5502 * "vi:set opt opt opt: foo" -- foo not interpreted 5503 * "vi:opt opt opt: foo" -- foo interpreted 5504 * Accept "se" for compatibility with Elvis. 5505 */ 5506 if (STRNCMP(s, "set ", (size_t)4) == 0 5507 || STRNCMP(s, "se ", (size_t)3) == 0) 5508 { 5509 if (*e != ':') /* no terminating ':'? */ 5510 break; 5511 end = TRUE; 5512 s = vim_strchr(s, ' ') + 1; 5513 } 5514 *e = NUL; /* truncate the set command */ 5515 5516 if (*s != NUL) /* skip over an empty "::" */ 5517 { 5518 #ifdef FEAT_EVAL 5519 save_SID = current_SID; 5520 current_SID = SID_MODELINE; 5521 #endif 5522 retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags); 5523 #ifdef FEAT_EVAL 5524 current_SID = save_SID; 5525 #endif 5526 if (retval == FAIL) /* stop if error found */ 5527 break; 5528 } 5529 s = e + 1; /* advance to next part */ 5530 } 5531 5532 sourcing_lnum = save_sourcing_lnum; 5533 sourcing_name = save_sourcing_name; 5534 5535 vim_free(linecopy); 5536 } 5537 return retval; 5538 } 5539 5540 #if defined(FEAT_VIMINFO) || defined(PROTO) 5541 int 5542 read_viminfo_bufferlist( 5543 vir_T *virp, 5544 int writing) 5545 { 5546 char_u *tab; 5547 linenr_T lnum; 5548 colnr_T col; 5549 buf_T *buf; 5550 char_u *sfname; 5551 char_u *xline; 5552 5553 /* Handle long line and escaped characters. */ 5554 xline = viminfo_readstring(virp, 1, FALSE); 5555 5556 /* don't read in if there are files on the command-line or if writing: */ 5557 if (xline != NULL && !writing && ARGCOUNT == 0 5558 && find_viminfo_parameter('%') != NULL) 5559 { 5560 /* Format is: <fname> Tab <lnum> Tab <col>. 5561 * Watch out for a Tab in the file name, work from the end. */ 5562 lnum = 0; 5563 col = 0; 5564 tab = vim_strrchr(xline, '\t'); 5565 if (tab != NULL) 5566 { 5567 *tab++ = '\0'; 5568 col = (colnr_T)atoi((char *)tab); 5569 tab = vim_strrchr(xline, '\t'); 5570 if (tab != NULL) 5571 { 5572 *tab++ = '\0'; 5573 lnum = atol((char *)tab); 5574 } 5575 } 5576 5577 /* Expand "~/" in the file name at "line + 1" to a full path. 5578 * Then try shortening it by comparing with the current directory */ 5579 expand_env(xline, NameBuff, MAXPATHL); 5580 sfname = shorten_fname1(NameBuff); 5581 5582 buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED); 5583 if (buf != NULL) /* just in case... */ 5584 { 5585 buf->b_last_cursor.lnum = lnum; 5586 buf->b_last_cursor.col = col; 5587 buflist_setfpos(buf, curwin, lnum, col, FALSE); 5588 } 5589 } 5590 vim_free(xline); 5591 5592 return viminfo_readline(virp); 5593 } 5594 5595 void 5596 write_viminfo_bufferlist(FILE *fp) 5597 { 5598 buf_T *buf; 5599 #ifdef FEAT_WINDOWS 5600 win_T *win; 5601 tabpage_T *tp; 5602 #endif 5603 char_u *line; 5604 int max_buffers; 5605 5606 if (find_viminfo_parameter('%') == NULL) 5607 return; 5608 5609 /* Without a number -1 is returned: do all buffers. */ 5610 max_buffers = get_viminfo_parameter('%'); 5611 5612 /* Allocate room for the file name, lnum and col. */ 5613 #define LINE_BUF_LEN (MAXPATHL + 40) 5614 line = alloc(LINE_BUF_LEN); 5615 if (line == NULL) 5616 return; 5617 5618 #ifdef FEAT_WINDOWS 5619 FOR_ALL_TAB_WINDOWS(tp, win) 5620 set_last_cursor(win); 5621 #else 5622 set_last_cursor(curwin); 5623 #endif 5624 5625 fputs(_("\n# Buffer list:\n"), fp); 5626 FOR_ALL_BUFFERS(buf) 5627 { 5628 if (buf->b_fname == NULL 5629 || !buf->b_p_bl 5630 #ifdef FEAT_QUICKFIX 5631 || bt_quickfix(buf) 5632 #endif 5633 || removable(buf->b_ffname)) 5634 continue; 5635 5636 if (max_buffers-- == 0) 5637 break; 5638 putc('%', fp); 5639 home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE); 5640 vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%ld\t%d", 5641 (long)buf->b_last_cursor.lnum, 5642 buf->b_last_cursor.col); 5643 viminfo_writestring(fp, line); 5644 } 5645 vim_free(line); 5646 } 5647 #endif 5648 5649 5650 /* 5651 * Return special buffer name. 5652 * Returns NULL when the buffer has a normal file name. 5653 */ 5654 char_u * 5655 buf_spname(buf_T *buf) 5656 { 5657 #if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS) 5658 if (bt_quickfix(buf)) 5659 { 5660 win_T *win; 5661 tabpage_T *tp; 5662 5663 /* 5664 * For location list window, w_llist_ref points to the location list. 5665 * For quickfix window, w_llist_ref is NULL. 5666 */ 5667 if (find_win_for_buf(buf, &win, &tp) == OK && win->w_llist_ref != NULL) 5668 return (char_u *)_(msg_loclist); 5669 else 5670 return (char_u *)_(msg_qflist); 5671 } 5672 #endif 5673 #ifdef FEAT_QUICKFIX 5674 /* There is no _file_ when 'buftype' is "nofile", b_sfname 5675 * contains the name as specified by the user */ 5676 if (bt_nofile(buf)) 5677 { 5678 if (buf->b_sfname != NULL) 5679 return buf->b_sfname; 5680 return (char_u *)_("[Scratch]"); 5681 } 5682 #endif 5683 if (buf->b_fname == NULL) 5684 return (char_u *)_("[No Name]"); 5685 return NULL; 5686 } 5687 5688 #if (defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)) \ 5689 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \ 5690 || defined(PROTO) 5691 /* 5692 * Find a window for buffer "buf". 5693 * If found OK is returned and "wp" and "tp" are set to the window and tabpage. 5694 * If not found FAIL is returned. 5695 */ 5696 int 5697 find_win_for_buf( 5698 buf_T *buf, 5699 win_T **wp, 5700 tabpage_T **tp) 5701 { 5702 FOR_ALL_TAB_WINDOWS(*tp, *wp) 5703 if ((*wp)->w_buffer == buf) 5704 goto win_found; 5705 return FAIL; 5706 win_found: 5707 return OK; 5708 } 5709 #endif 5710 5711 #if defined(FEAT_SIGNS) || defined(PROTO) 5712 /* 5713 * Insert the sign into the signlist. 5714 */ 5715 static void 5716 insert_sign( 5717 buf_T *buf, /* buffer to store sign in */ 5718 signlist_T *prev, /* previous sign entry */ 5719 signlist_T *next, /* next sign entry */ 5720 int id, /* sign ID */ 5721 linenr_T lnum, /* line number which gets the mark */ 5722 int typenr) /* typenr of sign we are adding */ 5723 { 5724 signlist_T *newsign; 5725 5726 newsign = (signlist_T *)lalloc((long_u)sizeof(signlist_T), FALSE); 5727 if (newsign != NULL) 5728 { 5729 newsign->id = id; 5730 newsign->lnum = lnum; 5731 newsign->typenr = typenr; 5732 newsign->next = next; 5733 #ifdef FEAT_NETBEANS_INTG 5734 newsign->prev = prev; 5735 if (next != NULL) 5736 next->prev = newsign; 5737 #endif 5738 5739 if (prev == NULL) 5740 { 5741 /* When adding first sign need to redraw the windows to create the 5742 * column for signs. */ 5743 if (buf->b_signlist == NULL) 5744 { 5745 redraw_buf_later(buf, NOT_VALID); 5746 changed_cline_bef_curs(); 5747 } 5748 5749 /* first sign in signlist */ 5750 buf->b_signlist = newsign; 5751 #ifdef FEAT_NETBEANS_INTG 5752 if (netbeans_active()) 5753 buf->b_has_sign_column = TRUE; 5754 #endif 5755 } 5756 else 5757 prev->next = newsign; 5758 } 5759 } 5760 5761 /* 5762 * Add the sign into the signlist. Find the right spot to do it though. 5763 */ 5764 void 5765 buf_addsign( 5766 buf_T *buf, /* buffer to store sign in */ 5767 int id, /* sign ID */ 5768 linenr_T lnum, /* line number which gets the mark */ 5769 int typenr) /* typenr of sign we are adding */ 5770 { 5771 signlist_T *sign; /* a sign in the signlist */ 5772 signlist_T *prev; /* the previous sign */ 5773 5774 prev = NULL; 5775 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5776 { 5777 if (lnum == sign->lnum && id == sign->id) 5778 { 5779 sign->typenr = typenr; 5780 return; 5781 } 5782 else if ( 5783 #ifndef FEAT_NETBEANS_INTG /* keep signs sorted by lnum */ 5784 id < 0 && 5785 #endif 5786 lnum < sign->lnum) 5787 { 5788 #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */ 5789 /* XXX - GRP: Is this because of sign slide problem? Or is it 5790 * really needed? Or is it because we allow multiple signs per 5791 * line? If so, should I add that feature to FEAT_SIGNS? 5792 */ 5793 while (prev != NULL && prev->lnum == lnum) 5794 prev = prev->prev; 5795 if (prev == NULL) 5796 sign = buf->b_signlist; 5797 else 5798 sign = prev->next; 5799 #endif 5800 insert_sign(buf, prev, sign, id, lnum, typenr); 5801 return; 5802 } 5803 prev = sign; 5804 } 5805 #ifdef FEAT_NETBEANS_INTG /* insert new sign at head of list for this lnum */ 5806 /* XXX - GRP: See previous comment */ 5807 while (prev != NULL && prev->lnum == lnum) 5808 prev = prev->prev; 5809 if (prev == NULL) 5810 sign = buf->b_signlist; 5811 else 5812 sign = prev->next; 5813 #endif 5814 insert_sign(buf, prev, sign, id, lnum, typenr); 5815 5816 return; 5817 } 5818 5819 /* 5820 * For an existing, placed sign "markId" change the type to "typenr". 5821 * Returns the line number of the sign, or zero if the sign is not found. 5822 */ 5823 linenr_T 5824 buf_change_sign_type( 5825 buf_T *buf, /* buffer to store sign in */ 5826 int markId, /* sign ID */ 5827 int typenr) /* typenr of sign we are adding */ 5828 { 5829 signlist_T *sign; /* a sign in the signlist */ 5830 5831 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5832 { 5833 if (sign->id == markId) 5834 { 5835 sign->typenr = typenr; 5836 return sign->lnum; 5837 } 5838 } 5839 5840 return (linenr_T)0; 5841 } 5842 5843 int 5844 buf_getsigntype( 5845 buf_T *buf, 5846 linenr_T lnum, 5847 int type) /* SIGN_ICON, SIGN_TEXT, SIGN_ANY, SIGN_LINEHL */ 5848 { 5849 signlist_T *sign; /* a sign in a b_signlist */ 5850 5851 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5852 if (sign->lnum == lnum 5853 && (type == SIGN_ANY 5854 # ifdef FEAT_SIGN_ICONS 5855 || (type == SIGN_ICON 5856 && sign_get_image(sign->typenr) != NULL) 5857 # endif 5858 || (type == SIGN_TEXT 5859 && sign_get_text(sign->typenr) != NULL) 5860 || (type == SIGN_LINEHL 5861 && sign_get_attr(sign->typenr, TRUE) != 0))) 5862 return sign->typenr; 5863 return 0; 5864 } 5865 5866 5867 linenr_T 5868 buf_delsign( 5869 buf_T *buf, /* buffer sign is stored in */ 5870 int id) /* sign id */ 5871 { 5872 signlist_T **lastp; /* pointer to pointer to current sign */ 5873 signlist_T *sign; /* a sign in a b_signlist */ 5874 signlist_T *next; /* the next sign in a b_signlist */ 5875 linenr_T lnum; /* line number whose sign was deleted */ 5876 5877 lastp = &buf->b_signlist; 5878 lnum = 0; 5879 for (sign = buf->b_signlist; sign != NULL; sign = next) 5880 { 5881 next = sign->next; 5882 if (sign->id == id) 5883 { 5884 *lastp = next; 5885 #ifdef FEAT_NETBEANS_INTG 5886 if (next != NULL) 5887 next->prev = sign->prev; 5888 #endif 5889 lnum = sign->lnum; 5890 vim_free(sign); 5891 break; 5892 } 5893 else 5894 lastp = &sign->next; 5895 } 5896 5897 /* When deleted the last sign need to redraw the windows to remove the 5898 * sign column. */ 5899 if (buf->b_signlist == NULL) 5900 { 5901 redraw_buf_later(buf, NOT_VALID); 5902 changed_cline_bef_curs(); 5903 } 5904 5905 return lnum; 5906 } 5907 5908 5909 /* 5910 * Find the line number of the sign with the requested id. If the sign does 5911 * not exist, return 0 as the line number. This will still let the correct file 5912 * get loaded. 5913 */ 5914 int 5915 buf_findsign( 5916 buf_T *buf, /* buffer to store sign in */ 5917 int id) /* sign ID */ 5918 { 5919 signlist_T *sign; /* a sign in the signlist */ 5920 5921 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5922 if (sign->id == id) 5923 return sign->lnum; 5924 5925 return 0; 5926 } 5927 5928 int 5929 buf_findsign_id( 5930 buf_T *buf, /* buffer whose sign we are searching for */ 5931 linenr_T lnum) /* line number of sign */ 5932 { 5933 signlist_T *sign; /* a sign in the signlist */ 5934 5935 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5936 if (sign->lnum == lnum) 5937 return sign->id; 5938 5939 return 0; 5940 } 5941 5942 5943 # if defined(FEAT_NETBEANS_INTG) || defined(PROTO) 5944 /* see if a given type of sign exists on a specific line */ 5945 int 5946 buf_findsigntype_id( 5947 buf_T *buf, /* buffer whose sign we are searching for */ 5948 linenr_T lnum, /* line number of sign */ 5949 int typenr) /* sign type number */ 5950 { 5951 signlist_T *sign; /* a sign in the signlist */ 5952 5953 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5954 if (sign->lnum == lnum && sign->typenr == typenr) 5955 return sign->id; 5956 5957 return 0; 5958 } 5959 5960 5961 # if defined(FEAT_SIGN_ICONS) || defined(PROTO) 5962 /* return the number of icons on the given line */ 5963 int 5964 buf_signcount(buf_T *buf, linenr_T lnum) 5965 { 5966 signlist_T *sign; /* a sign in the signlist */ 5967 int count = 0; 5968 5969 for (sign = buf->b_signlist; sign != NULL; sign = sign->next) 5970 if (sign->lnum == lnum) 5971 if (sign_get_image(sign->typenr) != NULL) 5972 count++; 5973 5974 return count; 5975 } 5976 # endif /* FEAT_SIGN_ICONS */ 5977 # endif /* FEAT_NETBEANS_INTG */ 5978 5979 5980 /* 5981 * Delete signs in buffer "buf". 5982 */ 5983 void 5984 buf_delete_signs(buf_T *buf) 5985 { 5986 signlist_T *next; 5987 5988 /* When deleting the last sign need to redraw the windows to remove the 5989 * sign column. Not when curwin is NULL (this means we're exiting). */ 5990 if (buf->b_signlist != NULL && curwin != NULL) 5991 { 5992 redraw_buf_later(buf, NOT_VALID); 5993 changed_cline_bef_curs(); 5994 } 5995 5996 while (buf->b_signlist != NULL) 5997 { 5998 next = buf->b_signlist->next; 5999 vim_free(buf->b_signlist); 6000 buf->b_signlist = next; 6001 } 6002 } 6003 6004 /* 6005 * Delete all signs in all buffers. 6006 */ 6007 void 6008 buf_delete_all_signs(void) 6009 { 6010 buf_T *buf; /* buffer we are checking for signs */ 6011 6012 FOR_ALL_BUFFERS(buf) 6013 if (buf->b_signlist != NULL) 6014 buf_delete_signs(buf); 6015 } 6016 6017 /* 6018 * List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers. 6019 */ 6020 void 6021 sign_list_placed(buf_T *rbuf) 6022 { 6023 buf_T *buf; 6024 signlist_T *p; 6025 char lbuf[BUFSIZ]; 6026 6027 MSG_PUTS_TITLE(_("\n--- Signs ---")); 6028 msg_putchar('\n'); 6029 if (rbuf == NULL) 6030 buf = firstbuf; 6031 else 6032 buf = rbuf; 6033 while (buf != NULL && !got_int) 6034 { 6035 if (buf->b_signlist != NULL) 6036 { 6037 vim_snprintf(lbuf, BUFSIZ, _("Signs for %s:"), buf->b_fname); 6038 MSG_PUTS_ATTR(lbuf, HL_ATTR(HLF_D)); 6039 msg_putchar('\n'); 6040 } 6041 for (p = buf->b_signlist; p != NULL && !got_int; p = p->next) 6042 { 6043 vim_snprintf(lbuf, BUFSIZ, _(" line=%ld id=%d name=%s"), 6044 (long)p->lnum, p->id, sign_typenr2name(p->typenr)); 6045 MSG_PUTS(lbuf); 6046 msg_putchar('\n'); 6047 } 6048 if (rbuf != NULL) 6049 break; 6050 buf = buf->b_next; 6051 } 6052 } 6053 6054 /* 6055 * Adjust a placed sign for inserted/deleted lines. 6056 */ 6057 void 6058 sign_mark_adjust( 6059 linenr_T line1, 6060 linenr_T line2, 6061 long amount, 6062 long amount_after) 6063 { 6064 signlist_T *sign; /* a sign in a b_signlist */ 6065 6066 for (sign = curbuf->b_signlist; sign != NULL; sign = sign->next) 6067 { 6068 if (sign->lnum >= line1 && sign->lnum <= line2) 6069 { 6070 if (amount == MAXLNUM) 6071 sign->lnum = line1; 6072 else 6073 sign->lnum += amount; 6074 } 6075 else if (sign->lnum > line2) 6076 sign->lnum += amount_after; 6077 } 6078 } 6079 #endif /* FEAT_SIGNS */ 6080 6081 /* 6082 * Set 'buflisted' for curbuf to "on" and trigger autocommands if it changed. 6083 */ 6084 void 6085 set_buflisted(int on) 6086 { 6087 if (on != curbuf->b_p_bl) 6088 { 6089 curbuf->b_p_bl = on; 6090 #ifdef FEAT_AUTOCMD 6091 if (on) 6092 apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf); 6093 else 6094 apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf); 6095 #endif 6096 } 6097 } 6098 6099 /* 6100 * Read the file for "buf" again and check if the contents changed. 6101 * Return TRUE if it changed or this could not be checked. 6102 */ 6103 int 6104 buf_contents_changed(buf_T *buf) 6105 { 6106 buf_T *newbuf; 6107 int differ = TRUE; 6108 linenr_T lnum; 6109 aco_save_T aco; 6110 exarg_T ea; 6111 6112 /* Allocate a buffer without putting it in the buffer list. */ 6113 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); 6114 if (newbuf == NULL) 6115 return TRUE; 6116 6117 /* Force the 'fileencoding' and 'fileformat' to be equal. */ 6118 if (prep_exarg(&ea, buf) == FAIL) 6119 { 6120 wipe_buffer(newbuf, FALSE); 6121 return TRUE; 6122 } 6123 6124 /* set curwin/curbuf to buf and save a few things */ 6125 aucmd_prepbuf(&aco, newbuf); 6126 6127 if (ml_open(curbuf) == OK 6128 && readfile(buf->b_ffname, buf->b_fname, 6129 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, 6130 &ea, READ_NEW | READ_DUMMY) == OK) 6131 { 6132 /* compare the two files line by line */ 6133 if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) 6134 { 6135 differ = FALSE; 6136 for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) 6137 if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0) 6138 { 6139 differ = TRUE; 6140 break; 6141 } 6142 } 6143 } 6144 vim_free(ea.cmd); 6145 6146 /* restore curwin/curbuf and a few other things */ 6147 aucmd_restbuf(&aco); 6148 6149 if (curbuf != newbuf) /* safety check */ 6150 wipe_buffer(newbuf, FALSE); 6151 6152 return differ; 6153 } 6154 6155 /* 6156 * Wipe out a buffer and decrement the last buffer number if it was used for 6157 * this buffer. Call this to wipe out a temp buffer that does not contain any 6158 * marks. 6159 */ 6160 void 6161 wipe_buffer( 6162 buf_T *buf, 6163 int aucmd UNUSED) /* When TRUE trigger autocommands. */ 6164 { 6165 if (buf->b_fnum == top_file_num - 1) 6166 --top_file_num; 6167 6168 #ifdef FEAT_AUTOCMD 6169 if (!aucmd) /* Don't trigger BufDelete autocommands here. */ 6170 block_autocmds(); 6171 #endif 6172 close_buffer(NULL, buf, DOBUF_WIPE, FALSE); 6173 #ifdef FEAT_AUTOCMD 6174 if (!aucmd) 6175 unblock_autocmds(); 6176 #endif 6177 } 6178