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