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 * evalwindow.c: Window related builtin functions 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) || defined(PROTO) 17 18 static int 19 win_getid(typval_T *argvars) 20 { 21 int winnr; 22 win_T *wp; 23 24 if (argvars[0].v_type == VAR_UNKNOWN) 25 return curwin->w_id; 26 winnr = tv_get_number(&argvars[0]); 27 if (winnr > 0) 28 { 29 if (argvars[1].v_type == VAR_UNKNOWN) 30 wp = firstwin; 31 else 32 { 33 tabpage_T *tp; 34 int tabnr = tv_get_number(&argvars[1]); 35 36 FOR_ALL_TABPAGES(tp) 37 if (--tabnr == 0) 38 break; 39 if (tp == NULL) 40 return -1; 41 if (tp == curtab) 42 wp = firstwin; 43 else 44 wp = tp->tp_firstwin; 45 } 46 for ( ; wp != NULL; wp = wp->w_next) 47 if (--winnr == 0) 48 return wp->w_id; 49 } 50 return 0; 51 } 52 53 static void 54 win_id2tabwin(typval_T *argvars, list_T *list) 55 { 56 win_T *wp; 57 tabpage_T *tp; 58 int winnr = 1; 59 int tabnr = 1; 60 int id = tv_get_number(&argvars[0]); 61 62 FOR_ALL_TABPAGES(tp) 63 { 64 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 65 { 66 if (wp->w_id == id) 67 { 68 list_append_number(list, tabnr); 69 list_append_number(list, winnr); 70 return; 71 } 72 ++winnr; 73 } 74 ++tabnr; 75 winnr = 1; 76 } 77 list_append_number(list, 0); 78 list_append_number(list, 0); 79 } 80 81 /* 82 * Return the window pointer of window "id". 83 */ 84 win_T * 85 win_id2wp(int id) 86 { 87 return win_id2wp_tp(id, NULL); 88 } 89 90 /* 91 * Return the window and tab pointer of window "id". 92 */ 93 win_T * 94 win_id2wp_tp(int id, tabpage_T **tpp) 95 { 96 win_T *wp; 97 tabpage_T *tp; 98 99 FOR_ALL_TAB_WINDOWS(tp, wp) 100 if (wp->w_id == id) 101 { 102 if (tpp != NULL) 103 *tpp = tp; 104 return wp; 105 } 106 #ifdef FEAT_PROP_POPUP 107 // popup windows are in separate lists 108 FOR_ALL_TABPAGES(tp) 109 FOR_ALL_POPUPWINS_IN_TAB(tp, wp) 110 if (wp->w_id == id) 111 { 112 if (tpp != NULL) 113 *tpp = tp; 114 return wp; 115 } 116 FOR_ALL_POPUPWINS(wp) 117 if (wp->w_id == id) 118 { 119 if (tpp != NULL) 120 *tpp = curtab; // any tabpage would do 121 return wp; 122 } 123 #endif 124 125 return NULL; 126 } 127 128 static int 129 win_id2win(typval_T *argvars) 130 { 131 win_T *wp; 132 int nr = 1; 133 int id = tv_get_number(&argvars[0]); 134 135 FOR_ALL_WINDOWS(wp) 136 { 137 if (wp->w_id == id) 138 return nr; 139 ++nr; 140 } 141 return 0; 142 } 143 144 void 145 win_findbuf(typval_T *argvars, list_T *list) 146 { 147 win_T *wp; 148 tabpage_T *tp; 149 int bufnr = tv_get_number(&argvars[0]); 150 151 FOR_ALL_TAB_WINDOWS(tp, wp) 152 if (wp->w_buffer->b_fnum == bufnr) 153 list_append_number(list, wp->w_id); 154 } 155 156 /* 157 * Find window specified by "vp" in tabpage "tp". 158 */ 159 win_T * 160 find_win_by_nr( 161 typval_T *vp, 162 tabpage_T *tp) // NULL for current tab page 163 { 164 win_T *wp; 165 int nr = (int)tv_get_number_chk(vp, NULL); 166 167 if (nr < 0) 168 return NULL; 169 if (nr == 0) 170 return curwin; 171 172 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 173 { 174 if (nr >= LOWEST_WIN_ID) 175 { 176 if (wp->w_id == nr) 177 return wp; 178 } 179 else if (--nr <= 0) 180 break; 181 } 182 if (nr >= LOWEST_WIN_ID) 183 { 184 #ifdef FEAT_PROP_POPUP 185 // check tab-local popup windows 186 for (wp = (tp == NULL ? curtab : tp)->tp_first_popupwin; 187 wp != NULL; wp = wp->w_next) 188 if (wp->w_id == nr) 189 return wp; 190 // check global popup windows 191 FOR_ALL_POPUPWINS(wp) 192 if (wp->w_id == nr) 193 return wp; 194 #endif 195 return NULL; 196 } 197 return wp; 198 } 199 200 /* 201 * Find a window: When using a Window ID in any tab page, when using a number 202 * in the current tab page. 203 * Returns NULL when not found. 204 */ 205 win_T * 206 find_win_by_nr_or_id(typval_T *vp) 207 { 208 int nr = (int)tv_get_number_chk(vp, NULL); 209 210 if (nr >= LOWEST_WIN_ID) 211 return win_id2wp(tv_get_number(vp)); 212 return find_win_by_nr(vp, NULL); 213 } 214 215 /* 216 * Find window specified by "wvp" in tabpage "tvp". 217 * Returns the tab page in 'ptp' 218 */ 219 win_T * 220 find_tabwin( 221 typval_T *wvp, // VAR_UNKNOWN for current window 222 typval_T *tvp, // VAR_UNKNOWN for current tab page 223 tabpage_T **ptp) 224 { 225 win_T *wp = NULL; 226 tabpage_T *tp = NULL; 227 long n; 228 229 if (wvp->v_type != VAR_UNKNOWN) 230 { 231 if (tvp->v_type != VAR_UNKNOWN) 232 { 233 n = (long)tv_get_number(tvp); 234 if (n >= 0) 235 tp = find_tabpage(n); 236 } 237 else 238 tp = curtab; 239 240 if (tp != NULL) 241 { 242 wp = find_win_by_nr(wvp, tp); 243 if (wp == NULL && wvp->v_type == VAR_NUMBER 244 && wvp->vval.v_number != -1) 245 // A window with the specified number is not found 246 tp = NULL; 247 } 248 } 249 else 250 { 251 wp = curwin; 252 tp = curtab; 253 } 254 255 if (ptp != NULL) 256 *ptp = tp; 257 258 return wp; 259 } 260 261 /* 262 * Get the layout of the given tab page for winlayout(). 263 */ 264 static void 265 get_framelayout(frame_T *fr, list_T *l, int outer) 266 { 267 frame_T *child; 268 list_T *fr_list; 269 list_T *win_list; 270 271 if (fr == NULL) 272 return; 273 274 if (outer) 275 // outermost call from f_winlayout() 276 fr_list = l; 277 else 278 { 279 fr_list = list_alloc(); 280 if (fr_list == NULL) 281 return; 282 list_append_list(l, fr_list); 283 } 284 285 if (fr->fr_layout == FR_LEAF) 286 { 287 if (fr->fr_win != NULL) 288 { 289 list_append_string(fr_list, (char_u *)"leaf", -1); 290 list_append_number(fr_list, fr->fr_win->w_id); 291 } 292 } 293 else 294 { 295 list_append_string(fr_list, 296 fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1); 297 298 win_list = list_alloc(); 299 if (win_list == NULL) 300 return; 301 list_append_list(fr_list, win_list); 302 child = fr->fr_child; 303 while (child != NULL) 304 { 305 get_framelayout(child, win_list, FALSE); 306 child = child->fr_next; 307 } 308 } 309 } 310 311 /* 312 * Common code for tabpagewinnr() and winnr(). 313 */ 314 static int 315 get_winnr(tabpage_T *tp, typval_T *argvar) 316 { 317 win_T *twin; 318 int nr = 1; 319 win_T *wp; 320 char_u *arg; 321 322 twin = (tp == curtab) ? curwin : tp->tp_curwin; 323 if (argvar->v_type != VAR_UNKNOWN) 324 { 325 int invalid_arg = FALSE; 326 327 arg = tv_get_string_chk(argvar); 328 if (arg == NULL) 329 nr = 0; // type error; errmsg already given 330 else if (STRCMP(arg, "$") == 0) 331 twin = (tp == curtab) ? lastwin : tp->tp_lastwin; 332 else if (STRCMP(arg, "#") == 0) 333 { 334 twin = (tp == curtab) ? prevwin : tp->tp_prevwin; 335 } 336 else 337 { 338 long count; 339 char_u *endp; 340 341 // Extract the window count (if specified). e.g. winnr('3j') 342 count = strtol((char *)arg, (char **)&endp, 10); 343 if (count <= 0) 344 count = 1; // if count is not specified, default to 1 345 if (endp != NULL && *endp != '\0') 346 { 347 if (STRCMP(endp, "j") == 0) 348 twin = win_vert_neighbor(tp, twin, FALSE, count); 349 else if (STRCMP(endp, "k") == 0) 350 twin = win_vert_neighbor(tp, twin, TRUE, count); 351 else if (STRCMP(endp, "h") == 0) 352 twin = win_horz_neighbor(tp, twin, TRUE, count); 353 else if (STRCMP(endp, "l") == 0) 354 twin = win_horz_neighbor(tp, twin, FALSE, count); 355 else 356 invalid_arg = TRUE; 357 } 358 else 359 invalid_arg = TRUE; 360 } 361 if (twin == NULL) 362 nr = 0; 363 364 if (invalid_arg) 365 { 366 semsg(_(e_invalid_expression_str), arg); 367 nr = 0; 368 } 369 } 370 371 if (nr > 0) 372 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; 373 wp != twin; wp = wp->w_next) 374 { 375 if (wp == NULL) 376 { 377 // didn't find it in this tabpage 378 nr = 0; 379 break; 380 } 381 ++nr; 382 } 383 return nr; 384 } 385 386 /* 387 * Returns information about a window as a dictionary. 388 */ 389 static dict_T * 390 get_win_info(win_T *wp, short tpnr, short winnr) 391 { 392 dict_T *dict; 393 394 dict = dict_alloc(); 395 if (dict == NULL) 396 return NULL; 397 398 dict_add_number(dict, "tabnr", tpnr); 399 dict_add_number(dict, "winnr", winnr); 400 dict_add_number(dict, "winid", wp->w_id); 401 dict_add_number(dict, "height", wp->w_height); 402 dict_add_number(dict, "winrow", wp->w_winrow + 1); 403 dict_add_number(dict, "topline", wp->w_topline); 404 dict_add_number(dict, "botline", wp->w_botline - 1); 405 #ifdef FEAT_MENU 406 dict_add_number(dict, "winbar", wp->w_winbar_height); 407 #endif 408 dict_add_number(dict, "width", wp->w_width); 409 dict_add_number(dict, "wincol", wp->w_wincol + 1); 410 dict_add_number(dict, "textoff", win_col_off(wp)); 411 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum); 412 413 #ifdef FEAT_TERMINAL 414 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer)); 415 #endif 416 #ifdef FEAT_QUICKFIX 417 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer)); 418 dict_add_number(dict, "loclist", 419 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)); 420 #endif 421 422 // Add a reference to window variables 423 dict_add_dict(dict, "variables", wp->w_vars); 424 425 return dict; 426 } 427 428 /* 429 * Returns information (variables, options, etc.) about a tab page 430 * as a dictionary. 431 */ 432 static dict_T * 433 get_tabpage_info(tabpage_T *tp, int tp_idx) 434 { 435 win_T *wp; 436 dict_T *dict; 437 list_T *l; 438 439 dict = dict_alloc(); 440 if (dict == NULL) 441 return NULL; 442 443 dict_add_number(dict, "tabnr", tp_idx); 444 445 l = list_alloc(); 446 if (l != NULL) 447 { 448 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 449 list_append_number(l, (varnumber_T)wp->w_id); 450 dict_add_list(dict, "windows", l); 451 } 452 453 // Make a reference to tabpage variables 454 dict_add_dict(dict, "variables", tp->tp_vars); 455 456 return dict; 457 } 458 459 /* 460 * "gettabinfo()" function 461 */ 462 void 463 f_gettabinfo(typval_T *argvars, typval_T *rettv) 464 { 465 tabpage_T *tp, *tparg = NULL; 466 dict_T *d; 467 int tpnr = 0; 468 469 if (rettv_list_alloc(rettv) != OK) 470 return; 471 472 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) 473 return; 474 475 if (argvars[0].v_type != VAR_UNKNOWN) 476 { 477 // Information about one tab page 478 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); 479 if (tparg == NULL) 480 return; 481 } 482 483 // Get information about a specific tab page or all tab pages 484 FOR_ALL_TABPAGES(tp) 485 { 486 tpnr++; 487 if (tparg != NULL && tp != tparg) 488 continue; 489 d = get_tabpage_info(tp, tpnr); 490 if (d != NULL) 491 list_append_dict(rettv->vval.v_list, d); 492 if (tparg != NULL) 493 return; 494 } 495 } 496 497 /* 498 * "getwininfo()" function 499 */ 500 void 501 f_getwininfo(typval_T *argvars, typval_T *rettv) 502 { 503 tabpage_T *tp; 504 win_T *wp = NULL, *wparg = NULL; 505 dict_T *d; 506 short tabnr = 0, winnr; 507 508 if (rettv_list_alloc(rettv) != OK) 509 return; 510 511 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) 512 return; 513 514 if (argvars[0].v_type != VAR_UNKNOWN) 515 { 516 wparg = win_id2wp(tv_get_number(&argvars[0])); 517 if (wparg == NULL) 518 return; 519 } 520 521 // Collect information about either all the windows across all the tab 522 // pages or one particular window. 523 FOR_ALL_TABPAGES(tp) 524 { 525 tabnr++; 526 winnr = 0; 527 FOR_ALL_WINDOWS_IN_TAB(tp, wp) 528 { 529 winnr++; 530 if (wparg != NULL && wp != wparg) 531 continue; 532 d = get_win_info(wp, tabnr, winnr); 533 if (d != NULL) 534 list_append_dict(rettv->vval.v_list, d); 535 if (wparg != NULL) 536 // found information about a specific window 537 return; 538 } 539 } 540 #ifdef FEAT_PROP_POPUP 541 if (wparg != NULL) 542 { 543 tabnr = 0; 544 FOR_ALL_TABPAGES(tp) 545 { 546 tabnr++; 547 FOR_ALL_POPUPWINS_IN_TAB(tp, wp) 548 if (wp == wparg) 549 break; 550 } 551 d = get_win_info(wparg, tp == NULL ? 0 : tabnr, 0); 552 if (d != NULL) 553 list_append_dict(rettv->vval.v_list, d); 554 } 555 #endif 556 } 557 558 /* 559 * "getwinpos({timeout})" function 560 */ 561 void 562 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv) 563 { 564 int x = -1; 565 int y = -1; 566 567 if (rettv_list_alloc(rettv) == FAIL) 568 return; 569 570 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) 571 return; 572 573 #if defined(FEAT_GUI) \ 574 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \ 575 || defined(MSWIN) 576 { 577 varnumber_T timeout = 100; 578 579 if (argvars[0].v_type != VAR_UNKNOWN) 580 timeout = tv_get_number(&argvars[0]); 581 582 (void)ui_get_winpos(&x, &y, timeout); 583 } 584 #endif 585 list_append_number(rettv->vval.v_list, (varnumber_T)x); 586 list_append_number(rettv->vval.v_list, (varnumber_T)y); 587 } 588 589 590 /* 591 * "getwinposx()" function 592 */ 593 void 594 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) 595 { 596 rettv->vval.v_number = -1; 597 #if defined(FEAT_GUI) \ 598 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \ 599 || defined(MSWIN) 600 601 { 602 int x, y; 603 604 if (ui_get_winpos(&x, &y, 100) == OK) 605 rettv->vval.v_number = x; 606 } 607 #endif 608 } 609 610 /* 611 * "getwinposy()" function 612 */ 613 void 614 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) 615 { 616 rettv->vval.v_number = -1; 617 #if defined(FEAT_GUI) \ 618 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \ 619 || defined(MSWIN) 620 { 621 int x, y; 622 623 if (ui_get_winpos(&x, &y, 100) == OK) 624 rettv->vval.v_number = y; 625 } 626 #endif 627 } 628 629 /* 630 * "tabpagenr()" function 631 */ 632 void 633 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) 634 { 635 int nr = 1; 636 char_u *arg; 637 638 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL) 639 return; 640 641 if (argvars[0].v_type != VAR_UNKNOWN) 642 { 643 arg = tv_get_string_chk(&argvars[0]); 644 nr = 0; 645 if (arg != NULL) 646 { 647 if (STRCMP(arg, "$") == 0) 648 nr = tabpage_index(NULL) - 1; 649 else if (STRCMP(arg, "#") == 0) 650 nr = valid_tabpage(lastused_tabpage) ? 651 tabpage_index(lastused_tabpage) : 0; 652 else 653 semsg(_(e_invalid_expression_str), arg); 654 } 655 } 656 else 657 nr = tabpage_index(curtab); 658 rettv->vval.v_number = nr; 659 } 660 661 /* 662 * "tabpagewinnr()" function 663 */ 664 void 665 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) 666 { 667 int nr = 1; 668 tabpage_T *tp; 669 670 if (in_vim9script() 671 && (check_for_number_arg(argvars, 0) == FAIL 672 || check_for_opt_string_arg(argvars, 1) == FAIL)) 673 return; 674 675 tp = find_tabpage((int)tv_get_number(&argvars[0])); 676 if (tp == NULL) 677 nr = 0; 678 else 679 nr = get_winnr(tp, &argvars[1]); 680 rettv->vval.v_number = nr; 681 } 682 683 /* 684 * "win_execute()" function 685 */ 686 void 687 f_win_execute(typval_T *argvars, typval_T *rettv) 688 { 689 int id; 690 tabpage_T *tp; 691 win_T *wp; 692 win_T *save_curwin; 693 tabpage_T *save_curtab; 694 695 // Return an empty string if something fails. 696 rettv->v_type = VAR_STRING; 697 rettv->vval.v_string = NULL; 698 699 if (in_vim9script() 700 && (check_for_number_arg(argvars, 0) == FAIL 701 || check_for_string_or_list_arg(argvars, 1) == FAIL 702 || check_for_opt_string_arg(argvars, 2) == FAIL)) 703 return; 704 705 id = (int)tv_get_number(argvars); 706 wp = win_id2wp_tp(id, &tp); 707 if (wp != NULL && tp != NULL) 708 { 709 pos_T curpos = wp->w_cursor; 710 711 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK) 712 { 713 check_cursor(); 714 execute_common(argvars, rettv, 1); 715 } 716 restore_win_noblock(save_curwin, save_curtab, TRUE); 717 718 // Update the status line if the cursor moved. 719 if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor)) 720 wp->w_redr_status = TRUE; 721 } 722 } 723 724 /* 725 * "win_findbuf()" function 726 */ 727 void 728 f_win_findbuf(typval_T *argvars, typval_T *rettv) 729 { 730 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 731 return; 732 733 if (rettv_list_alloc(rettv) != FAIL) 734 win_findbuf(argvars, rettv->vval.v_list); 735 } 736 737 /* 738 * "win_getid()" function 739 */ 740 void 741 f_win_getid(typval_T *argvars, typval_T *rettv) 742 { 743 if (in_vim9script() 744 && (check_for_opt_number_arg(argvars, 0) == FAIL 745 || (argvars[0].v_type != VAR_UNKNOWN 746 && check_for_opt_number_arg(argvars, 1) == FAIL))) 747 return; 748 749 rettv->vval.v_number = win_getid(argvars); 750 } 751 752 /* 753 * "win_gotoid()" function 754 */ 755 void 756 f_win_gotoid(typval_T *argvars, typval_T *rettv) 757 { 758 win_T *wp; 759 tabpage_T *tp; 760 int id; 761 762 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 763 return; 764 765 id = tv_get_number(&argvars[0]); 766 #ifdef FEAT_CMDWIN 767 if (cmdwin_type != 0) 768 { 769 emsg(_(e_invalid_in_cmdline_window)); 770 return; 771 } 772 #endif 773 FOR_ALL_TAB_WINDOWS(tp, wp) 774 if (wp->w_id == id) 775 { 776 goto_tabpage_win(tp, wp); 777 rettv->vval.v_number = 1; 778 return; 779 } 780 } 781 782 /* 783 * "win_id2tabwin()" function 784 */ 785 void 786 f_win_id2tabwin(typval_T *argvars, typval_T *rettv) 787 { 788 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 789 return; 790 791 if (rettv_list_alloc(rettv) != FAIL) 792 win_id2tabwin(argvars, rettv->vval.v_list); 793 } 794 795 /* 796 * "win_id2win()" function 797 */ 798 void 799 f_win_id2win(typval_T *argvars, typval_T *rettv) 800 { 801 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 802 return; 803 804 rettv->vval.v_number = win_id2win(argvars); 805 } 806 807 /* 808 * "win_screenpos()" function 809 */ 810 void 811 f_win_screenpos(typval_T *argvars, typval_T *rettv) 812 { 813 win_T *wp; 814 815 if (rettv_list_alloc(rettv) == FAIL) 816 return; 817 818 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 819 return; 820 821 wp = find_win_by_nr_or_id(&argvars[0]); 822 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1); 823 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1); 824 } 825 826 /* 827 * Move the window wp into a new split of targetwin in a given direction 828 */ 829 static void 830 win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags) 831 { 832 int dir; 833 int height = wp->w_height; 834 win_T *oldwin = curwin; 835 836 if (wp == targetwin) 837 return; 838 839 // Jump to the target window 840 if (curwin != targetwin) 841 win_goto(targetwin); 842 843 // Remove the old window and frame from the tree of frames 844 (void)winframe_remove(wp, &dir, NULL); 845 win_remove(wp, NULL); 846 last_status(FALSE); // may need to remove last status line 847 (void)win_comp_pos(); // recompute window positions 848 849 // Split a window on the desired side and put the old window there 850 (void)win_split_ins(size, flags, wp, dir); 851 852 // If splitting horizontally, try to preserve height 853 if (size == 0 && !(flags & WSP_VERT)) 854 { 855 win_setheight_win(height, wp); 856 if (p_ea) 857 win_equal(wp, TRUE, 'v'); 858 } 859 860 #if defined(FEAT_GUI) 861 // When 'guioptions' includes 'L' or 'R' may have to remove or add 862 // scrollbars. Have to update them anyway. 863 gui_may_update_scrollbars(); 864 #endif 865 866 if (oldwin != curwin) 867 win_goto(oldwin); 868 } 869 870 /* 871 * "win_splitmove()" function 872 */ 873 void 874 f_win_splitmove(typval_T *argvars, typval_T *rettv) 875 { 876 win_T *wp; 877 win_T *targetwin; 878 int flags = 0, size = 0; 879 880 if (in_vim9script() 881 && (check_for_number_arg(argvars, 0) == FAIL 882 || check_for_number_arg(argvars, 1) == FAIL 883 || check_for_opt_dict_arg(argvars, 2) == FAIL)) 884 return; 885 886 wp = find_win_by_nr_or_id(&argvars[0]); 887 targetwin = find_win_by_nr_or_id(&argvars[1]); 888 889 if (wp == NULL || targetwin == NULL || wp == targetwin 890 || !win_valid(wp) || !win_valid(targetwin) 891 || win_valid_popup(wp) || win_valid_popup(targetwin)) 892 { 893 emsg(_(e_invalwindow)); 894 rettv->vval.v_number = -1; 895 return; 896 } 897 898 if (argvars[2].v_type != VAR_UNKNOWN) 899 { 900 dict_T *d; 901 dictitem_T *di; 902 903 if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) 904 { 905 emsg(_(e_invarg)); 906 return; 907 } 908 909 d = argvars[2].vval.v_dict; 910 if (dict_get_bool(d, (char_u *)"vertical", FALSE)) 911 flags |= WSP_VERT; 912 if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL) 913 flags |= tv_get_bool(&di->di_tv) ? WSP_BELOW : WSP_ABOVE; 914 size = (int)dict_get_number(d, (char_u *)"size"); 915 } 916 917 win_move_into_split(wp, targetwin, size, flags); 918 } 919 920 /* 921 * "win_gettype(nr)" function 922 */ 923 void 924 f_win_gettype(typval_T *argvars, typval_T *rettv) 925 { 926 win_T *wp = curwin; 927 928 rettv->v_type = VAR_STRING; 929 rettv->vval.v_string = NULL; 930 931 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) 932 return; 933 934 if (argvars[0].v_type != VAR_UNKNOWN) 935 { 936 wp = find_win_by_nr_or_id(&argvars[0]); 937 if (wp == NULL) 938 { 939 rettv->vval.v_string = vim_strsave((char_u *)"unknown"); 940 return; 941 } 942 } 943 if (wp == aucmd_win) 944 rettv->vval.v_string = vim_strsave((char_u *)"autocmd"); 945 #if defined(FEAT_QUICKFIX) 946 else if (wp->w_p_pvw) 947 rettv->vval.v_string = vim_strsave((char_u *)"preview"); 948 #endif 949 #ifdef FEAT_PROP_POPUP 950 else if (WIN_IS_POPUP(wp)) 951 rettv->vval.v_string = vim_strsave((char_u *)"popup"); 952 #endif 953 #ifdef FEAT_CMDWIN 954 else if (wp == curwin && cmdwin_type != 0) 955 rettv->vval.v_string = vim_strsave((char_u *)"command"); 956 #endif 957 #ifdef FEAT_QUICKFIX 958 else if (bt_quickfix(wp->w_buffer)) 959 rettv->vval.v_string = vim_strsave((char_u *) 960 (wp->w_llist_ref != NULL ? "loclist" : "quickfix")); 961 #endif 962 963 } 964 965 /* 966 * "getcmdwintype()" function 967 */ 968 void 969 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) 970 { 971 rettv->v_type = VAR_STRING; 972 rettv->vval.v_string = NULL; 973 #ifdef FEAT_CMDWIN 974 rettv->vval.v_string = alloc(2); 975 if (rettv->vval.v_string != NULL) 976 { 977 rettv->vval.v_string[0] = cmdwin_type; 978 rettv->vval.v_string[1] = NUL; 979 } 980 #endif 981 } 982 983 /* 984 * "winbufnr(nr)" function 985 */ 986 void 987 f_winbufnr(typval_T *argvars, typval_T *rettv) 988 { 989 win_T *wp; 990 991 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 992 return; 993 994 wp = find_win_by_nr_or_id(&argvars[0]); 995 if (wp == NULL) 996 rettv->vval.v_number = -1; 997 else 998 rettv->vval.v_number = wp->w_buffer->b_fnum; 999 } 1000 1001 /* 1002 * "wincol()" function 1003 */ 1004 void 1005 f_wincol(typval_T *argvars UNUSED, typval_T *rettv) 1006 { 1007 validate_cursor(); 1008 rettv->vval.v_number = curwin->w_wcol + 1; 1009 } 1010 1011 /* 1012 * "winheight(nr)" function 1013 */ 1014 void 1015 f_winheight(typval_T *argvars, typval_T *rettv) 1016 { 1017 win_T *wp; 1018 1019 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 1020 return; 1021 1022 wp = find_win_by_nr_or_id(&argvars[0]); 1023 if (wp == NULL) 1024 rettv->vval.v_number = -1; 1025 else 1026 rettv->vval.v_number = wp->w_height; 1027 } 1028 1029 /* 1030 * "winlayout()" function 1031 */ 1032 void 1033 f_winlayout(typval_T *argvars, typval_T *rettv) 1034 { 1035 tabpage_T *tp; 1036 1037 if (rettv_list_alloc(rettv) != OK) 1038 return; 1039 1040 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL) 1041 return; 1042 1043 if (argvars[0].v_type == VAR_UNKNOWN) 1044 tp = curtab; 1045 else 1046 { 1047 tp = find_tabpage((int)tv_get_number(&argvars[0])); 1048 if (tp == NULL) 1049 return; 1050 } 1051 1052 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE); 1053 } 1054 1055 /* 1056 * "winline()" function 1057 */ 1058 void 1059 f_winline(typval_T *argvars UNUSED, typval_T *rettv) 1060 { 1061 validate_cursor(); 1062 rettv->vval.v_number = curwin->w_wrow + 1; 1063 } 1064 1065 /* 1066 * "winnr()" function 1067 */ 1068 void 1069 f_winnr(typval_T *argvars UNUSED, typval_T *rettv) 1070 { 1071 int nr = 1; 1072 1073 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL) 1074 return; 1075 1076 nr = get_winnr(curtab, &argvars[0]); 1077 rettv->vval.v_number = nr; 1078 } 1079 1080 /* 1081 * "winrestcmd()" function 1082 */ 1083 void 1084 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) 1085 { 1086 win_T *wp; 1087 int i; 1088 int winnr; 1089 garray_T ga; 1090 char_u buf[50]; 1091 1092 ga_init2(&ga, (int)sizeof(char), 70); 1093 1094 // Do this twice to handle some window layouts properly. 1095 for (i = 0; i < 2; ++i) 1096 { 1097 winnr = 1; 1098 FOR_ALL_WINDOWS(wp) 1099 { 1100 sprintf((char *)buf, ":%dresize %d|", winnr, wp->w_height); 1101 ga_concat(&ga, buf); 1102 sprintf((char *)buf, "vert :%dresize %d|", winnr, wp->w_width); 1103 ga_concat(&ga, buf); 1104 ++winnr; 1105 } 1106 } 1107 ga_append(&ga, NUL); 1108 1109 rettv->vval.v_string = ga.ga_data; 1110 rettv->v_type = VAR_STRING; 1111 } 1112 1113 /* 1114 * "winrestview()" function 1115 */ 1116 void 1117 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) 1118 { 1119 dict_T *dict; 1120 1121 if (in_vim9script() && check_for_dict_arg(argvars, 0) == FAIL) 1122 return; 1123 1124 if (argvars[0].v_type != VAR_DICT 1125 || (dict = argvars[0].vval.v_dict) == NULL) 1126 emsg(_(e_invarg)); 1127 else 1128 { 1129 if (dict_find(dict, (char_u *)"lnum", -1) != NULL) 1130 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum"); 1131 if (dict_find(dict, (char_u *)"col", -1) != NULL) 1132 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col"); 1133 if (dict_find(dict, (char_u *)"coladd", -1) != NULL) 1134 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd"); 1135 if (dict_find(dict, (char_u *)"curswant", -1) != NULL) 1136 { 1137 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant"); 1138 curwin->w_set_curswant = FALSE; 1139 } 1140 1141 if (dict_find(dict, (char_u *)"topline", -1) != NULL) 1142 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline")); 1143 #ifdef FEAT_DIFF 1144 if (dict_find(dict, (char_u *)"topfill", -1) != NULL) 1145 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill"); 1146 #endif 1147 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) 1148 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol"); 1149 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) 1150 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol"); 1151 1152 check_cursor(); 1153 win_new_height(curwin, curwin->w_height); 1154 win_new_width(curwin, curwin->w_width); 1155 changed_window_setting(); 1156 1157 if (curwin->w_topline <= 0) 1158 curwin->w_topline = 1; 1159 if (curwin->w_topline > curbuf->b_ml.ml_line_count) 1160 curwin->w_topline = curbuf->b_ml.ml_line_count; 1161 #ifdef FEAT_DIFF 1162 check_topfill(curwin, TRUE); 1163 #endif 1164 } 1165 } 1166 1167 /* 1168 * "winsaveview()" function 1169 */ 1170 void 1171 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) 1172 { 1173 dict_T *dict; 1174 1175 if (rettv_dict_alloc(rettv) == FAIL) 1176 return; 1177 dict = rettv->vval.v_dict; 1178 1179 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum); 1180 dict_add_number(dict, "col", (long)curwin->w_cursor.col); 1181 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd); 1182 update_curswant(); 1183 dict_add_number(dict, "curswant", (long)curwin->w_curswant); 1184 1185 dict_add_number(dict, "topline", (long)curwin->w_topline); 1186 #ifdef FEAT_DIFF 1187 dict_add_number(dict, "topfill", (long)curwin->w_topfill); 1188 #endif 1189 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol); 1190 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol); 1191 } 1192 1193 /* 1194 * "winwidth(nr)" function 1195 */ 1196 void 1197 f_winwidth(typval_T *argvars, typval_T *rettv) 1198 { 1199 win_T *wp; 1200 1201 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL) 1202 return; 1203 1204 wp = find_win_by_nr_or_id(&argvars[0]); 1205 if (wp == NULL) 1206 rettv->vval.v_number = -1; 1207 else 1208 rettv->vval.v_number = wp->w_width; 1209 } 1210 #endif // FEAT_EVAL 1211 1212 #if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \ 1213 || defined(PROTO) 1214 /* 1215 * Set "win" to be the curwin and "tp" to be the current tab page. 1216 * restore_win() MUST be called to undo, also when FAIL is returned. 1217 * No autocommands will be executed until restore_win() is called. 1218 * When "no_display" is TRUE the display won't be affected, no redraw is 1219 * triggered, another tabpage access is limited. 1220 * Returns FAIL if switching to "win" failed. 1221 */ 1222 int 1223 switch_win( 1224 win_T **save_curwin, 1225 tabpage_T **save_curtab, 1226 win_T *win, 1227 tabpage_T *tp, 1228 int no_display) 1229 { 1230 block_autocmds(); 1231 return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display); 1232 } 1233 1234 /* 1235 * As switch_win() but without blocking autocommands. 1236 */ 1237 int 1238 switch_win_noblock( 1239 win_T **save_curwin, 1240 tabpage_T **save_curtab, 1241 win_T *win, 1242 tabpage_T *tp, 1243 int no_display) 1244 { 1245 *save_curwin = curwin; 1246 if (tp != NULL) 1247 { 1248 *save_curtab = curtab; 1249 if (no_display) 1250 { 1251 curtab->tp_firstwin = firstwin; 1252 curtab->tp_lastwin = lastwin; 1253 curtab = tp; 1254 firstwin = curtab->tp_firstwin; 1255 lastwin = curtab->tp_lastwin; 1256 } 1257 else 1258 goto_tabpage_tp(tp, FALSE, FALSE); 1259 } 1260 if (!win_valid(win)) 1261 return FAIL; 1262 curwin = win; 1263 curbuf = curwin->w_buffer; 1264 return OK; 1265 } 1266 1267 /* 1268 * Restore current tabpage and window saved by switch_win(), if still valid. 1269 * When "no_display" is TRUE the display won't be affected, no redraw is 1270 * triggered. 1271 */ 1272 void 1273 restore_win( 1274 win_T *save_curwin, 1275 tabpage_T *save_curtab, 1276 int no_display) 1277 { 1278 restore_win_noblock(save_curwin, save_curtab, no_display); 1279 unblock_autocmds(); 1280 } 1281 1282 /* 1283 * As restore_win() but without unblocking autocommands. 1284 */ 1285 void 1286 restore_win_noblock( 1287 win_T *save_curwin, 1288 tabpage_T *save_curtab, 1289 int no_display) 1290 { 1291 if (save_curtab != NULL && valid_tabpage(save_curtab)) 1292 { 1293 if (no_display) 1294 { 1295 curtab->tp_firstwin = firstwin; 1296 curtab->tp_lastwin = lastwin; 1297 curtab = save_curtab; 1298 firstwin = curtab->tp_firstwin; 1299 lastwin = curtab->tp_lastwin; 1300 } 1301 else 1302 goto_tabpage_tp(save_curtab, FALSE, FALSE); 1303 } 1304 if (win_valid(save_curwin)) 1305 { 1306 curwin = save_curwin; 1307 curbuf = curwin->w_buffer; 1308 } 1309 # ifdef FEAT_PROP_POPUP 1310 else if (WIN_IS_POPUP(curwin)) 1311 // original window was closed and now we're in a popup window: Go 1312 // to the first valid window. 1313 win_goto(firstwin); 1314 # endif 1315 1316 // If called by win_execute() and executing the command changed the 1317 // directory, it now has to be restored. 1318 fix_current_dir(); 1319 } 1320 #endif 1321