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 range_list_materialize(l); 180 li = l->lv_first; 181 } 182 else 183 line = tv_get_string_chk(lines); 184 185 // default result is zero == OK 186 for (;;) 187 { 188 if (l != NULL) 189 { 190 // list argument, get next string 191 if (li == NULL) 192 break; 193 line = tv_get_string_chk(&li->li_tv); 194 li = li->li_next; 195 } 196 197 rettv->vval.v_number = 1; // FAIL 198 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) 199 break; 200 201 // When coming here from Insert mode, sync undo, so that this can be 202 // undone separately from what was previously inserted. 203 if (u_sync_once == 2) 204 { 205 u_sync_once = 1; // notify that u_sync() was called 206 u_sync(TRUE); 207 } 208 209 if (!append && lnum <= curbuf->b_ml.ml_line_count) 210 { 211 // Existing line, replace it. 212 // Removes any existing text properties. 213 if (u_savesub(lnum) == OK && ml_replace_len( 214 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK) 215 { 216 changed_bytes(lnum, 0); 217 if (is_curbuf && lnum == curwin->w_cursor.lnum) 218 check_cursor_col(); 219 rettv->vval.v_number = 0; // OK 220 } 221 } 222 else if (added > 0 || u_save(lnum - 1, lnum) == OK) 223 { 224 // append the line 225 ++added; 226 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) 227 rettv->vval.v_number = 0; // OK 228 } 229 230 if (l == NULL) // only one string argument 231 break; 232 ++lnum; 233 } 234 235 if (added > 0) 236 { 237 win_T *wp; 238 tabpage_T *tp; 239 240 appended_lines_mark(append_lnum, added); 241 242 // Only adjust the cursor for buffers other than the current, unless it 243 // is the current window. For curbuf and other windows it has been 244 // done in mark_adjust_internal(). 245 FOR_ALL_TAB_WINDOWS(tp, wp) 246 if (wp->w_buffer == buf 247 && (wp->w_buffer != curbuf || wp == curwin) 248 && wp->w_cursor.lnum > append_lnum) 249 wp->w_cursor.lnum += added; 250 check_cursor_col(); 251 update_topline(); 252 } 253 254 if (!is_curbuf) 255 { 256 curbuf = curbuf_save; 257 curwin = curwin_save; 258 } 259 } 260 261 /* 262 * "append(lnum, string/list)" function 263 */ 264 void 265 f_append(typval_T *argvars, typval_T *rettv) 266 { 267 linenr_T lnum = tv_get_lnum(&argvars[0]); 268 269 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv); 270 } 271 272 /* 273 * "appendbufline(buf, lnum, string/list)" function 274 */ 275 void 276 f_appendbufline(typval_T *argvars, typval_T *rettv) 277 { 278 linenr_T lnum; 279 buf_T *buf; 280 281 buf = tv_get_buf(&argvars[0], FALSE); 282 if (buf == NULL) 283 rettv->vval.v_number = 1; // FAIL 284 else 285 { 286 lnum = tv_get_lnum_buf(&argvars[1], buf); 287 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv); 288 } 289 } 290 291 /* 292 * "bufadd(expr)" function 293 */ 294 void 295 f_bufadd(typval_T *argvars, typval_T *rettv) 296 { 297 char_u *name = tv_get_string(&argvars[0]); 298 299 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0); 300 } 301 302 /* 303 * "bufexists(expr)" function 304 */ 305 void 306 f_bufexists(typval_T *argvars, typval_T *rettv) 307 { 308 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); 309 } 310 311 /* 312 * "buflisted(expr)" function 313 */ 314 void 315 f_buflisted(typval_T *argvars, typval_T *rettv) 316 { 317 buf_T *buf; 318 319 buf = find_buffer(&argvars[0]); 320 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); 321 } 322 323 /* 324 * "bufload(expr)" function 325 */ 326 void 327 f_bufload(typval_T *argvars, typval_T *rettv UNUSED) 328 { 329 buf_T *buf = get_buf_arg(&argvars[0]); 330 331 if (buf != NULL) 332 buffer_ensure_loaded(buf); 333 } 334 335 /* 336 * "bufloaded(expr)" function 337 */ 338 void 339 f_bufloaded(typval_T *argvars, typval_T *rettv) 340 { 341 buf_T *buf; 342 343 buf = find_buffer(&argvars[0]); 344 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); 345 } 346 347 /* 348 * "bufname(expr)" function 349 */ 350 void 351 f_bufname(typval_T *argvars, typval_T *rettv) 352 { 353 buf_T *buf; 354 355 if (argvars[0].v_type == VAR_UNKNOWN) 356 buf = curbuf; 357 else 358 { 359 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 360 ++emsg_off; 361 buf = tv_get_buf(&argvars[0], FALSE); 362 --emsg_off; 363 } 364 rettv->v_type = VAR_STRING; 365 if (buf != NULL && buf->b_fname != NULL) 366 rettv->vval.v_string = vim_strsave(buf->b_fname); 367 else 368 rettv->vval.v_string = NULL; 369 } 370 371 /* 372 * "bufnr(expr)" function 373 */ 374 void 375 f_bufnr(typval_T *argvars, typval_T *rettv) 376 { 377 buf_T *buf; 378 int error = FALSE; 379 char_u *name; 380 381 if (argvars[0].v_type == VAR_UNKNOWN) 382 buf = curbuf; 383 else 384 { 385 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 386 ++emsg_off; 387 buf = tv_get_buf(&argvars[0], FALSE); 388 --emsg_off; 389 } 390 391 // If the buffer isn't found and the second argument is not zero create a 392 // new buffer. 393 if (buf == NULL 394 && argvars[1].v_type != VAR_UNKNOWN 395 && tv_get_number_chk(&argvars[1], &error) != 0 396 && !error 397 && (name = tv_get_string_chk(&argvars[0])) != NULL 398 && !error) 399 buf = buflist_new(name, NULL, (linenr_T)1, 0); 400 401 if (buf != NULL) 402 rettv->vval.v_number = buf->b_fnum; 403 else 404 rettv->vval.v_number = -1; 405 } 406 407 static void 408 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) 409 { 410 win_T *wp; 411 int winnr = 0; 412 buf_T *buf; 413 414 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 415 ++emsg_off; 416 buf = tv_get_buf(&argvars[0], TRUE); 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 --emsg_off; 425 } 426 427 /* 428 * "bufwinid(nr)" function 429 */ 430 void 431 f_bufwinid(typval_T *argvars, typval_T *rettv) 432 { 433 buf_win_common(argvars, rettv, FALSE); 434 } 435 436 /* 437 * "bufwinnr(nr)" function 438 */ 439 void 440 f_bufwinnr(typval_T *argvars, typval_T *rettv) 441 { 442 buf_win_common(argvars, rettv, TRUE); 443 } 444 445 /* 446 * "deletebufline()" function 447 */ 448 void 449 f_deletebufline(typval_T *argvars, typval_T *rettv) 450 { 451 buf_T *buf; 452 linenr_T first, last; 453 linenr_T lnum; 454 long count; 455 int is_curbuf; 456 buf_T *curbuf_save = NULL; 457 win_T *curwin_save = NULL; 458 tabpage_T *tp; 459 win_T *wp; 460 461 buf = tv_get_buf(&argvars[0], FALSE); 462 if (buf == NULL) 463 { 464 rettv->vval.v_number = 1; // FAIL 465 return; 466 } 467 is_curbuf = buf == curbuf; 468 469 first = tv_get_lnum_buf(&argvars[1], buf); 470 if (argvars[2].v_type != VAR_UNKNOWN) 471 last = tv_get_lnum_buf(&argvars[2], buf); 472 else 473 last = first; 474 475 if (buf->b_ml.ml_mfp == NULL || first < 1 476 || first > buf->b_ml.ml_line_count || last < first) 477 { 478 rettv->vval.v_number = 1; // FAIL 479 return; 480 } 481 482 if (!is_curbuf) 483 { 484 curbuf_save = curbuf; 485 curwin_save = curwin; 486 curbuf = buf; 487 find_win_for_curbuf(); 488 } 489 if (last > curbuf->b_ml.ml_line_count) 490 last = curbuf->b_ml.ml_line_count; 491 count = last - first + 1; 492 493 // When coming here from Insert mode, sync undo, so that this can be 494 // undone separately from what was previously inserted. 495 if (u_sync_once == 2) 496 { 497 u_sync_once = 1; // notify that u_sync() was called 498 u_sync(TRUE); 499 } 500 501 if (u_save(first - 1, last + 1) == FAIL) 502 { 503 rettv->vval.v_number = 1; // FAIL 504 return; 505 } 506 507 for (lnum = first; lnum <= last; ++lnum) 508 ml_delete(first, TRUE); 509 510 FOR_ALL_TAB_WINDOWS(tp, wp) 511 if (wp->w_buffer == buf) 512 { 513 if (wp->w_cursor.lnum > last) 514 wp->w_cursor.lnum -= count; 515 else if (wp->w_cursor.lnum> first) 516 wp->w_cursor.lnum = first; 517 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) 518 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; 519 } 520 check_cursor_col(); 521 deleted_lines_mark(first, count); 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 (wp = first_popupwin; wp != NULL; wp = wp->w_next) 576 if (wp->w_buffer == buf) 577 list_append_number(windows, (varnumber_T)wp->w_id); 578 FOR_ALL_TABPAGES(tp) 579 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next) 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 dictitem_T *di; 632 633 filtered = TRUE; 634 635 di = dict_find(sel_d, (char_u *)"buflisted", -1); 636 if (di != NULL && tv_get_number(&di->di_tv)) 637 sel_buflisted = TRUE; 638 639 di = dict_find(sel_d, (char_u *)"bufloaded", -1); 640 if (di != NULL && tv_get_number(&di->di_tv)) 641 sel_bufloaded = TRUE; 642 643 di = dict_find(sel_d, (char_u *)"bufmodified", -1); 644 if (di != NULL && tv_get_number(&di->di_tv)) 645 sel_bufmodified = TRUE; 646 } 647 } 648 else if (argvars[0].v_type != VAR_UNKNOWN) 649 { 650 // Information about one buffer. Argument specifies the buffer 651 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 652 ++emsg_off; 653 argbuf = tv_get_buf(&argvars[0], FALSE); 654 --emsg_off; 655 if (argbuf == NULL) 656 return; 657 } 658 659 // Return information about all the buffers or a specified buffer 660 FOR_ALL_BUFFERS(buf) 661 { 662 if (argbuf != NULL && argbuf != buf) 663 continue; 664 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL) 665 || (sel_buflisted && !buf->b_p_bl) 666 || (sel_bufmodified && !buf->b_changed))) 667 continue; 668 669 d = get_buffer_info(buf); 670 if (d != NULL) 671 list_append_dict(rettv->vval.v_list, d); 672 if (argbuf != NULL) 673 return; 674 } 675 } 676 677 /* 678 * Get line or list of lines from buffer "buf" into "rettv". 679 * Return a range (from start to end) of lines in rettv from the specified 680 * buffer. 681 * If 'retlist' is TRUE, then the lines are returned as a Vim List. 682 */ 683 static void 684 get_buffer_lines( 685 buf_T *buf, 686 linenr_T start, 687 linenr_T end, 688 int retlist, 689 typval_T *rettv) 690 { 691 char_u *p; 692 693 if (retlist) 694 { 695 if (rettv_list_alloc(rettv) == FAIL) 696 return; 697 } 698 else 699 { 700 rettv->v_type = VAR_STRING; 701 rettv->vval.v_string = NULL; 702 } 703 704 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) 705 return; 706 707 if (!retlist) 708 { 709 if (start >= 1 && start <= buf->b_ml.ml_line_count) 710 p = ml_get_buf(buf, start, FALSE); 711 else 712 p = (char_u *)""; 713 rettv->vval.v_string = vim_strsave(p); 714 } 715 else 716 { 717 if (end < start) 718 return; 719 720 if (start < 1) 721 start = 1; 722 if (end > buf->b_ml.ml_line_count) 723 end = buf->b_ml.ml_line_count; 724 while (start <= end) 725 if (list_append_string(rettv->vval.v_list, 726 ml_get_buf(buf, start++, FALSE), -1) == FAIL) 727 break; 728 } 729 } 730 731 /* 732 * "getbufline()" function 733 */ 734 void 735 f_getbufline(typval_T *argvars, typval_T *rettv) 736 { 737 linenr_T lnum; 738 linenr_T end; 739 buf_T *buf; 740 741 (void)tv_get_number(&argvars[0]); // issue errmsg if type error 742 ++emsg_off; 743 buf = tv_get_buf(&argvars[0], FALSE); 744 --emsg_off; 745 746 lnum = tv_get_lnum_buf(&argvars[1], buf); 747 if (argvars[2].v_type == VAR_UNKNOWN) 748 end = lnum; 749 else 750 end = tv_get_lnum_buf(&argvars[2], buf); 751 752 get_buffer_lines(buf, lnum, end, TRUE, rettv); 753 } 754 755 /* 756 * "getline(lnum, [end])" function 757 */ 758 void 759 f_getline(typval_T *argvars, typval_T *rettv) 760 { 761 linenr_T lnum; 762 linenr_T end; 763 int retlist; 764 765 lnum = tv_get_lnum(argvars); 766 if (argvars[1].v_type == VAR_UNKNOWN) 767 { 768 end = 0; 769 retlist = FALSE; 770 } 771 else 772 { 773 end = tv_get_lnum(&argvars[1]); 774 retlist = TRUE; 775 } 776 777 get_buffer_lines(curbuf, lnum, end, retlist, rettv); 778 } 779 780 /* 781 * "setbufline()" function 782 */ 783 void 784 f_setbufline(typval_T *argvars, typval_T *rettv) 785 { 786 linenr_T lnum; 787 buf_T *buf; 788 789 buf = tv_get_buf(&argvars[0], FALSE); 790 if (buf == NULL) 791 rettv->vval.v_number = 1; // FAIL 792 else 793 { 794 lnum = tv_get_lnum_buf(&argvars[1], buf); 795 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv); 796 } 797 } 798 799 /* 800 * "setline()" function 801 */ 802 void 803 f_setline(typval_T *argvars, typval_T *rettv) 804 { 805 linenr_T lnum = tv_get_lnum(&argvars[0]); 806 807 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv); 808 } 809 #endif // FEAT_EVAL 810 811 #if defined(FEAT_JOB_CHANNEL) \ 812 || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \ 813 || defined(PROTO) 814 /* 815 * Make "buf" the current buffer. restore_buffer() MUST be called to undo. 816 * No autocommands will be executed. Use aucmd_prepbuf() if there are any. 817 */ 818 void 819 switch_buffer(bufref_T *save_curbuf, buf_T *buf) 820 { 821 block_autocmds(); 822 set_bufref(save_curbuf, curbuf); 823 --curbuf->b_nwindows; 824 curbuf = buf; 825 curwin->w_buffer = buf; 826 ++curbuf->b_nwindows; 827 } 828 829 /* 830 * Restore the current buffer after using switch_buffer(). 831 */ 832 void 833 restore_buffer(bufref_T *save_curbuf) 834 { 835 unblock_autocmds(); 836 // Check for valid buffer, just in case. 837 if (bufref_valid(save_curbuf)) 838 { 839 --curbuf->b_nwindows; 840 curwin->w_buffer = save_curbuf->br_buf; 841 curbuf = save_curbuf->br_buf; 842 ++curbuf->b_nwindows; 843 } 844 } 845 846 /* 847 * Find a window for buffer "buf". 848 * If found OK is returned and "wp" and "tp" are set to the window and tabpage. 849 * If not found FAIL is returned. 850 */ 851 static int 852 find_win_for_buf( 853 buf_T *buf, 854 win_T **wp, 855 tabpage_T **tp) 856 { 857 FOR_ALL_TAB_WINDOWS(*tp, *wp) 858 if ((*wp)->w_buffer == buf) 859 return OK; 860 return FAIL; 861 } 862 863 /* 864 * Find a window that contains "buf" and switch to it. 865 * If there is no such window, use the current window and change "curbuf". 866 * Caller must initialize save_curbuf to NULL. 867 * restore_win_for_buf() MUST be called later! 868 */ 869 void 870 switch_to_win_for_buf( 871 buf_T *buf, 872 win_T **save_curwinp, 873 tabpage_T **save_curtabp, 874 bufref_T *save_curbuf) 875 { 876 win_T *wp; 877 tabpage_T *tp; 878 879 if (find_win_for_buf(buf, &wp, &tp) == FAIL) 880 switch_buffer(save_curbuf, buf); 881 else if (switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL) 882 { 883 restore_win(*save_curwinp, *save_curtabp, TRUE); 884 switch_buffer(save_curbuf, buf); 885 } 886 } 887 888 void 889 restore_win_for_buf( 890 win_T *save_curwin, 891 tabpage_T *save_curtab, 892 bufref_T *save_curbuf) 893 { 894 if (save_curbuf->br_buf == NULL) 895 restore_win(save_curwin, save_curtab, TRUE); 896 else 897 restore_buffer(save_curbuf); 898 } 899 #endif 900