xref: /vim-8.2.3635/src/evalwindow.c (revision 30e8e735)
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_TEXT_PROP
107     // popup windows are in separate lists
108      FOR_ALL_TABPAGES(tp)
109 	 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
110 	     if (wp->w_id == id)
111 	     {
112 		 if (tpp != NULL)
113 		     *tpp = tp;
114 		 return wp;
115 	     }
116     for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
117 	if (wp->w_id == id)
118 	{
119 	    if (tpp != NULL)
120 		*tpp = tp;
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_TEXT_PROP
185 	// check tab-local popup windows
186 	for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
187 	    if (wp->w_id == nr)
188 		return wp;
189 	// check global popup windows
190 	for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
191 	    if (wp->w_id == nr)
192 		return wp;
193 #endif
194 	return NULL;
195     }
196     return wp;
197 }
198 
199 /*
200  * Find a window: When using a Window ID in any tab page, when using a number
201  * in the current tab page.
202  */
203     win_T *
204 find_win_by_nr_or_id(typval_T *vp)
205 {
206     int	nr = (int)tv_get_number_chk(vp, NULL);
207 
208     if (nr >= LOWEST_WIN_ID)
209 	return win_id2wp(tv_get_number(vp));
210     return find_win_by_nr(vp, NULL);
211 }
212 
213 /*
214  * Find window specified by "wvp" in tabpage "tvp".
215  * Returns the tab page in 'ptp'
216  */
217     win_T *
218 find_tabwin(
219     typval_T	*wvp,	// VAR_UNKNOWN for current window
220     typval_T	*tvp,	// VAR_UNKNOWN for current tab page
221     tabpage_T	**ptp)
222 {
223     win_T	*wp = NULL;
224     tabpage_T	*tp = NULL;
225     long	n;
226 
227     if (wvp->v_type != VAR_UNKNOWN)
228     {
229 	if (tvp->v_type != VAR_UNKNOWN)
230 	{
231 	    n = (long)tv_get_number(tvp);
232 	    if (n >= 0)
233 		tp = find_tabpage(n);
234 	}
235 	else
236 	    tp = curtab;
237 
238 	if (tp != NULL)
239 	{
240 	    wp = find_win_by_nr(wvp, tp);
241 	    if (wp == NULL && wvp->v_type == VAR_NUMBER
242 						&& wvp->vval.v_number != -1)
243 		// A window with the specified number is not found
244 		tp = NULL;
245 	}
246     }
247     else
248     {
249 	wp = curwin;
250 	tp = curtab;
251     }
252 
253     if (ptp != NULL)
254 	*ptp = tp;
255 
256     return wp;
257 }
258 
259 /*
260  * Get the layout of the given tab page for winlayout().
261  */
262     static void
263 get_framelayout(frame_T *fr, list_T *l, int outer)
264 {
265     frame_T	*child;
266     list_T	*fr_list;
267     list_T	*win_list;
268 
269     if (fr == NULL)
270 	return;
271 
272     if (outer)
273 	// outermost call from f_winlayout()
274 	fr_list = l;
275     else
276     {
277 	fr_list = list_alloc();
278 	if (fr_list == NULL)
279 	    return;
280 	list_append_list(l, fr_list);
281     }
282 
283     if (fr->fr_layout == FR_LEAF)
284     {
285 	if (fr->fr_win != NULL)
286 	{
287 	    list_append_string(fr_list, (char_u *)"leaf", -1);
288 	    list_append_number(fr_list, fr->fr_win->w_id);
289 	}
290     }
291     else
292     {
293 	list_append_string(fr_list,
294 	     fr->fr_layout == FR_ROW ?  (char_u *)"row" : (char_u *)"col", -1);
295 
296 	win_list = list_alloc();
297 	if (win_list == NULL)
298 	    return;
299 	list_append_list(fr_list, win_list);
300 	child = fr->fr_child;
301 	while (child != NULL)
302 	{
303 	    get_framelayout(child, win_list, FALSE);
304 	    child = child->fr_next;
305 	}
306     }
307 }
308 
309 /*
310  * Common code for tabpagewinnr() and winnr().
311  */
312     static int
313 get_winnr(tabpage_T *tp, typval_T *argvar)
314 {
315     win_T	*twin;
316     int		nr = 1;
317     win_T	*wp;
318     char_u	*arg;
319 
320     twin = (tp == curtab) ? curwin : tp->tp_curwin;
321     if (argvar->v_type != VAR_UNKNOWN)
322     {
323 	int	invalid_arg = FALSE;
324 
325 	arg = tv_get_string_chk(argvar);
326 	if (arg == NULL)
327 	    nr = 0;		// type error; errmsg already given
328 	else if (STRCMP(arg, "$") == 0)
329 	    twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
330 	else if (STRCMP(arg, "#") == 0)
331 	{
332 	    twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
333 	    if (twin == NULL)
334 		nr = 0;
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 
362 	if (invalid_arg)
363 	{
364 	    semsg(_(e_invexpr2), arg);
365 	    nr = 0;
366 	}
367     }
368 
369     if (nr > 0)
370 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
371 					      wp != twin; wp = wp->w_next)
372 	{
373 	    if (wp == NULL)
374 	    {
375 		// didn't find it in this tabpage
376 		nr = 0;
377 		break;
378 	    }
379 	    ++nr;
380 	}
381     return nr;
382 }
383 
384 /*
385  * Returns information about a window as a dictionary.
386  */
387     static dict_T *
388 get_win_info(win_T *wp, short tpnr, short winnr)
389 {
390     dict_T	*dict;
391 
392     dict = dict_alloc();
393     if (dict == NULL)
394 	return NULL;
395 
396     dict_add_number(dict, "tabnr", tpnr);
397     dict_add_number(dict, "winnr", winnr);
398     dict_add_number(dict, "winid", wp->w_id);
399     dict_add_number(dict, "height", wp->w_height);
400     dict_add_number(dict, "winrow", wp->w_winrow + 1);
401     dict_add_number(dict, "topline", wp->w_topline);
402     dict_add_number(dict, "botline", wp->w_botline - 1);
403 #ifdef FEAT_MENU
404     dict_add_number(dict, "winbar", wp->w_winbar_height);
405 #endif
406     dict_add_number(dict, "width", wp->w_width);
407     dict_add_number(dict, "wincol", wp->w_wincol + 1);
408     dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
409 
410 #ifdef FEAT_TERMINAL
411     dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
412 #endif
413 #ifdef FEAT_QUICKFIX
414     dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
415     dict_add_number(dict, "loclist",
416 		      (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
417 #endif
418 
419     // Add a reference to window variables
420     dict_add_dict(dict, "variables", wp->w_vars);
421 
422     return dict;
423 }
424 
425 /*
426  * Returns information (variables, options, etc.) about a tab page
427  * as a dictionary.
428  */
429     static dict_T *
430 get_tabpage_info(tabpage_T *tp, int tp_idx)
431 {
432     win_T	*wp;
433     dict_T	*dict;
434     list_T	*l;
435 
436     dict = dict_alloc();
437     if (dict == NULL)
438 	return NULL;
439 
440     dict_add_number(dict, "tabnr", tp_idx);
441 
442     l = list_alloc();
443     if (l != NULL)
444     {
445 	for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
446 						   wp != NULL; wp = wp->w_next)
447 	    list_append_number(l, (varnumber_T)wp->w_id);
448 	dict_add_list(dict, "windows", l);
449     }
450 
451     // Make a reference to tabpage variables
452     dict_add_dict(dict, "variables", tp->tp_vars);
453 
454     return dict;
455 }
456 
457 /*
458  * "gettabinfo()" function
459  */
460     void
461 f_gettabinfo(typval_T *argvars, typval_T *rettv)
462 {
463     tabpage_T	*tp, *tparg = NULL;
464     dict_T	*d;
465     int		tpnr = 0;
466 
467     if (rettv_list_alloc(rettv) != OK)
468 	return;
469 
470     if (argvars[0].v_type != VAR_UNKNOWN)
471     {
472 	// Information about one tab page
473 	tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
474 	if (tparg == NULL)
475 	    return;
476     }
477 
478     // Get information about a specific tab page or all tab pages
479     FOR_ALL_TABPAGES(tp)
480     {
481 	tpnr++;
482 	if (tparg != NULL && tp != tparg)
483 	    continue;
484 	d = get_tabpage_info(tp, tpnr);
485 	if (d != NULL)
486 	    list_append_dict(rettv->vval.v_list, d);
487 	if (tparg != NULL)
488 	    return;
489     }
490 }
491 
492 /*
493  * "getwininfo()" function
494  */
495     void
496 f_getwininfo(typval_T *argvars, typval_T *rettv)
497 {
498     tabpage_T	*tp;
499     win_T	*wp = NULL, *wparg = NULL;
500     dict_T	*d;
501     short	tabnr = 0, winnr;
502 
503     if (rettv_list_alloc(rettv) != OK)
504 	return;
505 
506     if (argvars[0].v_type != VAR_UNKNOWN)
507     {
508 	wparg = win_id2wp(tv_get_number(&argvars[0]));
509 	if (wparg == NULL)
510 	    return;
511     }
512 
513     // Collect information about either all the windows across all the tab
514     // pages or one particular window.
515     FOR_ALL_TABPAGES(tp)
516     {
517 	tabnr++;
518 	winnr = 0;
519 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
520 	{
521 	    winnr++;
522 	    if (wparg != NULL && wp != wparg)
523 		continue;
524 	    d = get_win_info(wp, tabnr, winnr);
525 	    if (d != NULL)
526 		list_append_dict(rettv->vval.v_list, d);
527 	    if (wparg != NULL)
528 		// found information about a specific window
529 		return;
530 	}
531     }
532 }
533 
534 /*
535  * "getwinpos({timeout})" function
536  */
537     void
538 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
539 {
540     int x = -1;
541     int y = -1;
542 
543     if (rettv_list_alloc(rettv) == FAIL)
544 	return;
545 #if defined(FEAT_GUI) \
546 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
547 	|| defined(MSWIN)
548     {
549 	varnumber_T timeout = 100;
550 
551 	if (argvars[0].v_type != VAR_UNKNOWN)
552 	    timeout = tv_get_number(&argvars[0]);
553 
554 	(void)ui_get_winpos(&x, &y, timeout);
555     }
556 #endif
557     list_append_number(rettv->vval.v_list, (varnumber_T)x);
558     list_append_number(rettv->vval.v_list, (varnumber_T)y);
559 }
560 
561 
562 /*
563  * "getwinposx()" function
564  */
565     void
566 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
567 {
568     rettv->vval.v_number = -1;
569 #if defined(FEAT_GUI) \
570 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
571 	|| defined(MSWIN)
572 
573     {
574 	int	    x, y;
575 
576 	if (ui_get_winpos(&x, &y, 100) == OK)
577 	    rettv->vval.v_number = x;
578     }
579 #endif
580 }
581 
582 /*
583  * "getwinposy()" function
584  */
585     void
586 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
587 {
588     rettv->vval.v_number = -1;
589 #if defined(FEAT_GUI) \
590 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
591 	|| defined(MSWIN)
592     {
593 	int	    x, y;
594 
595 	if (ui_get_winpos(&x, &y, 100) == OK)
596 	    rettv->vval.v_number = y;
597     }
598 #endif
599 }
600 
601 /*
602  * "tabpagenr()" function
603  */
604     void
605 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
606 {
607     int		nr = 1;
608     char_u	*arg;
609 
610     if (argvars[0].v_type != VAR_UNKNOWN)
611     {
612 	arg = tv_get_string_chk(&argvars[0]);
613 	nr = 0;
614 	if (arg != NULL)
615 	{
616 	    if (STRCMP(arg, "$") == 0)
617 		nr = tabpage_index(NULL) - 1;
618 	    else
619 		semsg(_(e_invexpr2), arg);
620 	}
621     }
622     else
623 	nr = tabpage_index(curtab);
624     rettv->vval.v_number = nr;
625 }
626 
627 /*
628  * "tabpagewinnr()" function
629  */
630     void
631 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
632 {
633     int		nr = 1;
634     tabpage_T	*tp;
635 
636     tp = find_tabpage((int)tv_get_number(&argvars[0]));
637     if (tp == NULL)
638 	nr = 0;
639     else
640 	nr = get_winnr(tp, &argvars[1]);
641     rettv->vval.v_number = nr;
642 }
643 
644 /*
645  * "win_execute()" function
646  */
647     void
648 f_win_execute(typval_T *argvars, typval_T *rettv)
649 {
650     int		id = (int)tv_get_number(argvars);
651     tabpage_T	*tp;
652     win_T	*wp = win_id2wp_tp(id, &tp);
653     win_T	*save_curwin;
654     tabpage_T	*save_curtab;
655 
656     if (wp != NULL && tp != NULL)
657     {
658 	if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
659 	{
660 	    check_cursor();
661 	    execute_common(argvars, rettv, 1);
662 	}
663 	restore_win_noblock(save_curwin, save_curtab, TRUE);
664     }
665 }
666 
667 /*
668  * "win_findbuf()" function
669  */
670     void
671 f_win_findbuf(typval_T *argvars, typval_T *rettv)
672 {
673     if (rettv_list_alloc(rettv) != FAIL)
674 	win_findbuf(argvars, rettv->vval.v_list);
675 }
676 
677 /*
678  * "win_getid()" function
679  */
680     void
681 f_win_getid(typval_T *argvars, typval_T *rettv)
682 {
683     rettv->vval.v_number = win_getid(argvars);
684 }
685 
686 /*
687  * "win_gotoid()" function
688  */
689     void
690 f_win_gotoid(typval_T *argvars, typval_T *rettv)
691 {
692     win_T	*wp;
693     tabpage_T   *tp;
694     int		id = tv_get_number(&argvars[0]);
695 
696 #ifdef FEAT_CMDWIN
697     if (cmdwin_type != 0)
698     {
699 	emsg(_(e_cmdwin));
700 	return;
701     }
702 #endif
703     FOR_ALL_TAB_WINDOWS(tp, wp)
704 	if (wp->w_id == id)
705 	{
706 	    goto_tabpage_win(tp, wp);
707 	    rettv->vval.v_number = 1;
708 	    return;
709 	}
710 }
711 
712 /*
713  * "win_id2tabwin()" function
714  */
715     void
716 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
717 {
718     if (rettv_list_alloc(rettv) != FAIL)
719 	win_id2tabwin(argvars, rettv->vval.v_list);
720 }
721 
722 /*
723  * "win_id2win()" function
724  */
725     void
726 f_win_id2win(typval_T *argvars, typval_T *rettv)
727 {
728     rettv->vval.v_number = win_id2win(argvars);
729 }
730 
731 /*
732  * "win_screenpos()" function
733  */
734     void
735 f_win_screenpos(typval_T *argvars, typval_T *rettv)
736 {
737     win_T	*wp;
738 
739     if (rettv_list_alloc(rettv) == FAIL)
740 	return;
741 
742     wp = find_win_by_nr_or_id(&argvars[0]);
743     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
744     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
745 }
746 
747 /*
748  * Move the window wp into a new split of targetwin in a given direction
749  */
750     static void
751 win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
752 {
753     int	    dir;
754     int	    height = wp->w_height;
755     win_T   *oldwin = curwin;
756 
757     if (wp == targetwin)
758 	return;
759 
760     // Jump to the target window
761     if (curwin != targetwin)
762 	win_goto(targetwin);
763 
764     // Remove the old window and frame from the tree of frames
765     (void)winframe_remove(wp, &dir, NULL);
766     win_remove(wp, NULL);
767     last_status(FALSE);	    // may need to remove last status line
768     (void)win_comp_pos();   // recompute window positions
769 
770     // Split a window on the desired side and put the old window there
771     (void)win_split_ins(size, flags, wp, dir);
772 
773     // If splitting horizontally, try to preserve height
774     if (size == 0 && !(flags & WSP_VERT))
775     {
776 	win_setheight_win(height, wp);
777 	if (p_ea)
778 	    win_equal(wp, TRUE, 'v');
779     }
780 
781 #if defined(FEAT_GUI)
782     // When 'guioptions' includes 'L' or 'R' may have to remove or add
783     // scrollbars.  Have to update them anyway.
784     gui_may_update_scrollbars();
785 #endif
786 
787     if (oldwin != curwin)
788 	win_goto(oldwin);
789 }
790 
791 /*
792  * "win_splitmove()" function
793  */
794     void
795 f_win_splitmove(typval_T *argvars, typval_T *rettv)
796 {
797     win_T   *wp;
798     win_T   *targetwin;
799     int     flags = 0, size = 0;
800 
801     wp = find_win_by_nr_or_id(&argvars[0]);
802     targetwin = find_win_by_nr_or_id(&argvars[1]);
803 
804     if (wp == NULL || targetwin == NULL || wp == targetwin)
805     {
806         emsg(_(e_invalwindow));
807 	rettv->vval.v_number = -1;
808 	return;
809     }
810 
811     if (argvars[2].v_type != VAR_UNKNOWN)
812     {
813         dict_T      *d;
814         dictitem_T  *di;
815 
816         if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL)
817         {
818             emsg(_(e_invarg));
819             return;
820         }
821 
822         d = argvars[2].vval.v_dict;
823         if (dict_get_number(d, (char_u *)"vertical"))
824             flags |= WSP_VERT;
825         if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
826             flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
827         size = (int)dict_get_number(d, (char_u *)"size");
828     }
829 
830     win_move_into_split(wp, targetwin, size, flags);
831 }
832 
833 /*
834  * "winbufnr(nr)" function
835  */
836     void
837 f_winbufnr(typval_T *argvars, typval_T *rettv)
838 {
839     win_T	*wp;
840 
841     wp = find_win_by_nr_or_id(&argvars[0]);
842     if (wp == NULL)
843 	rettv->vval.v_number = -1;
844     else
845 	rettv->vval.v_number = wp->w_buffer->b_fnum;
846 }
847 
848 /*
849  * "wincol()" function
850  */
851     void
852 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
853 {
854     validate_cursor();
855     rettv->vval.v_number = curwin->w_wcol + 1;
856 }
857 
858 /*
859  * "winheight(nr)" function
860  */
861     void
862 f_winheight(typval_T *argvars, typval_T *rettv)
863 {
864     win_T	*wp;
865 
866     wp = find_win_by_nr_or_id(&argvars[0]);
867     if (wp == NULL)
868 	rettv->vval.v_number = -1;
869     else
870 	rettv->vval.v_number = wp->w_height;
871 }
872 
873 /*
874  * "winlayout()" function
875  */
876     void
877 f_winlayout(typval_T *argvars, typval_T *rettv)
878 {
879     tabpage_T	*tp;
880 
881     if (rettv_list_alloc(rettv) != OK)
882 	return;
883 
884     if (argvars[0].v_type == VAR_UNKNOWN)
885 	tp = curtab;
886     else
887     {
888 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
889 	if (tp == NULL)
890 	    return;
891     }
892 
893     get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
894 }
895 
896 /*
897  * "winline()" function
898  */
899     void
900 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
901 {
902     validate_cursor();
903     rettv->vval.v_number = curwin->w_wrow + 1;
904 }
905 
906 /*
907  * "winnr()" function
908  */
909     void
910 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
911 {
912     int		nr = 1;
913 
914     nr = get_winnr(curtab, &argvars[0]);
915     rettv->vval.v_number = nr;
916 }
917 
918 /*
919  * "winrestcmd()" function
920  */
921     void
922 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
923 {
924     win_T	*wp;
925     int		winnr = 1;
926     garray_T	ga;
927     char_u	buf[50];
928 
929     ga_init2(&ga, (int)sizeof(char), 70);
930     FOR_ALL_WINDOWS(wp)
931     {
932 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
933 	ga_concat(&ga, buf);
934 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
935 	ga_concat(&ga, buf);
936 	++winnr;
937     }
938     ga_append(&ga, NUL);
939 
940     rettv->vval.v_string = ga.ga_data;
941     rettv->v_type = VAR_STRING;
942 }
943 
944 /*
945  * "winrestview()" function
946  */
947     void
948 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
949 {
950     dict_T	*dict;
951 
952     if (argvars[0].v_type != VAR_DICT
953 	    || (dict = argvars[0].vval.v_dict) == NULL)
954 	emsg(_(e_invarg));
955     else
956     {
957 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
958 	    curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
959 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
960 	    curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
961 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
962 	    curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
963 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
964 	{
965 	    curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
966 	    curwin->w_set_curswant = FALSE;
967 	}
968 
969 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
970 	    set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
971 #ifdef FEAT_DIFF
972 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
973 	    curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
974 #endif
975 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
976 	    curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
977 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
978 	    curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
979 
980 	check_cursor();
981 	win_new_height(curwin, curwin->w_height);
982 	win_new_width(curwin, curwin->w_width);
983 	changed_window_setting();
984 
985 	if (curwin->w_topline <= 0)
986 	    curwin->w_topline = 1;
987 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
988 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
989 #ifdef FEAT_DIFF
990 	check_topfill(curwin, TRUE);
991 #endif
992     }
993 }
994 
995 /*
996  * "winsaveview()" function
997  */
998     void
999 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1000 {
1001     dict_T	*dict;
1002 
1003     if (rettv_dict_alloc(rettv) == FAIL)
1004 	return;
1005     dict = rettv->vval.v_dict;
1006 
1007     dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1008     dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1009     dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1010     update_curswant();
1011     dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1012 
1013     dict_add_number(dict, "topline", (long)curwin->w_topline);
1014 #ifdef FEAT_DIFF
1015     dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1016 #endif
1017     dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1018     dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1019 }
1020 
1021 /*
1022  * "winwidth(nr)" function
1023  */
1024     void
1025 f_winwidth(typval_T *argvars, typval_T *rettv)
1026 {
1027     win_T	*wp;
1028 
1029     wp = find_win_by_nr_or_id(&argvars[0]);
1030     if (wp == NULL)
1031 	rettv->vval.v_number = -1;
1032     else
1033 	rettv->vval.v_number = wp->w_width;
1034 }
1035 #endif // FEAT_EVAL
1036 
1037 #if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1038 	|| defined(PROTO)
1039 /*
1040  * Set "win" to be the curwin and "tp" to be the current tab page.
1041  * restore_win() MUST be called to undo, also when FAIL is returned.
1042  * No autocommands will be executed until restore_win() is called.
1043  * When "no_display" is TRUE the display won't be affected, no redraw is
1044  * triggered, another tabpage access is limited.
1045  * Returns FAIL if switching to "win" failed.
1046  */
1047     int
1048 switch_win(
1049     win_T	**save_curwin,
1050     tabpage_T	**save_curtab,
1051     win_T	*win,
1052     tabpage_T	*tp,
1053     int		no_display)
1054 {
1055     block_autocmds();
1056     return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
1057 }
1058 
1059 /*
1060  * As switch_win() but without blocking autocommands.
1061  */
1062     int
1063 switch_win_noblock(
1064     win_T	**save_curwin,
1065     tabpage_T	**save_curtab,
1066     win_T	*win,
1067     tabpage_T	*tp,
1068     int		no_display)
1069 {
1070     *save_curwin = curwin;
1071     if (tp != NULL)
1072     {
1073 	*save_curtab = curtab;
1074 	if (no_display)
1075 	{
1076 	    curtab->tp_firstwin = firstwin;
1077 	    curtab->tp_lastwin = lastwin;
1078 	    curtab = tp;
1079 	    firstwin = curtab->tp_firstwin;
1080 	    lastwin = curtab->tp_lastwin;
1081 	}
1082 	else
1083 	    goto_tabpage_tp(tp, FALSE, FALSE);
1084     }
1085     if (!win_valid(win))
1086 	return FAIL;
1087     curwin = win;
1088     curbuf = curwin->w_buffer;
1089     return OK;
1090 }
1091 
1092 /*
1093  * Restore current tabpage and window saved by switch_win(), if still valid.
1094  * When "no_display" is TRUE the display won't be affected, no redraw is
1095  * triggered.
1096  */
1097     void
1098 restore_win(
1099     win_T	*save_curwin,
1100     tabpage_T	*save_curtab,
1101     int		no_display)
1102 {
1103     restore_win_noblock(save_curwin, save_curtab, no_display);
1104     unblock_autocmds();
1105 }
1106 
1107 /*
1108  * As restore_win() but without unblocking autocommands.
1109  */
1110     void
1111 restore_win_noblock(
1112     win_T	*save_curwin,
1113     tabpage_T	*save_curtab,
1114     int		no_display)
1115 {
1116     if (save_curtab != NULL && valid_tabpage(save_curtab))
1117     {
1118 	if (no_display)
1119 	{
1120 	    curtab->tp_firstwin = firstwin;
1121 	    curtab->tp_lastwin = lastwin;
1122 	    curtab = save_curtab;
1123 	    firstwin = curtab->tp_firstwin;
1124 	    lastwin = curtab->tp_lastwin;
1125 	}
1126 	else
1127 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
1128     }
1129     if (win_valid(save_curwin))
1130     {
1131 	curwin = save_curwin;
1132 	curbuf = curwin->w_buffer;
1133     }
1134 # ifdef FEAT_TEXT_PROP
1135     else if (WIN_IS_POPUP(curwin))
1136 	// original window was closed and now we're in a popup window: Go
1137 	// to the first valid window.
1138 	win_goto(firstwin);
1139 # endif
1140 }
1141 #endif
1142