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 = (char_u *)""; 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 (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) 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". 132 */ 133 static void 134 set_buffer_lines( 135 buf_T *buf, 136 linenr_T lnum_arg, 137 int append, 138 typval_T *lines, 139 typval_T *rettv) 140 { 141 linenr_T lnum = lnum_arg + (append ? 1 : 0); 142 char_u *line = NULL; 143 list_T *l = NULL; 144 listitem_T *li = NULL; 145 long added = 0; 146 linenr_T append_lnum; 147 buf_T *curbuf_save = NULL; 148 win_T *curwin_save = NULL; 149 int is_curbuf = buf == curbuf; 150 151 // When using the current buffer ml_mfp will be set if needed. Useful when 152 // setline() is used on startup. For other buffers the buffer must be 153 // loaded. 154 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) 155 { 156 rettv->vval.v_number = 1; // FAIL 157 return; 158 } 159 160 if (!is_curbuf) 161 { 162 curbuf_save = curbuf; 163 curwin_save = curwin; 164 curbuf = buf; 165 find_win_for_curbuf(); 166 } 167 168 if (append) 169 // appendbufline() uses the line number below which we insert 170 append_lnum = lnum - 1; 171 else 172 // setbufline() uses the line number above which we insert, we only 173 // append if it's below the last line 174 append_lnum = curbuf->b_ml.ml_line_count; 175 176 if (lines->v_type == VAR_LIST) 177 { 178 l = lines->vval.v_list; 179 li = l->lv_first; 180 } 181 else 182 line = tv_get_string_chk(lines); 183 184 // default result is zero == OK 185 for (;;) 186 { 187 if (l != NULL) 188 { 189 // list argument, get next string 190 if (li == NULL) 191 break; 192 line = tv_get_string_chk(&li->li_tv); 193 li = li->li_next; 194 } 195 196 rettv->vval.v_number = 1; // FAIL 197 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) 198 break; 199 200 // When coming here from Insert mode, sync undo, so that this can be 201 // undone separately from what was previously inserted. 202 if (u_sync_once == 2) 203 { 204 u_sync_once = 1; // notify that u_sync() was called 205 u_sync(TRUE); 206 } 207 208 if (!append && lnum <= curbuf->b_ml.ml_line_count) 209 { 210 // Existing line, replace it. 211 // Removes any existing text properties. 212 if (u_savesub(lnum) == OK && ml_replace_len( 213 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK) 214 { 215 changed_bytes(lnum, 0); 216 if (is_curbuf && lnum == curwin->w_cursor.lnum) 217 check_cursor_col(); 218 rettv->vval.v_number = 0; // OK 219 } 220 } 221 else if (added > 0 || u_save(lnum - 1, lnum) == OK) 222 { 223 // append the line 224 ++added; 225 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) 226 rettv->vval.v_number = 0; // OK 227 } 228 229 if (l == NULL) // only one string argument 230 break; 231 ++lnum; 232 } 233 234 if (added > 0) 235 { 236 win_T *wp; 237 tabpage_T *tp; 238 239 appended_lines_mark(append_lnum, added); 240 241 // Only adjust the cursor for buffers other than the current, unless it 242 // is the current window. For curbuf and other windows it has been 243 // done in mark_adjust_internal(). 244 FOR_ALL_TAB_WINDOWS(tp, wp) 245 if (wp->w_buffer == buf 246 && (wp->w_buffer != curbuf || wp == curwin) 247 && wp->w_cursor.lnum > append_lnum) 248 wp->w_cursor.lnum += added; 249 check_cursor_col(); 250 update_topline(); 251 } 252 253 if (!is_curbuf) 254 { 255 curbuf = curbuf_save; 256 curwin = curwin_save; 257 } 258 } 259 260 /* 261 * "append(lnum, string/list)" function 262 */ 263 void 264 f_append(typval_T *argvars, typval_T *rettv) 265 { 266 linenr_T lnum = tv_get_lnum(&argvars[0]); 267 268 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv); 269 } 270 271 /* 272 * "appendbufline(buf, lnum, string/list)" function 273 */ 274 void 275 f_appendbufline(typval_T *argvars, typval_T *rettv) 276 { 277 linenr_T lnum; 278 buf_T *buf; 279 280 buf = tv_get_buf(&argvars[0], FALSE); 281 if (buf == NULL) 282 rettv->vval.v_number = 1; // FAIL 283 else 284 { 285 lnum = tv_get_lnum_buf(&argvars[1], buf); 286 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv); 287 } 288 } 289 290 /* 291 * "bufadd(expr)" function 292 */ 293 void 294 f_bufadd(typval_T *argvars, typval_T *rettv) 295 { 296 char_u *name = tv_get_string(&argvars[0]); 297 298 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0); 299 } 300 301 /* 302 * "bufexists(expr)" function 303 */ 304 void 305 f_bufexists(typval_T *argvars, typval_T *rettv) 306 { 307 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); 308 } 309 310 /* 311 * "buflisted(expr)" function 312 */ 313 void 314 f_buflisted(typval_T *argvars, typval_T *rettv) 315 { 316 buf_T *buf; 317 318 buf = find_buffer(&argvars[0]); 319 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); 320 } 321 322 /* 323 * "bufload(expr)" function 324 */ 325 void 326 f_bufload(typval_T *argvars, typval_T *rettv UNUSED) 327 { 328 buf_T *buf = get_buf_arg(&argvars[0]); 329 330 if (buf != NULL) 331 buffer_ensure_loaded(buf); 332 } 333 334 /* 335 * "bufloaded(expr)" function 336 */ 337 void 338 f_bufloaded(typval_T *argvars, typval_T *rettv) 339 { 340 buf_T *buf; 341 342 buf = find_buffer(&argvars[0]); 343 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); 344 } 345 346 /* 347 * "bufname(expr)" function 348 */ 349 void 350 f_bufname(typval_T *argvars, typval_T *rettv) 351 { 352 buf_T *buf; 353 354 if (argvars[0].v_type == VAR_UNKNOWN) 355 buf = curbuf; 356 else 357 { 358 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 359 ++emsg_off; 360 buf = tv_get_buf(&argvars[0], FALSE); 361 --emsg_off; 362 } 363 rettv->v_type = VAR_STRING; 364 if (buf != NULL && buf->b_fname != NULL) 365 rettv->vval.v_string = vim_strsave(buf->b_fname); 366 else 367 rettv->vval.v_string = NULL; 368 } 369 370 /* 371 * "bufnr(expr)" function 372 */ 373 void 374 f_bufnr(typval_T *argvars, typval_T *rettv) 375 { 376 buf_T *buf; 377 int error = FALSE; 378 char_u *name; 379 380 if (argvars[0].v_type == VAR_UNKNOWN) 381 buf = curbuf; 382 else 383 { 384 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 385 ++emsg_off; 386 buf = tv_get_buf(&argvars[0], FALSE); 387 --emsg_off; 388 } 389 390 // If the buffer isn't found and the second argument is not zero create a 391 // new buffer. 392 if (buf == NULL 393 && argvars[1].v_type != VAR_UNKNOWN 394 && tv_get_number_chk(&argvars[1], &error) != 0 395 && !error 396 && (name = tv_get_string_chk(&argvars[0])) != NULL 397 && !error) 398 buf = buflist_new(name, NULL, (linenr_T)1, 0); 399 400 if (buf != NULL) 401 rettv->vval.v_number = buf->b_fnum; 402 else 403 rettv->vval.v_number = -1; 404 } 405 406 static void 407 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) 408 { 409 win_T *wp; 410 int winnr = 0; 411 buf_T *buf; 412 413 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 414 ++emsg_off; 415 buf = tv_get_buf(&argvars[0], TRUE); 416 FOR_ALL_WINDOWS(wp) 417 { 418 ++winnr; 419 if (wp->w_buffer == buf) 420 break; 421 } 422 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); 423 --emsg_off; 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 return; 504 } 505 506 for (lnum = first; lnum <= last; ++lnum) 507 ml_delete(first, TRUE); 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 if (!is_curbuf) 523 { 524 curbuf = curbuf_save; 525 curwin = curwin_save; 526 } 527 } 528 529 /* 530 * Returns buffer options, variables and other attributes in a dictionary. 531 */ 532 static dict_T * 533 get_buffer_info(buf_T *buf) 534 { 535 dict_T *dict; 536 tabpage_T *tp; 537 win_T *wp; 538 list_T *windows; 539 540 dict = dict_alloc(); 541 if (dict == NULL) 542 return NULL; 543 544 dict_add_number(dict, "bufnr", buf->b_fnum); 545 dict_add_string(dict, "name", buf->b_ffname); 546 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum 547 : buflist_findlnum(buf)); 548 dict_add_number(dict, "linecount", buf->b_ml.ml_line_count); 549 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL); 550 dict_add_number(dict, "listed", buf->b_p_bl); 551 dict_add_number(dict, "changed", bufIsChanged(buf)); 552 dict_add_number(dict, "changedtick", CHANGEDTICK(buf)); 553 dict_add_number(dict, "hidden", 554 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0); 555 556 // Get a reference to buffer variables 557 dict_add_dict(dict, "variables", buf->b_vars); 558 559 // List of windows displaying this buffer 560 windows = list_alloc(); 561 if (windows != NULL) 562 { 563 FOR_ALL_TAB_WINDOWS(tp, wp) 564 if (wp->w_buffer == buf) 565 list_append_number(windows, (varnumber_T)wp->w_id); 566 dict_add_list(dict, "windows", windows); 567 } 568 569 #ifdef FEAT_PROP_POPUP 570 // List of popup windows displaying this buffer 571 windows = list_alloc(); 572 if (windows != NULL) 573 { 574 for (wp = first_popupwin; wp != NULL; wp = wp->w_next) 575 if (wp->w_buffer == buf) 576 list_append_number(windows, (varnumber_T)wp->w_id); 577 FOR_ALL_TABPAGES(tp) 578 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next) 579 if (wp->w_buffer == buf) 580 list_append_number(windows, (varnumber_T)wp->w_id); 581 582 dict_add_list(dict, "popups", windows); 583 } 584 #endif 585 586 #ifdef FEAT_SIGNS 587 if (buf->b_signlist != NULL) 588 { 589 // List of signs placed in this buffer 590 list_T *signs = list_alloc(); 591 if (signs != NULL) 592 { 593 get_buffer_signs(buf, signs); 594 dict_add_list(dict, "signs", signs); 595 } 596 } 597 #endif 598 599 #ifdef FEAT_VIMINFO 600 dict_add_number(dict, "lastused", buf->b_last_used); 601 #endif 602 603 return dict; 604 } 605 606 /* 607 * "getbufinfo()" function 608 */ 609 void 610 f_getbufinfo(typval_T *argvars, typval_T *rettv) 611 { 612 buf_T *buf = NULL; 613 buf_T *argbuf = NULL; 614 dict_T *d; 615 int filtered = FALSE; 616 int sel_buflisted = FALSE; 617 int sel_bufloaded = FALSE; 618 int sel_bufmodified = FALSE; 619 620 if (rettv_list_alloc(rettv) != OK) 621 return; 622 623 // List of all the buffers or selected buffers 624 if (argvars[0].v_type == VAR_DICT) 625 { 626 dict_T *sel_d = argvars[0].vval.v_dict; 627 628 if (sel_d != NULL) 629 { 630 dictitem_T *di; 631 632 filtered = TRUE; 633 634 di = dict_find(sel_d, (char_u *)"buflisted", -1); 635 if (di != NULL && tv_get_number(&di->di_tv)) 636 sel_buflisted = TRUE; 637 638 di = dict_find(sel_d, (char_u *)"bufloaded", -1); 639 if (di != NULL && tv_get_number(&di->di_tv)) 640 sel_bufloaded = TRUE; 641 642 di = dict_find(sel_d, (char_u *)"bufmodified", -1); 643 if (di != NULL && tv_get_number(&di->di_tv)) 644 sel_bufmodified = TRUE; 645 } 646 } 647 else if (argvars[0].v_type != VAR_UNKNOWN) 648 { 649 // Information about one buffer. Argument specifies the buffer 650 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 651 ++emsg_off; 652 argbuf = tv_get_buf(&argvars[0], FALSE); 653 --emsg_off; 654 if (argbuf == NULL) 655 return; 656 } 657 658 // Return information about all the buffers or a specified buffer 659 FOR_ALL_BUFFERS(buf) 660 { 661 if (argbuf != NULL && argbuf != buf) 662 continue; 663 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) 664 || (sel_buflisted && !buf->b_p_bl) 665 || (sel_bufmodified && !buf->b_changed))) 666 continue; 667 668 d = get_buffer_info(buf); 669 if (d != NULL) 670 list_append_dict(rettv->vval.v_list, d); 671 if (argbuf != NULL) 672 return; 673 } 674 } 675 676 /* 677 * Get line or list of lines from buffer "buf" into "rettv". 678 * Return a range (from start to end) of lines in rettv from the specified 679 * buffer. 680 * If 'retlist' is TRUE, then the lines are returned as a Vim List. 681 */ 682 static void 683 get_buffer_lines( 684 buf_T *buf, 685 linenr_T start, 686 linenr_T end, 687 int retlist, 688 typval_T *rettv) 689 { 690 char_u *p; 691 692 rettv->v_type = VAR_STRING; 693 rettv->vval.v_string = NULL; 694 if (retlist && rettv_list_alloc(rettv) == FAIL) 695 return; 696 697 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) 698 return; 699 700 if (!retlist) 701 { 702 if (start >= 1 && start <= buf->b_ml.ml_line_count) 703 p = ml_get_buf(buf, start, FALSE); 704 else 705 p = (char_u *)""; 706 rettv->vval.v_string = vim_strsave(p); 707 } 708 else 709 { 710 if (end < start) 711 return; 712 713 if (start < 1) 714 start = 1; 715 if (end > buf->b_ml.ml_line_count) 716 end = buf->b_ml.ml_line_count; 717 while (start <= end) 718 if (list_append_string(rettv->vval.v_list, 719 ml_get_buf(buf, start++, FALSE), -1) == FAIL) 720 break; 721 } 722 } 723 724 /* 725 * "getbufline()" function 726 */ 727 void 728 f_getbufline(typval_T *argvars, typval_T *rettv) 729 { 730 linenr_T lnum; 731 linenr_T end; 732 buf_T *buf; 733 734 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 735 ++emsg_off; 736 buf = tv_get_buf(&argvars[0], FALSE); 737 --emsg_off; 738 739 lnum = tv_get_lnum_buf(&argvars[1], buf); 740 if (argvars[2].v_type == VAR_UNKNOWN) 741 end = lnum; 742 else 743 end = tv_get_lnum_buf(&argvars[2], buf); 744 745 get_buffer_lines(buf, lnum, end, TRUE, rettv); 746 } 747 748 /* 749 * "getline(lnum, [end])" function 750 */ 751 void 752 f_getline(typval_T *argvars, typval_T *rettv) 753 { 754 linenr_T lnum; 755 linenr_T end; 756 int retlist; 757 758 lnum = tv_get_lnum(argvars); 759 if (argvars[1].v_type == VAR_UNKNOWN) 760 { 761 end = 0; 762 retlist = FALSE; 763 } 764 else 765 { 766 end = tv_get_lnum(&argvars[1]); 767 retlist = TRUE; 768 } 769 770 get_buffer_lines(curbuf, lnum, end, retlist, rettv); 771 } 772 773 /* 774 * "setbufline()" function 775 */ 776 void 777 f_setbufline(typval_T *argvars, typval_T *rettv) 778 { 779 linenr_T lnum; 780 buf_T *buf; 781 782 buf = tv_get_buf(&argvars[0], FALSE); 783 if (buf == NULL) 784 rettv->vval.v_number = 1; // FAIL 785 else 786 { 787 lnum = tv_get_lnum_buf(&argvars[1], buf); 788 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv); 789 } 790 } 791 792 /* 793 * "setline()" function 794 */ 795 void 796 f_setline(typval_T *argvars, typval_T *rettv) 797 { 798 linenr_T lnum = tv_get_lnum(&argvars[0]); 799 800 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv); 801 } 802 #endif // FEAT_EVAL 803 804 #if defined(FEAT_JOB_CHANNEL) \ 805 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \ 806 || defined(PROTO) 807 /* 808 * Make "buf" the current buffer. restore_buffer() MUST be called to undo. 809 * No autocommands will be executed. Use aucmd_prepbuf() if there are any. 810 */ 811 void 812 switch_buffer(bufref_T *save_curbuf, buf_T *buf) 813 { 814 block_autocmds(); 815 set_bufref(save_curbuf, curbuf); 816 --curbuf->b_nwindows; 817 curbuf = buf; 818 curwin->w_buffer = buf; 819 ++curbuf->b_nwindows; 820 } 821 822 /* 823 * Restore the current buffer after using switch_buffer(). 824 */ 825 void 826 restore_buffer(bufref_T *save_curbuf) 827 { 828 unblock_autocmds(); 829 // Check for valid buffer, just in case. 830 if (bufref_valid(save_curbuf)) 831 { 832 --curbuf->b_nwindows; 833 curwin->w_buffer = save_curbuf->br_buf; 834 curbuf = save_curbuf->br_buf; 835 ++curbuf->b_nwindows; 836 } 837 } 838 839 /* 840 * Find a window for buffer "buf". 841 * If found OK is returned and "wp" and "tp" are set to the window and tabpage. 842 * If not found FAIL is returned. 843 */ 844 static int 845 find_win_for_buf( 846 buf_T *buf, 847 win_T **wp, 848 tabpage_T **tp) 849 { 850 FOR_ALL_TAB_WINDOWS(*tp, *wp) 851 if ((*wp)->w_buffer == buf) 852 return OK; 853 return FAIL; 854 } 855 856 /* 857 * Find a window that contains "buf" and switch to it. 858 * If there is no such window, use the current window and change "curbuf". 859 * Caller must initialize save_curbuf to NULL. 860 * restore_win_for_buf() MUST be called later! 861 */ 862 void 863 switch_to_win_for_buf( 864 buf_T *buf, 865 win_T **save_curwinp, 866 tabpage_T **save_curtabp, 867 bufref_T *save_curbuf) 868 { 869 win_T *wp; 870 tabpage_T *tp; 871 872 if (find_win_for_buf(buf, &wp, &tp) == FAIL) 873 switch_buffer(save_curbuf, buf); 874 else if (switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL) 875 { 876 restore_win(*save_curwinp, *save_curtabp, TRUE); 877 switch_buffer(save_curbuf, buf); 878 } 879 } 880 881 void 882 restore_win_for_buf( 883 win_T *save_curwin, 884 tabpage_T *save_curtab, 885 bufref_T *save_curbuf) 886 { 887 if (save_curbuf->br_buf == NULL) 888 restore_win(save_curwin, save_curtab, TRUE); 889 else 890 restore_buffer(save_curbuf); 891 } 892 #endif 893