xref: /vim-8.2.3635/src/evalwindow.c (revision 8ea05de6)
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_invexpr2), 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, "bufnr", wp->w_buffer->b_fnum);
411 
412 #ifdef FEAT_TERMINAL
413     dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
414 #endif
415 #ifdef FEAT_QUICKFIX
416     dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
417     dict_add_number(dict, "loclist",
418 		      (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
419 #endif
420 
421     // Add a reference to window variables
422     dict_add_dict(dict, "variables", wp->w_vars);
423 
424     return dict;
425 }
426 
427 /*
428  * Returns information (variables, options, etc.) about a tab page
429  * as a dictionary.
430  */
431     static dict_T *
432 get_tabpage_info(tabpage_T *tp, int tp_idx)
433 {
434     win_T	*wp;
435     dict_T	*dict;
436     list_T	*l;
437 
438     dict = dict_alloc();
439     if (dict == NULL)
440 	return NULL;
441 
442     dict_add_number(dict, "tabnr", tp_idx);
443 
444     l = list_alloc();
445     if (l != NULL)
446     {
447 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
448 	    list_append_number(l, (varnumber_T)wp->w_id);
449 	dict_add_list(dict, "windows", l);
450     }
451 
452     // Make a reference to tabpage variables
453     dict_add_dict(dict, "variables", tp->tp_vars);
454 
455     return dict;
456 }
457 
458 /*
459  * "gettabinfo()" function
460  */
461     void
462 f_gettabinfo(typval_T *argvars, typval_T *rettv)
463 {
464     tabpage_T	*tp, *tparg = NULL;
465     dict_T	*d;
466     int		tpnr = 0;
467 
468     if (rettv_list_alloc(rettv) != OK)
469 	return;
470 
471     if (argvars[0].v_type != VAR_UNKNOWN)
472     {
473 	// Information about one tab page
474 	tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
475 	if (tparg == NULL)
476 	    return;
477     }
478 
479     // Get information about a specific tab page or all tab pages
480     FOR_ALL_TABPAGES(tp)
481     {
482 	tpnr++;
483 	if (tparg != NULL && tp != tparg)
484 	    continue;
485 	d = get_tabpage_info(tp, tpnr);
486 	if (d != NULL)
487 	    list_append_dict(rettv->vval.v_list, d);
488 	if (tparg != NULL)
489 	    return;
490     }
491 }
492 
493 /*
494  * "getwininfo()" function
495  */
496     void
497 f_getwininfo(typval_T *argvars, typval_T *rettv)
498 {
499     tabpage_T	*tp;
500     win_T	*wp = NULL, *wparg = NULL;
501     dict_T	*d;
502     short	tabnr = 0, winnr;
503 
504     if (rettv_list_alloc(rettv) != OK)
505 	return;
506 
507     if (argvars[0].v_type != VAR_UNKNOWN)
508     {
509 	wparg = win_id2wp(tv_get_number(&argvars[0]));
510 	if (wparg == NULL)
511 	    return;
512     }
513 
514     // Collect information about either all the windows across all the tab
515     // pages or one particular window.
516     FOR_ALL_TABPAGES(tp)
517     {
518 	tabnr++;
519 	winnr = 0;
520 	FOR_ALL_WINDOWS_IN_TAB(tp, wp)
521 	{
522 	    winnr++;
523 	    if (wparg != NULL && wp != wparg)
524 		continue;
525 	    d = get_win_info(wp, tabnr, winnr);
526 	    if (d != NULL)
527 		list_append_dict(rettv->vval.v_list, d);
528 	    if (wparg != NULL)
529 		// found information about a specific window
530 		return;
531 	}
532     }
533 #ifdef FEAT_PROP_POPUP
534     if (wparg != NULL)
535     {
536 	tabnr = 0;
537 	FOR_ALL_TABPAGES(tp)
538 	{
539 	    tabnr++;
540 	    FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
541 	    if (wp == wparg)
542 		break;
543 	}
544 	d = get_win_info(wparg, tp == NULL ? 0 : tabnr, 0);
545 	if (d != NULL)
546 	    list_append_dict(rettv->vval.v_list, d);
547     }
548 #endif
549 }
550 
551 /*
552  * "getwinpos({timeout})" function
553  */
554     void
555 f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
556 {
557     int x = -1;
558     int y = -1;
559 
560     if (rettv_list_alloc(rettv) == FAIL)
561 	return;
562 #if defined(FEAT_GUI) \
563 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
564 	|| defined(MSWIN)
565     {
566 	varnumber_T timeout = 100;
567 
568 	if (argvars[0].v_type != VAR_UNKNOWN)
569 	    timeout = tv_get_number(&argvars[0]);
570 
571 	(void)ui_get_winpos(&x, &y, timeout);
572     }
573 #endif
574     list_append_number(rettv->vval.v_list, (varnumber_T)x);
575     list_append_number(rettv->vval.v_list, (varnumber_T)y);
576 }
577 
578 
579 /*
580  * "getwinposx()" function
581  */
582     void
583 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
584 {
585     rettv->vval.v_number = -1;
586 #if defined(FEAT_GUI) \
587 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
588 	|| defined(MSWIN)
589 
590     {
591 	int	    x, y;
592 
593 	if (ui_get_winpos(&x, &y, 100) == OK)
594 	    rettv->vval.v_number = x;
595     }
596 #endif
597 }
598 
599 /*
600  * "getwinposy()" function
601  */
602     void
603 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
604 {
605     rettv->vval.v_number = -1;
606 #if defined(FEAT_GUI) \
607 	|| (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
608 	|| defined(MSWIN)
609     {
610 	int	    x, y;
611 
612 	if (ui_get_winpos(&x, &y, 100) == OK)
613 	    rettv->vval.v_number = y;
614     }
615 #endif
616 }
617 
618 /*
619  * "tabpagenr()" function
620  */
621     void
622 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
623 {
624     int		nr = 1;
625     char_u	*arg;
626 
627     if (argvars[0].v_type != VAR_UNKNOWN)
628     {
629 	arg = tv_get_string_chk(&argvars[0]);
630 	nr = 0;
631 	if (arg != NULL)
632 	{
633 	    if (STRCMP(arg, "$") == 0)
634 		nr = tabpage_index(NULL) - 1;
635 	    else if (STRCMP(arg, "#") == 0)
636 		nr = valid_tabpage(lastused_tabpage) ?
637 					tabpage_index(lastused_tabpage) : 0;
638 	    else
639 		semsg(_(e_invexpr2), arg);
640 	}
641     }
642     else
643 	nr = tabpage_index(curtab);
644     rettv->vval.v_number = nr;
645 }
646 
647 /*
648  * "tabpagewinnr()" function
649  */
650     void
651 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
652 {
653     int		nr = 1;
654     tabpage_T	*tp;
655 
656     tp = find_tabpage((int)tv_get_number(&argvars[0]));
657     if (tp == NULL)
658 	nr = 0;
659     else
660 	nr = get_winnr(tp, &argvars[1]);
661     rettv->vval.v_number = nr;
662 }
663 
664 /*
665  * "win_execute()" function
666  */
667     void
668 f_win_execute(typval_T *argvars, typval_T *rettv)
669 {
670     int		id = (int)tv_get_number(argvars);
671     tabpage_T	*tp;
672     win_T	*wp = win_id2wp_tp(id, &tp);
673     win_T	*save_curwin;
674     tabpage_T	*save_curtab;
675 
676     if (wp != NULL && tp != NULL)
677     {
678 	pos_T	curpos = wp->w_cursor;
679 
680 	if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
681 	{
682 	    check_cursor();
683 	    execute_common(argvars, rettv, 1);
684 	}
685 	restore_win_noblock(save_curwin, save_curtab, TRUE);
686 
687 	// Update the status line if the cursor moved.
688 	if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
689 	    wp->w_redr_status = TRUE;
690     }
691 }
692 
693 /*
694  * "win_findbuf()" function
695  */
696     void
697 f_win_findbuf(typval_T *argvars, typval_T *rettv)
698 {
699     if (rettv_list_alloc(rettv) != FAIL)
700 	win_findbuf(argvars, rettv->vval.v_list);
701 }
702 
703 /*
704  * "win_getid()" function
705  */
706     void
707 f_win_getid(typval_T *argvars, typval_T *rettv)
708 {
709     rettv->vval.v_number = win_getid(argvars);
710 }
711 
712 /*
713  * "win_gotoid()" function
714  */
715     void
716 f_win_gotoid(typval_T *argvars, typval_T *rettv)
717 {
718     win_T	*wp;
719     tabpage_T   *tp;
720     int		id = tv_get_number(&argvars[0]);
721 
722 #ifdef FEAT_CMDWIN
723     if (cmdwin_type != 0)
724     {
725 	emsg(_(e_cmdwin));
726 	return;
727     }
728 #endif
729     FOR_ALL_TAB_WINDOWS(tp, wp)
730 	if (wp->w_id == id)
731 	{
732 	    goto_tabpage_win(tp, wp);
733 	    rettv->vval.v_number = 1;
734 	    return;
735 	}
736 }
737 
738 /*
739  * "win_id2tabwin()" function
740  */
741     void
742 f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
743 {
744     if (rettv_list_alloc(rettv) != FAIL)
745 	win_id2tabwin(argvars, rettv->vval.v_list);
746 }
747 
748 /*
749  * "win_id2win()" function
750  */
751     void
752 f_win_id2win(typval_T *argvars, typval_T *rettv)
753 {
754     rettv->vval.v_number = win_id2win(argvars);
755 }
756 
757 /*
758  * "win_screenpos()" function
759  */
760     void
761 f_win_screenpos(typval_T *argvars, typval_T *rettv)
762 {
763     win_T	*wp;
764 
765     if (rettv_list_alloc(rettv) == FAIL)
766 	return;
767 
768     wp = find_win_by_nr_or_id(&argvars[0]);
769     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
770     list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
771 }
772 
773 /*
774  * Move the window wp into a new split of targetwin in a given direction
775  */
776     static void
777 win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
778 {
779     int	    dir;
780     int	    height = wp->w_height;
781     win_T   *oldwin = curwin;
782 
783     if (wp == targetwin)
784 	return;
785 
786     // Jump to the target window
787     if (curwin != targetwin)
788 	win_goto(targetwin);
789 
790     // Remove the old window and frame from the tree of frames
791     (void)winframe_remove(wp, &dir, NULL);
792     win_remove(wp, NULL);
793     last_status(FALSE);	    // may need to remove last status line
794     (void)win_comp_pos();   // recompute window positions
795 
796     // Split a window on the desired side and put the old window there
797     (void)win_split_ins(size, flags, wp, dir);
798 
799     // If splitting horizontally, try to preserve height
800     if (size == 0 && !(flags & WSP_VERT))
801     {
802 	win_setheight_win(height, wp);
803 	if (p_ea)
804 	    win_equal(wp, TRUE, 'v');
805     }
806 
807 #if defined(FEAT_GUI)
808     // When 'guioptions' includes 'L' or 'R' may have to remove or add
809     // scrollbars.  Have to update them anyway.
810     gui_may_update_scrollbars();
811 #endif
812 
813     if (oldwin != curwin)
814 	win_goto(oldwin);
815 }
816 
817 /*
818  * "win_splitmove()" function
819  */
820     void
821 f_win_splitmove(typval_T *argvars, typval_T *rettv)
822 {
823     win_T   *wp;
824     win_T   *targetwin;
825     int     flags = 0, size = 0;
826 
827     wp = find_win_by_nr_or_id(&argvars[0]);
828     targetwin = find_win_by_nr_or_id(&argvars[1]);
829 
830     if (wp == NULL || targetwin == NULL || wp == targetwin
831 	    || !win_valid(wp) || !win_valid(targetwin)
832 	    || win_valid_popup(wp) || win_valid_popup(targetwin))
833     {
834         emsg(_(e_invalwindow));
835 	rettv->vval.v_number = -1;
836 	return;
837     }
838 
839     if (argvars[2].v_type != VAR_UNKNOWN)
840     {
841         dict_T      *d;
842         dictitem_T  *di;
843 
844         if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL)
845         {
846             emsg(_(e_invarg));
847             return;
848         }
849 
850         d = argvars[2].vval.v_dict;
851         if (dict_get_bool(d, (char_u *)"vertical", FALSE))
852             flags |= WSP_VERT;
853         if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
854             flags |= tv_get_bool(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
855         size = (int)dict_get_number(d, (char_u *)"size");
856     }
857 
858     win_move_into_split(wp, targetwin, size, flags);
859 }
860 
861 /*
862  * "win_gettype(nr)" function
863  */
864     void
865 f_win_gettype(typval_T *argvars, typval_T *rettv)
866 {
867     win_T	*wp = curwin;
868 
869     rettv->v_type = VAR_STRING;
870     rettv->vval.v_string = NULL;
871     if (argvars[0].v_type != VAR_UNKNOWN)
872     {
873 	wp = find_win_by_nr_or_id(&argvars[0]);
874 	if (wp == NULL)
875 	{
876 	    rettv->vval.v_string = vim_strsave((char_u *)"unknown");
877 	    return;
878 	}
879     }
880     if (wp == aucmd_win)
881 	rettv->vval.v_string = vim_strsave((char_u *)"autocmd");
882 #if defined(FEAT_QUICKFIX)
883     else if (wp->w_p_pvw)
884 	rettv->vval.v_string = vim_strsave((char_u *)"preview");
885 #endif
886 #ifdef FEAT_PROP_POPUP
887     else if (WIN_IS_POPUP(wp))
888 	rettv->vval.v_string = vim_strsave((char_u *)"popup");
889 #endif
890 #ifdef FEAT_CMDWIN
891     else if (wp == curwin && cmdwin_type != 0)
892 	rettv->vval.v_string = vim_strsave((char_u *)"command");
893 #endif
894 }
895 
896 /*
897  * "getcmdwintype()" function
898  */
899     void
900 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
901 {
902     rettv->v_type = VAR_STRING;
903     rettv->vval.v_string = NULL;
904 #ifdef FEAT_CMDWIN
905     rettv->vval.v_string = alloc(2);
906     if (rettv->vval.v_string != NULL)
907     {
908 	rettv->vval.v_string[0] = cmdwin_type;
909 	rettv->vval.v_string[1] = NUL;
910     }
911 #endif
912 }
913 
914 /*
915  * "winbufnr(nr)" function
916  */
917     void
918 f_winbufnr(typval_T *argvars, typval_T *rettv)
919 {
920     win_T	*wp;
921 
922     wp = find_win_by_nr_or_id(&argvars[0]);
923     if (wp == NULL)
924 	rettv->vval.v_number = -1;
925     else
926 	rettv->vval.v_number = wp->w_buffer->b_fnum;
927 }
928 
929 /*
930  * "wincol()" function
931  */
932     void
933 f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
934 {
935     validate_cursor();
936     rettv->vval.v_number = curwin->w_wcol + 1;
937 }
938 
939 /*
940  * "winheight(nr)" function
941  */
942     void
943 f_winheight(typval_T *argvars, typval_T *rettv)
944 {
945     win_T	*wp;
946 
947     wp = find_win_by_nr_or_id(&argvars[0]);
948     if (wp == NULL)
949 	rettv->vval.v_number = -1;
950     else
951 	rettv->vval.v_number = wp->w_height;
952 }
953 
954 /*
955  * "winlayout()" function
956  */
957     void
958 f_winlayout(typval_T *argvars, typval_T *rettv)
959 {
960     tabpage_T	*tp;
961 
962     if (rettv_list_alloc(rettv) != OK)
963 	return;
964 
965     if (argvars[0].v_type == VAR_UNKNOWN)
966 	tp = curtab;
967     else
968     {
969 	tp = find_tabpage((int)tv_get_number(&argvars[0]));
970 	if (tp == NULL)
971 	    return;
972     }
973 
974     get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
975 }
976 
977 /*
978  * "winline()" function
979  */
980     void
981 f_winline(typval_T *argvars UNUSED, typval_T *rettv)
982 {
983     validate_cursor();
984     rettv->vval.v_number = curwin->w_wrow + 1;
985 }
986 
987 /*
988  * "winnr()" function
989  */
990     void
991 f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
992 {
993     int		nr = 1;
994 
995     nr = get_winnr(curtab, &argvars[0]);
996     rettv->vval.v_number = nr;
997 }
998 
999 /*
1000  * "winrestcmd()" function
1001  */
1002     void
1003 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
1004 {
1005     win_T	*wp;
1006     int		winnr = 1;
1007     garray_T	ga;
1008     char_u	buf[50];
1009 
1010     ga_init2(&ga, (int)sizeof(char), 70);
1011     FOR_ALL_WINDOWS(wp)
1012     {
1013 	sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
1014 	ga_concat(&ga, buf);
1015 	sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
1016 	ga_concat(&ga, buf);
1017 	++winnr;
1018     }
1019     ga_append(&ga, NUL);
1020 
1021     rettv->vval.v_string = ga.ga_data;
1022     rettv->v_type = VAR_STRING;
1023 }
1024 
1025 /*
1026  * "winrestview()" function
1027  */
1028     void
1029 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
1030 {
1031     dict_T	*dict;
1032 
1033     if (argvars[0].v_type != VAR_DICT
1034 	    || (dict = argvars[0].vval.v_dict) == NULL)
1035 	emsg(_(e_invarg));
1036     else
1037     {
1038 	if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
1039 	    curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
1040 	if (dict_find(dict, (char_u *)"col", -1) != NULL)
1041 	    curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
1042 	if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
1043 	    curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
1044 	if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
1045 	{
1046 	    curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
1047 	    curwin->w_set_curswant = FALSE;
1048 	}
1049 
1050 	if (dict_find(dict, (char_u *)"topline", -1) != NULL)
1051 	    set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
1052 #ifdef FEAT_DIFF
1053 	if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
1054 	    curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
1055 #endif
1056 	if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
1057 	    curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
1058 	if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
1059 	    curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
1060 
1061 	check_cursor();
1062 	win_new_height(curwin, curwin->w_height);
1063 	win_new_width(curwin, curwin->w_width);
1064 	changed_window_setting();
1065 
1066 	if (curwin->w_topline <= 0)
1067 	    curwin->w_topline = 1;
1068 	if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1069 	    curwin->w_topline = curbuf->b_ml.ml_line_count;
1070 #ifdef FEAT_DIFF
1071 	check_topfill(curwin, TRUE);
1072 #endif
1073     }
1074 }
1075 
1076 /*
1077  * "winsaveview()" function
1078  */
1079     void
1080 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1081 {
1082     dict_T	*dict;
1083 
1084     if (rettv_dict_alloc(rettv) == FAIL)
1085 	return;
1086     dict = rettv->vval.v_dict;
1087 
1088     dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1089     dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1090     dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1091     update_curswant();
1092     dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1093 
1094     dict_add_number(dict, "topline", (long)curwin->w_topline);
1095 #ifdef FEAT_DIFF
1096     dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1097 #endif
1098     dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1099     dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1100 }
1101 
1102 /*
1103  * "winwidth(nr)" function
1104  */
1105     void
1106 f_winwidth(typval_T *argvars, typval_T *rettv)
1107 {
1108     win_T	*wp;
1109 
1110     wp = find_win_by_nr_or_id(&argvars[0]);
1111     if (wp == NULL)
1112 	rettv->vval.v_number = -1;
1113     else
1114 	rettv->vval.v_number = wp->w_width;
1115 }
1116 #endif // FEAT_EVAL
1117 
1118 #if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1119 	|| defined(PROTO)
1120 /*
1121  * Set "win" to be the curwin and "tp" to be the current tab page.
1122  * restore_win() MUST be called to undo, also when FAIL is returned.
1123  * No autocommands will be executed until restore_win() is called.
1124  * When "no_display" is TRUE the display won't be affected, no redraw is
1125  * triggered, another tabpage access is limited.
1126  * Returns FAIL if switching to "win" failed.
1127  */
1128     int
1129 switch_win(
1130     win_T	**save_curwin,
1131     tabpage_T	**save_curtab,
1132     win_T	*win,
1133     tabpage_T	*tp,
1134     int		no_display)
1135 {
1136     block_autocmds();
1137     return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
1138 }
1139 
1140 /*
1141  * As switch_win() but without blocking autocommands.
1142  */
1143     int
1144 switch_win_noblock(
1145     win_T	**save_curwin,
1146     tabpage_T	**save_curtab,
1147     win_T	*win,
1148     tabpage_T	*tp,
1149     int		no_display)
1150 {
1151     *save_curwin = curwin;
1152     if (tp != NULL)
1153     {
1154 	*save_curtab = curtab;
1155 	if (no_display)
1156 	{
1157 	    curtab->tp_firstwin = firstwin;
1158 	    curtab->tp_lastwin = lastwin;
1159 	    curtab = tp;
1160 	    firstwin = curtab->tp_firstwin;
1161 	    lastwin = curtab->tp_lastwin;
1162 	}
1163 	else
1164 	    goto_tabpage_tp(tp, FALSE, FALSE);
1165     }
1166     if (!win_valid(win))
1167 	return FAIL;
1168     curwin = win;
1169     curbuf = curwin->w_buffer;
1170     return OK;
1171 }
1172 
1173 /*
1174  * Restore current tabpage and window saved by switch_win(), if still valid.
1175  * When "no_display" is TRUE the display won't be affected, no redraw is
1176  * triggered.
1177  */
1178     void
1179 restore_win(
1180     win_T	*save_curwin,
1181     tabpage_T	*save_curtab,
1182     int		no_display)
1183 {
1184     restore_win_noblock(save_curwin, save_curtab, no_display);
1185     unblock_autocmds();
1186 }
1187 
1188 /*
1189  * As restore_win() but without unblocking autocommands.
1190  */
1191     void
1192 restore_win_noblock(
1193     win_T	*save_curwin,
1194     tabpage_T	*save_curtab,
1195     int		no_display)
1196 {
1197     if (save_curtab != NULL && valid_tabpage(save_curtab))
1198     {
1199 	if (no_display)
1200 	{
1201 	    curtab->tp_firstwin = firstwin;
1202 	    curtab->tp_lastwin = lastwin;
1203 	    curtab = save_curtab;
1204 	    firstwin = curtab->tp_firstwin;
1205 	    lastwin = curtab->tp_lastwin;
1206 	}
1207 	else
1208 	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
1209     }
1210     if (win_valid(save_curwin))
1211     {
1212 	curwin = save_curwin;
1213 	curbuf = curwin->w_buffer;
1214     }
1215 # ifdef FEAT_PROP_POPUP
1216     else if (WIN_IS_POPUP(curwin))
1217 	// original window was closed and now we're in a popup window: Go
1218 	// to the first valid window.
1219 	win_goto(firstwin);
1220 # endif
1221 }
1222 #endif
1223