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