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