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