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