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