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
win_getid(typval_T * argvars)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
win_id2tabwin(typval_T * argvars,list_T * list)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 *
win_id2wp(int id)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 *
win_id2wp_tp(int id,tabpage_T ** tpp)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
win_id2win(typval_T * argvars)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
win_findbuf(typval_T * argvars,list_T * list)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 *
find_win_by_nr(typval_T * vp,tabpage_T * tp)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 *
find_win_by_nr_or_id(typval_T * vp)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 *
find_tabwin(typval_T * wvp,typval_T * tvp,tabpage_T ** ptp)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
get_framelayout(frame_T * fr,list_T * l,int outer)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
get_winnr(tabpage_T * tp,typval_T * argvar)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 *
get_win_info(win_T * wp,short tpnr,short winnr)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 *
get_tabpage_info(tabpage_T * tp,int tp_idx)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
f_gettabinfo(typval_T * argvars,typval_T * rettv)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
f_getwininfo(typval_T * argvars,typval_T * rettv)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
f_getwinpos(typval_T * argvars UNUSED,typval_T * rettv)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
f_getwinposx(typval_T * argvars UNUSED,typval_T * rettv)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
f_getwinposy(typval_T * argvars UNUSED,typval_T * rettv)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
f_tabpagenr(typval_T * argvars UNUSED,typval_T * rettv)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
f_tabpagewinnr(typval_T * argvars UNUSED,typval_T * rettv)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
f_win_execute(typval_T * argvars,typval_T * rettv)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
f_win_findbuf(typval_T * argvars,typval_T * rettv)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
f_win_getid(typval_T * argvars,typval_T * rettv)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
f_win_gotoid(typval_T * argvars,typval_T * rettv)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
f_win_id2tabwin(typval_T * argvars,typval_T * rettv)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
f_win_id2win(typval_T * argvars,typval_T * rettv)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
f_win_screenpos(typval_T * argvars,typval_T * rettv)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
win_move_into_split(win_T * wp,win_T * targetwin,int size,int flags)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
f_win_splitmove(typval_T * argvars,typval_T * rettv)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
f_win_gettype(typval_T * argvars,typval_T * rettv)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
f_getcmdwintype(typval_T * argvars UNUSED,typval_T * rettv)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
f_winbufnr(typval_T * argvars,typval_T * rettv)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
f_wincol(typval_T * argvars UNUSED,typval_T * rettv)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
f_winheight(typval_T * argvars,typval_T * rettv)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
f_winlayout(typval_T * argvars,typval_T * rettv)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
f_winline(typval_T * argvars UNUSED,typval_T * rettv)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
f_winnr(typval_T * argvars UNUSED,typval_T * rettv)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
f_winrestcmd(typval_T * argvars UNUSED,typval_T * rettv)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
f_winrestview(typval_T * argvars,typval_T * rettv UNUSED)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
f_winsaveview(typval_T * argvars UNUSED,typval_T * rettv)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
f_winwidth(typval_T * argvars,typval_T * rettv)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
switch_win(win_T ** save_curwin,tabpage_T ** save_curtab,win_T * win,tabpage_T * tp,int no_display)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
switch_win_noblock(win_T ** save_curwin,tabpage_T ** save_curtab,win_T * win,tabpage_T * tp,int no_display)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
restore_win(win_T * save_curwin,tabpage_T * save_curtab,int no_display)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
restore_win_noblock(win_T * save_curwin,tabpage_T * save_curtab,int no_display)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