1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * evalbuffer.c: Buffer related builtin functions 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) || defined(PROTO) 17 /* 18 * Mark references in functions of buffers. 19 */ 20 int 21 set_ref_in_buffers(int copyID) 22 { 23 int abort = FALSE; 24 buf_T *bp; 25 26 FOR_ALL_BUFFERS(bp) 27 { 28 listener_T *lnr; 29 typval_T tv; 30 31 for (lnr = bp->b_listener; !abort && lnr != NULL; lnr = lnr->lr_next) 32 { 33 if (lnr->lr_callback.cb_partial != NULL) 34 { 35 tv.v_type = VAR_PARTIAL; 36 tv.vval.v_partial = lnr->lr_callback.cb_partial; 37 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); 38 } 39 } 40 # ifdef FEAT_JOB_CHANNEL 41 if (!abort && bp->b_prompt_callback.cb_partial != NULL) 42 { 43 tv.v_type = VAR_PARTIAL; 44 tv.vval.v_partial = bp->b_prompt_callback.cb_partial; 45 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); 46 } 47 if (!abort && bp->b_prompt_interrupt.cb_partial != NULL) 48 { 49 tv.v_type = VAR_PARTIAL; 50 tv.vval.v_partial = bp->b_prompt_interrupt.cb_partial; 51 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); 52 } 53 # endif 54 if (abort) 55 break; 56 } 57 return abort; 58 } 59 60 buf_T * 61 buflist_find_by_name(char_u *name, int curtab_only) 62 { 63 int save_magic; 64 char_u *save_cpo; 65 buf_T *buf; 66 67 // Ignore 'magic' and 'cpoptions' here to make scripts portable 68 save_magic = p_magic; 69 p_magic = TRUE; 70 save_cpo = p_cpo; 71 p_cpo = empty_option; 72 73 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), 74 TRUE, FALSE, curtab_only)); 75 76 p_magic = save_magic; 77 p_cpo = save_cpo; 78 return buf; 79 } 80 81 /* 82 * Find a buffer by number or exact name. 83 */ 84 buf_T * 85 find_buffer(typval_T *avar) 86 { 87 buf_T *buf = NULL; 88 89 if (avar->v_type == VAR_NUMBER) 90 buf = buflist_findnr((int)avar->vval.v_number); 91 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) 92 { 93 buf = buflist_findname_exp(avar->vval.v_string); 94 if (buf == NULL) 95 { 96 // No full path name match, try a match with a URL or a "nofile" 97 // buffer, these don't use the full path. 98 FOR_ALL_BUFFERS(buf) 99 if (buf->b_fname != NULL 100 && (path_with_url(buf->b_fname) 101 #ifdef FEAT_QUICKFIX 102 || bt_nofilename(buf) 103 #endif 104 ) 105 && STRCMP(buf->b_fname, avar->vval.v_string) == 0) 106 break; 107 } 108 } 109 return buf; 110 } 111 112 /* 113 * If there is a window for "curbuf", make it the current window. 114 */ 115 static void 116 find_win_for_curbuf(void) 117 { 118 wininfo_T *wip; 119 120 FOR_ALL_BUF_WININFO(curbuf, wip) 121 { 122 if (wip->wi_win != NULL) 123 { 124 curwin = wip->wi_win; 125 break; 126 } 127 } 128 } 129 130 /* 131 * Set line or list of lines in buffer "buf" to "lines". 132 * Any type is allowed and converted to a string. 133 */ 134 static void 135 set_buffer_lines( 136 buf_T *buf, 137 linenr_T lnum_arg, 138 int append, 139 typval_T *lines, 140 typval_T *rettv) 141 { 142 linenr_T lnum = lnum_arg + (append ? 1 : 0); 143 char_u *line = NULL; 144 list_T *l = NULL; 145 listitem_T *li = NULL; 146 long added = 0; 147 linenr_T append_lnum; 148 buf_T *curbuf_save = NULL; 149 win_T *curwin_save = NULL; 150 int is_curbuf = buf == curbuf; 151 152 // When using the current buffer ml_mfp will be set if needed. Useful when 153 // setline() is used on startup. For other buffers the buffer must be 154 // loaded. 155 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) 156 { 157 rettv->vval.v_number = 1; // FAIL 158 return; 159 } 160 161 if (!is_curbuf) 162 { 163 curbuf_save = curbuf; 164 curwin_save = curwin; 165 curbuf = buf; 166 find_win_for_curbuf(); 167 } 168 169 if (append) 170 // appendbufline() uses the line number below which we insert 171 append_lnum = lnum - 1; 172 else 173 // setbufline() uses the line number above which we insert, we only 174 // append if it's below the last line 175 append_lnum = curbuf->b_ml.ml_line_count; 176 177 if (lines->v_type == VAR_LIST) 178 { 179 l = lines->vval.v_list; 180 if (l == NULL || list_len(l) == 0) 181 { 182 // set proper return code 183 if (lnum > curbuf->b_ml.ml_line_count) 184 rettv->vval.v_number = 1; // FAIL 185 goto done; 186 } 187 CHECK_LIST_MATERIALIZE(l); 188 li = l->lv_first; 189 } 190 else 191 line = typval_tostring(lines, FALSE); 192 193 // default result is zero == OK 194 for (;;) 195 { 196 if (l != NULL) 197 { 198 // list argument, get next string 199 if (li == NULL) 200 break; 201 vim_free(line); 202 line = typval_tostring(&li->li_tv, FALSE); 203 li = li->li_next; 204 } 205 206 rettv->vval.v_number = 1; // FAIL 207 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) 208 break; 209 210 // When coming here from Insert mode, sync undo, so that this can be 211 // undone separately from what was previously inserted. 212 if (u_sync_once == 2) 213 { 214 u_sync_once = 1; // notify that u_sync() was called 215 u_sync(TRUE); 216 } 217 218 if (!append && lnum <= curbuf->b_ml.ml_line_count) 219 { 220 // Existing line, replace it. 221 // Removes any existing text properties. 222 if (u_savesub(lnum) == OK && ml_replace_len( 223 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK) 224 { 225 changed_bytes(lnum, 0); 226 if (is_curbuf && lnum == curwin->w_cursor.lnum) 227 check_cursor_col(); 228 rettv->vval.v_number = 0; // OK 229 } 230 } 231 else if (added > 0 || u_save(lnum - 1, lnum) == OK) 232 { 233 // append the line 234 ++added; 235 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) 236 rettv->vval.v_number = 0; // OK 237 } 238 239 if (l == NULL) // only one string argument 240 break; 241 ++lnum; 242 } 243 vim_free(line); 244 245 if (added > 0) 246 { 247 win_T *wp; 248 tabpage_T *tp; 249 250 appended_lines_mark(append_lnum, added); 251 252 // Only adjust the cursor for buffers other than the current, unless it 253 // is the current window. For curbuf and other windows it has been 254 // done in mark_adjust_internal(). 255 FOR_ALL_TAB_WINDOWS(tp, wp) 256 if (wp->w_buffer == buf 257 && (wp->w_buffer != curbuf || wp == curwin) 258 && wp->w_cursor.lnum > append_lnum) 259 wp->w_cursor.lnum += added; 260 check_cursor_col(); 261 update_topline(); 262 } 263 264 done: 265 if (!is_curbuf) 266 { 267 curbuf = curbuf_save; 268 curwin = curwin_save; 269 } 270 } 271 272 /* 273 * "append(lnum, string/list)" function 274 */ 275 void 276 f_append(typval_T *argvars, typval_T *rettv) 277 { 278 linenr_T lnum = tv_get_lnum(&argvars[0]); 279 280 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv); 281 } 282 283 /* 284 * "appendbufline(buf, lnum, string/list)" function 285 */ 286 void 287 f_appendbufline(typval_T *argvars, typval_T *rettv) 288 { 289 linenr_T lnum; 290 buf_T *buf; 291 292 buf = tv_get_buf(&argvars[0], FALSE); 293 if (buf == NULL) 294 rettv->vval.v_number = 1; // FAIL 295 else 296 { 297 lnum = tv_get_lnum_buf(&argvars[1], buf); 298 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv); 299 } 300 } 301 302 /* 303 * "bufadd(expr)" function 304 */ 305 void 306 f_bufadd(typval_T *argvars, typval_T *rettv) 307 { 308 char_u *name = tv_get_string(&argvars[0]); 309 310 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0); 311 } 312 313 /* 314 * "bufexists(expr)" function 315 */ 316 void 317 f_bufexists(typval_T *argvars, typval_T *rettv) 318 { 319 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); 320 } 321 322 /* 323 * "buflisted(expr)" function 324 */ 325 void 326 f_buflisted(typval_T *argvars, typval_T *rettv) 327 { 328 buf_T *buf; 329 330 buf = find_buffer(&argvars[0]); 331 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); 332 } 333 334 /* 335 * "bufload(expr)" function 336 */ 337 void 338 f_bufload(typval_T *argvars, typval_T *rettv UNUSED) 339 { 340 buf_T *buf = get_buf_arg(&argvars[0]); 341 342 if (buf != NULL) 343 buffer_ensure_loaded(buf); 344 } 345 346 /* 347 * "bufloaded(expr)" function 348 */ 349 void 350 f_bufloaded(typval_T *argvars, typval_T *rettv) 351 { 352 buf_T *buf; 353 354 buf = find_buffer(&argvars[0]); 355 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); 356 } 357 358 /* 359 * "bufname(expr)" function 360 */ 361 void 362 f_bufname(typval_T *argvars, typval_T *rettv) 363 { 364 buf_T *buf; 365 typval_T *tv = &argvars[0]; 366 367 if (tv->v_type == VAR_UNKNOWN) 368 buf = curbuf; 369 else 370 buf = tv_get_buf_from_arg(tv); 371 rettv->v_type = VAR_STRING; 372 if (buf != NULL && buf->b_fname != NULL) 373 rettv->vval.v_string = vim_strsave(buf->b_fname); 374 else 375 rettv->vval.v_string = NULL; 376 } 377 378 /* 379 * "bufnr(expr)" function 380 */ 381 void 382 f_bufnr(typval_T *argvars, typval_T *rettv) 383 { 384 buf_T *buf; 385 int error = FALSE; 386 char_u *name; 387 388 if (argvars[0].v_type == VAR_UNKNOWN) 389 buf = curbuf; 390 else 391 buf = tv_get_buf_from_arg(&argvars[0]); 392 393 // If the buffer isn't found and the second argument is not zero create a 394 // new buffer. 395 if (buf == NULL 396 && argvars[1].v_type != VAR_UNKNOWN 397 && tv_get_bool_chk(&argvars[1], &error) != 0 398 && !error 399 && (name = tv_get_string_chk(&argvars[0])) != NULL 400 && !error) 401 buf = buflist_new(name, NULL, (linenr_T)1, 0); 402 403 if (buf != NULL) 404 rettv->vval.v_number = buf->b_fnum; 405 else 406 rettv->vval.v_number = -1; 407 } 408 409 static void 410 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) 411 { 412 win_T *wp; 413 int winnr = 0; 414 buf_T *buf; 415 416 buf = tv_get_buf_from_arg(&argvars[0]); 417 FOR_ALL_WINDOWS(wp) 418 { 419 ++winnr; 420 if (wp->w_buffer == buf) 421 break; 422 } 423 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); 424 } 425 426 /* 427 * "bufwinid(nr)" function 428 */ 429 void 430 f_bufwinid(typval_T *argvars, typval_T *rettv) 431 { 432 buf_win_common(argvars, rettv, FALSE); 433 } 434 435 /* 436 * "bufwinnr(nr)" function 437 */ 438 void 439 f_bufwinnr(typval_T *argvars, typval_T *rettv) 440 { 441 buf_win_common(argvars, rettv, TRUE); 442 } 443 444 /* 445 * "deletebufline()" function 446 */ 447 void 448 f_deletebufline(typval_T *argvars, typval_T *rettv) 449 { 450 buf_T *buf; 451 linenr_T first, last; 452 linenr_T lnum; 453 long count; 454 int is_curbuf; 455 buf_T *curbuf_save = NULL; 456 win_T *curwin_save = NULL; 457 tabpage_T *tp; 458 win_T *wp; 459 460 buf = tv_get_buf(&argvars[0], FALSE); 461 if (buf == NULL) 462 { 463 rettv->vval.v_number = 1; // FAIL 464 return; 465 } 466 is_curbuf = buf == curbuf; 467 468 first = tv_get_lnum_buf(&argvars[1], buf); 469 if (argvars[2].v_type != VAR_UNKNOWN) 470 last = tv_get_lnum_buf(&argvars[2], buf); 471 else 472 last = first; 473 474 if (buf->b_ml.ml_mfp == NULL || first < 1 475 || first > buf->b_ml.ml_line_count || last < first) 476 { 477 rettv->vval.v_number = 1; // FAIL 478 return; 479 } 480 481 if (!is_curbuf) 482 { 483 curbuf_save = curbuf; 484 curwin_save = curwin; 485 curbuf = buf; 486 find_win_for_curbuf(); 487 } 488 if (last > curbuf->b_ml.ml_line_count) 489 last = curbuf->b_ml.ml_line_count; 490 count = last - first + 1; 491 492 // When coming here from Insert mode, sync undo, so that this can be 493 // undone separately from what was previously inserted. 494 if (u_sync_once == 2) 495 { 496 u_sync_once = 1; // notify that u_sync() was called 497 u_sync(TRUE); 498 } 499 500 if (u_save(first - 1, last + 1) == FAIL) 501 { 502 rettv->vval.v_number = 1; // FAIL 503 } 504 else 505 { 506 for (lnum = first; lnum <= last; ++lnum) 507 ml_delete_flags(first, ML_DEL_MESSAGE); 508 509 FOR_ALL_TAB_WINDOWS(tp, wp) 510 if (wp->w_buffer == buf) 511 { 512 if (wp->w_cursor.lnum > last) 513 wp->w_cursor.lnum -= count; 514 else if (wp->w_cursor.lnum> first) 515 wp->w_cursor.lnum = first; 516 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) 517 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; 518 } 519 check_cursor_col(); 520 deleted_lines_mark(first, count); 521 } 522 523 if (!is_curbuf) 524 { 525 curbuf = curbuf_save; 526 curwin = curwin_save; 527 } 528 } 529 530 /* 531 * Returns buffer options, variables and other attributes in a dictionary. 532 */ 533 static dict_T * 534 get_buffer_info(buf_T *buf) 535 { 536 dict_T *dict; 537 tabpage_T *tp; 538 win_T *wp; 539 list_T *windows; 540 541 dict = dict_alloc(); 542 if (dict == NULL) 543 return NULL; 544 545 dict_add_number(dict, "bufnr", buf->b_fnum); 546 dict_add_string(dict, "name", buf->b_ffname); 547 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum 548 : buflist_findlnum(buf)); 549 dict_add_number(dict, "linecount", buf->b_ml.ml_line_count); 550 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL); 551 dict_add_number(dict, "listed", buf->b_p_bl); 552 dict_add_number(dict, "changed", bufIsChanged(buf)); 553 dict_add_number(dict, "changedtick", CHANGEDTICK(buf)); 554 dict_add_number(dict, "hidden", 555 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0); 556 557 // Get a reference to buffer variables 558 dict_add_dict(dict, "variables", buf->b_vars); 559 560 // List of windows displaying this buffer 561 windows = list_alloc(); 562 if (windows != NULL) 563 { 564 FOR_ALL_TAB_WINDOWS(tp, wp) 565 if (wp->w_buffer == buf) 566 list_append_number(windows, (varnumber_T)wp->w_id); 567 dict_add_list(dict, "windows", windows); 568 } 569 570 #ifdef FEAT_PROP_POPUP 571 // List of popup windows displaying this buffer 572 windows = list_alloc(); 573 if (windows != NULL) 574 { 575 FOR_ALL_POPUPWINS(wp) 576 if (wp->w_buffer == buf) 577 list_append_number(windows, (varnumber_T)wp->w_id); 578 FOR_ALL_TABPAGES(tp) 579 FOR_ALL_POPUPWINS_IN_TAB(tp, wp) 580 if (wp->w_buffer == buf) 581 list_append_number(windows, (varnumber_T)wp->w_id); 582 583 dict_add_list(dict, "popups", windows); 584 } 585 #endif 586 587 #ifdef FEAT_SIGNS 588 if (buf->b_signlist != NULL) 589 { 590 // List of signs placed in this buffer 591 list_T *signs = list_alloc(); 592 if (signs != NULL) 593 { 594 get_buffer_signs(buf, signs); 595 dict_add_list(dict, "signs", signs); 596 } 597 } 598 #endif 599 600 #ifdef FEAT_VIMINFO 601 dict_add_number(dict, "lastused", buf->b_last_used); 602 #endif 603 604 return dict; 605 } 606 607 /* 608 * "getbufinfo()" function 609 */ 610 void 611 f_getbufinfo(typval_T *argvars, typval_T *rettv) 612 { 613 buf_T *buf = NULL; 614 buf_T *argbuf = NULL; 615 dict_T *d; 616 int filtered = FALSE; 617 int sel_buflisted = FALSE; 618 int sel_bufloaded = FALSE; 619 int sel_bufmodified = FALSE; 620 621 if (rettv_list_alloc(rettv) != OK) 622 return; 623 624 // List of all the buffers or selected buffers 625 if (argvars[0].v_type == VAR_DICT) 626 { 627 dict_T *sel_d = argvars[0].vval.v_dict; 628 629 if (sel_d != NULL) 630 { 631 filtered = TRUE; 632 sel_buflisted = dict_get_bool(sel_d, (char_u *)"buflisted", FALSE); 633 sel_bufloaded = dict_get_bool(sel_d, (char_u *)"bufloaded", FALSE); 634 sel_bufmodified = dict_get_bool(sel_d, (char_u *)"bufmodified", 635 FALSE); 636 } 637 } 638 else if (argvars[0].v_type != VAR_UNKNOWN) 639 { 640 // Information about one buffer. Argument specifies the buffer 641 argbuf = tv_get_buf_from_arg(&argvars[0]); 642 if (argbuf == NULL) 643 return; 644 } 645 646 // Return information about all the buffers or a specified buffer 647 FOR_ALL_BUFFERS(buf) 648 { 649 if (argbuf != NULL && argbuf != buf) 650 continue; 651 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) 652 || (sel_buflisted && !buf->b_p_bl) 653 || (sel_bufmodified && !buf->b_changed))) 654 continue; 655 656 d = get_buffer_info(buf); 657 if (d != NULL) 658 list_append_dict(rettv->vval.v_list, d); 659 if (argbuf != NULL) 660 return; 661 } 662 } 663 664 /* 665 * Get line or list of lines from buffer "buf" into "rettv". 666 * Return a range (from start to end) of lines in rettv from the specified 667 * buffer. 668 * If 'retlist' is TRUE, then the lines are returned as a Vim List. 669 */ 670 static void 671 get_buffer_lines( 672 buf_T *buf, 673 linenr_T start, 674 linenr_T end, 675 int retlist, 676 typval_T *rettv) 677 { 678 char_u *p; 679 680 if (retlist) 681 { 682 if (rettv_list_alloc(rettv) == FAIL) 683 return; 684 } 685 else 686 { 687 rettv->v_type = VAR_STRING; 688 rettv->vval.v_string = NULL; 689 } 690 691 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) 692 return; 693 694 if (!retlist) 695 { 696 if (start >= 1 && start <= buf->b_ml.ml_line_count) 697 p = ml_get_buf(buf, start, FALSE); 698 else 699 p = (char_u *)""; 700 rettv->vval.v_string = vim_strsave(p); 701 } 702 else 703 { 704 if (end < start) 705 return; 706 707 if (start < 1) 708 start = 1; 709 if (end > buf->b_ml.ml_line_count) 710 end = buf->b_ml.ml_line_count; 711 while (start <= end) 712 if (list_append_string(rettv->vval.v_list, 713 ml_get_buf(buf, start++, FALSE), -1) == FAIL) 714 break; 715 } 716 } 717 718 /* 719 * "getbufline()" function 720 */ 721 void 722 f_getbufline(typval_T *argvars, typval_T *rettv) 723 { 724 linenr_T lnum = 1; 725 linenr_T end = 1; 726 buf_T *buf; 727 728 buf = tv_get_buf_from_arg(&argvars[0]); 729 if (buf != NULL) 730 { 731 lnum = tv_get_lnum_buf(&argvars[1], buf); 732 if (argvars[2].v_type == VAR_UNKNOWN) 733 end = lnum; 734 else 735 end = tv_get_lnum_buf(&argvars[2], buf); 736 } 737 738 get_buffer_lines(buf, lnum, end, TRUE, rettv); 739 } 740 741 type_T * 742 ret_f_getline(int argcount, type_T **argtypes UNUSED) 743 { 744 return argcount == 1 ? &t_string : &t_list_string; 745 } 746 747 /* 748 * "getline(lnum, [end])" function 749 */ 750 void 751 f_getline(typval_T *argvars, typval_T *rettv) 752 { 753 linenr_T lnum; 754 linenr_T end; 755 int retlist; 756 757 lnum = tv_get_lnum(argvars); 758 if (argvars[1].v_type == VAR_UNKNOWN) 759 { 760 end = 0; 761 retlist = FALSE; 762 } 763 else 764 { 765 end = tv_get_lnum(&argvars[1]); 766 retlist = TRUE; 767 } 768 769 get_buffer_lines(curbuf, lnum, end, retlist, rettv); 770 } 771 772 /* 773 * "setbufline()" function 774 */ 775 void 776 f_setbufline(typval_T *argvars, typval_T *rettv) 777 { 778 linenr_T lnum; 779 buf_T *buf; 780 781 buf = tv_get_buf(&argvars[0], FALSE); 782 if (buf == NULL) 783 rettv->vval.v_number = 1; // FAIL 784 else 785 { 786 lnum = tv_get_lnum_buf(&argvars[1], buf); 787 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv); 788 } 789 } 790 791 /* 792 * "setline()" function 793 */ 794 void 795 f_setline(typval_T *argvars, typval_T *rettv) 796 { 797 linenr_T lnum = tv_get_lnum(&argvars[0]); 798 799 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv); 800 } 801 #endif // FEAT_EVAL 802 803 #if defined(FEAT_JOB_CHANNEL) \ 804 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \ 805 || defined(PROTO) 806 /* 807 * Make "buf" the current buffer. restore_buffer() MUST be called to undo. 808 * No autocommands will be executed. Use aucmd_prepbuf() if there are any. 809 */ 810 void 811 switch_buffer(bufref_T *save_curbuf, buf_T *buf) 812 { 813 block_autocmds(); 814 #ifdef FEAT_FOLDING 815 ++disable_fold_update; 816 #endif 817 set_bufref(save_curbuf, curbuf); 818 --curbuf->b_nwindows; 819 curbuf = buf; 820 curwin->w_buffer = buf; 821 ++curbuf->b_nwindows; 822 } 823 824 /* 825 * Restore the current buffer after using switch_buffer(). 826 */ 827 void 828 restore_buffer(bufref_T *save_curbuf) 829 { 830 unblock_autocmds(); 831 #ifdef FEAT_FOLDING 832 --disable_fold_update; 833 #endif 834 // Check for valid buffer, just in case. 835 if (bufref_valid(save_curbuf)) 836 { 837 --curbuf->b_nwindows; 838 curwin->w_buffer = save_curbuf->br_buf; 839 curbuf = save_curbuf->br_buf; 840 ++curbuf->b_nwindows; 841 } 842 } 843 844 /* 845 * Find a window for buffer "buf". 846 * If found OK is returned and "wp" and "tp" are set to the window and tabpage. 847 * If not found FAIL is returned. 848 */ 849 static int 850 find_win_for_buf( 851 buf_T *buf, 852 win_T **wp, 853 tabpage_T **tp) 854 { 855 FOR_ALL_TAB_WINDOWS(*tp, *wp) 856 if ((*wp)->w_buffer == buf) 857 return OK; 858 return FAIL; 859 } 860 861 /* 862 * Find a window that contains "buf" and switch to it. 863 * If there is no such window, use the current window and change "curbuf". 864 * Caller must initialize save_curbuf to NULL. 865 * restore_win_for_buf() MUST be called later! 866 */ 867 void 868 switch_to_win_for_buf( 869 buf_T *buf, 870 win_T **save_curwinp, 871 tabpage_T **save_curtabp, 872 bufref_T *save_curbuf) 873 { 874 win_T *wp; 875 tabpage_T *tp; 876 877 if (find_win_for_buf(buf, &wp, &tp) == FAIL) 878 switch_buffer(save_curbuf, buf); 879 else if (switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL) 880 { 881 restore_win(*save_curwinp, *save_curtabp, TRUE); 882 switch_buffer(save_curbuf, buf); 883 } 884 } 885 886 void 887 restore_win_for_buf( 888 win_T *save_curwin, 889 tabpage_T *save_curtab, 890 bufref_T *save_curbuf) 891 { 892 if (save_curbuf->br_buf == NULL) 893 restore_win(save_curwin, save_curtab, TRUE); 894 else 895 restore_buffer(save_curbuf); 896 } 897 #endif 898