xref: /vim-8.2.3635/src/evalwindow.c (revision 345f28df)
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 	pos_T	curpos = wp->w_cursor;
659 
660 	if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
661 	{
662 	    check_cursor();
663 	    execute_common(argvars, rettv, 1);
664 	}
665 	restore_win_noblock(save_curwin, save_curtab, TRUE);
666 
667 	// Update the status line if the cursor moved.
668 	if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
669 	    wp->w_redr_status = TRUE;
670     }
671 }
672 
673 /*
674  * "win_findbuf()" function
675  */
676     void
677 f_win_findbuf(typval_T *argvars, typval_T *rettv)
678 {
679     if (rettv_list_alloc(rettv) != FAIL)
680 	win_findbuf(argvars, rettv->vval.v_list);
681 }
682 
683 /*
684  * "win_getid()" function
685  */
686     void
687 f_win_getid(typval_T *argvars, typval_T *rettv)
688 {
689     rettv->vval.v_number = win_getid(argvars);
690 }
691 
692 /*
693  * "win_gotoid()" function
694  */
695     void
696 f_win_gotoid(typval_T *argvars, typval_T *rettv)
697 {
698     win_T	*wp;
699     tabpage_T   *tp;
700     int		id = tv_get_number(&argvars[0]);
701 
702 #ifdef FEAT_CMDWIN
703     if (cmdwin_type != 0)
704     {
705 	emsg(_(e_cmdwin));
706 	return;
707     }
708 #endif
709     FOR_ALL_TAB_WINDOWS(tp, wp)
710 	if (wp->w_id == id)
711 	{
712 	    goto_tabpage_win(tp, wp);
713 	    rettv->vval.v_number = 1;
714 	    return;
715 	}
716 }
717 
718 /*
719  * "win_id2tabwin()" function
720  */
721     void
722 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
723 {
724     if (rettv_list_alloc(rettv) != FAIL)
725 	win_id2tabwin(argvars, rettv->vval.v_list);
726 }
727 
728 /*
729  * "win_id2win()" function
730  */
731     void
732 f_win_id2win(typval_T *argvars, typval_T *rettv)
733 {
734     rettv->vval.v_number = win_id2win(argvars);
735 }
736 
737 /*
738  * "win_screenpos()" function
739  */
740     void
741 f_win_screenpos(typval_T *argvars, typval_T *rettv)
742 {
743     win_T	*wp;
744 
745     if (rettv_list_alloc(rettv) == FAIL)
746 	return;
747 
748     wp = find_win_by_nr_or_id(&argvars[0]);
749     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
750     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
751 }
752 
753 /*
754  * Move the window wp into a new split of targetwin in a given direction
755  */
756     static void
757 win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
758 {
759     int	    dir;
760     int	    height = wp->w_height;
761     win_T   *oldwin = curwin;
762 
763     if (wp == targetwin)
764 	return;
765 
766     // Jump to the target window
767     if (curwin != targetwin)
768 	win_goto(targetwin);
769 
770     // Remove the old window and frame from the tree of frames
771     (void)winframe_remove(wp, &dir, NULL);
772     win_remove(wp, NULL);
773     last_status(FALSE);	    // may need to remove last status line
774     (void)win_comp_pos();   // recompute window positions
775 
776     // Split a window on the desired side and put the old window there
777     (void)win_split_ins(size, flags, wp, dir);
778 
779     // If splitting horizontally, try to preserve height
780     if (size == 0 && !(flags & WSP_VERT))
781     {
782 	win_setheight_win(height, wp);
783 	if (p_ea)
784 	    win_equal(wp, TRUE, 'v');
785     }
786 
787 #if defined(FEAT_GUI)
788     // When 'guioptions' includes 'L' or 'R' may have to remove or add
789     // scrollbars.  Have to update them anyway.
790     gui_may_update_scrollbars();
791 #endif
792 
793     if (oldwin != curwin)
794 	win_goto(oldwin);
795 }
796 
797 /*
798  * "win_splitmove()" function
799  */
800     void
801 f_win_splitmove(typval_T *argvars, typval_T *rettv)
802 {
803     win_T   *wp;
804     win_T   *targetwin;
805     int     flags = 0, size = 0;
806 
807     wp = find_win_by_nr_or_id(&argvars[0]);
808     targetwin = find_win_by_nr_or_id(&argvars[1]);
809 
810     if (wp == NULL || targetwin == NULL || wp == targetwin)
811     {
812         emsg(_(e_invalwindow));
813 	rettv->vval.v_number = -1;
814 	return;
815     }
816 
817     if (argvars[2].v_type != VAR_UNKNOWN)
818     {
819         dict_T      *d;
820         dictitem_T  *di;
821 
822         if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL)
823         {
824             emsg(_(e_invarg));
825             return;
826         }
827 
828         d = argvars[2].vval.v_dict;
829         if (dict_get_number(d, (char_u *)"vertical"))
830             flags |= WSP_VERT;
831         if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
832             flags |= tv_get_number(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
833         size = (int)dict_get_number(d, (char_u *)"size");
834     }
835 
836     win_move_into_split(wp, targetwin, size, flags);
837 }
838 
839 /*
840  * "winbufnr(nr)" function
841  */
842     void
843 f_winbufnr(typval_T *argvars, typval_T *rettv)
844 {
845     win_T	*wp;
846 
847     wp = find_win_by_nr_or_id(&argvars[0]);
848     if (wp == NULL)
849 	rettv->vval.v_number = -1;
850     else
851 	rettv->vval.v_number = wp->w_buffer->b_fnum;
852 }
853 
854 /*
855  * "wincol()" function
856  */
857     void
858 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
859 {
860     validate_cursor();
861     rettv->vval.v_number = curwin->w_wcol + 1;
862 }
863 
864 /*
865  * "winheight(nr)" function
866  */
867     void
868 f_winheight(typval_T *argvars, typval_T *rettv)
869 {
870     win_T	*wp;
871 
872     wp = find_win_by_nr_or_id(&argvars[0]);
873     if (wp == NULL)
874 	rettv->vval.v_number = -1;
875     else
876 	rettv->vval.v_number = wp->w_height;
877 }
878 
879 /*
880  * "winlayout()" function
881  */
882     void
883 f_winlayout(typval_T *argvars, typval_T *rettv)
884 {
885     tabpage_T	*tp;
886 
887     if (rettv_list_alloc(rettv) != OK)
888 	return;
889 
890     if (argvars[0].v_type == VAR_UNKNOWN)
891 	tp = curtab;
892     else
893     {
894 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
895 	if (tp == NULL)
896 	    return;
897     }
898 
899     get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
900 }
901 
902 /*
903  * "winline()" function
904  */
905     void
906 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
907 {
908     validate_cursor();
909     rettv->vval.v_number = curwin->w_wrow + 1;
910 }
911 
912 /*
913  * "winnr()" function
914  */
915     void
916 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
917 {
918     int		nr = 1;
919 
920     nr = get_winnr(curtab, &argvars[0]);
921     rettv->vval.v_number = nr;
922 }
923 
924 /*
925  * "winrestcmd()" function
926  */
927     void
928 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
929 {
930     win_T	*wp;
931     int		winnr = 1;
932     garray_T	ga;
933     char_u	buf[50];
934 
935     ga_init2(&ga, (int)sizeof(char), 70);
936     FOR_ALL_WINDOWS(wp)
937     {
938 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
939 	ga_concat(&ga, buf);
940 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
941 	ga_concat(&ga, buf);
942 	++winnr;
943     }
944     ga_append(&ga, NUL);
945 
946     rettv->vval.v_string = ga.ga_data;
947     rettv->v_type = VAR_STRING;
948 }
949 
950 /*
951  * "winrestview()" function
952  */
953     void
954 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
955 {
956     dict_T	*dict;
957 
958     if (argvars[0].v_type != VAR_DICT
959 	    || (dict = argvars[0].vval.v_dict) == NULL)
960 	emsg(_(e_invarg));
961     else
962     {
963 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
964 	    curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
965 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
966 	    curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
967 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
968 	    curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
969 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
970 	{
971 	    curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
972 	    curwin->w_set_curswant = FALSE;
973 	}
974 
975 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
976 	    set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
977 #ifdef FEAT_DIFF
978 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
979 	    curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
980 #endif
981 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
982 	    curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
983 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
984 	    curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
985 
986 	check_cursor();
987 	win_new_height(curwin, curwin->w_height);
988 	win_new_width(curwin, curwin->w_width);
989 	changed_window_setting();
990 
991 	if (curwin->w_topline <= 0)
992 	    curwin->w_topline = 1;
993 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
994 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
995 #ifdef FEAT_DIFF
996 	check_topfill(curwin, TRUE);
997 #endif
998     }
999 }
1000 
1001 /*
1002  * "winsaveview()" function
1003  */
1004     void
1005 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1006 {
1007     dict_T	*dict;
1008 
1009     if (rettv_dict_alloc(rettv) == FAIL)
1010 	return;
1011     dict = rettv->vval.v_dict;
1012 
1013     dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1014     dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1015     dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1016     update_curswant();
1017     dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1018 
1019     dict_add_number(dict, "topline", (long)curwin->w_topline);
1020 #ifdef FEAT_DIFF
1021     dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1022 #endif
1023     dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1024     dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1025 }
1026 
1027 /*
1028  * "winwidth(nr)" function
1029  */
1030     void
1031 f_winwidth(typval_T *argvars, typval_T *rettv)
1032 {
1033     win_T	*wp;
1034 
1035     wp = find_win_by_nr_or_id(&argvars[0]);
1036     if (wp == NULL)
1037 	rettv->vval.v_number = -1;
1038     else
1039 	rettv->vval.v_number = wp->w_width;
1040 }
1041 #endif // FEAT_EVAL
1042 
1043 #if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1044 	|| defined(PROTO)
1045 /*
1046  * Set "win" to be the curwin and "tp" to be the current tab page.
1047  * restore_win() MUST be called to undo, also when FAIL is returned.
1048  * No autocommands will be executed until restore_win() is called.
1049  * When "no_display" is TRUE the display won't be affected, no redraw is
1050  * triggered, another tabpage access is limited.
1051  * Returns FAIL if switching to "win" failed.
1052  */
1053     int
1054 switch_win(
1055     win_T	**save_curwin,
1056     tabpage_T	**save_curtab,
1057     win_T	*win,
1058     tabpage_T	*tp,
1059     int		no_display)
1060 {
1061     block_autocmds();
1062     return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
1063 }
1064 
1065 /*
1066  * As switch_win() but without blocking autocommands.
1067  */
1068     int
1069 switch_win_noblock(
1070     win_T	**save_curwin,
1071     tabpage_T	**save_curtab,
1072     win_T	*win,
1073     tabpage_T	*tp,
1074     int		no_display)
1075 {
1076     *save_curwin = curwin;
1077     if (tp != NULL)
1078     {
1079 	*save_curtab = curtab;
1080 	if (no_display)
1081 	{
1082 	    curtab->tp_firstwin = firstwin;
1083 	    curtab->tp_lastwin = lastwin;
1084 	    curtab = tp;
1085 	    firstwin = curtab->tp_firstwin;
1086 	    lastwin = curtab->tp_lastwin;
1087 	}
1088 	else
1089 	    goto_tabpage_tp(tp, FALSE, FALSE);
1090     }
1091     if (!win_valid(win))
1092 	return FAIL;
1093     curwin = win;
1094     curbuf = curwin->w_buffer;
1095     return OK;
1096 }
1097 
1098 /*
1099  * Restore current tabpage and window saved by switch_win(), if still valid.
1100  * When "no_display" is TRUE the display won't be affected, no redraw is
1101  * triggered.
1102  */
1103     void
1104 restore_win(
1105     win_T	*save_curwin,
1106     tabpage_T	*save_curtab,
1107     int		no_display)
1108 {
1109     restore_win_noblock(save_curwin, save_curtab, no_display);
1110     unblock_autocmds();
1111 }
1112 
1113 /*
1114  * As restore_win() but without unblocking autocommands.
1115  */
1116     void
1117 restore_win_noblock(
1118     win_T	*save_curwin,
1119     tabpage_T	*save_curtab,
1120     int		no_display)
1121 {
1122     if (save_curtab != NULL && valid_tabpage(save_curtab))
1123     {
1124 	if (no_display)
1125 	{
1126 	    curtab->tp_firstwin = firstwin;
1127 	    curtab->tp_lastwin = lastwin;
1128 	    curtab = save_curtab;
1129 	    firstwin = curtab->tp_firstwin;
1130 	    lastwin = curtab->tp_lastwin;
1131 	}
1132 	else
1133 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
1134     }
1135     if (win_valid(save_curwin))
1136     {
1137 	curwin = save_curwin;
1138 	curbuf = curwin->w_buffer;
1139     }
1140 # ifdef FEAT_TEXT_PROP
1141     else if (WIN_IS_POPUP(curwin))
1142 	// original window was closed and now we're in a popup window: Go
1143 	// to the first valid window.
1144 	win_goto(firstwin);
1145 # endif
1146 }
1147 #endif
1148