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