blob: 76916936dce272142ce8ee1fcb3aabdd0bd04650 [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
Bram Moolenaar261f3462019-09-07 15:45:32 +020053 static void
54win_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 *
85win_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 *
94win_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
129win_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
145win_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 *
160find_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 *
204find_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 *
218find_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
263get_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
313get_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 *
388get_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 *
430get_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
461f_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
496f_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
538f_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
566f_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
586f_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
605f_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
631f_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
648f_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 {
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200658 pos_T curpos = wp->w_cursor;
659
Bram Moolenaar261f3462019-09-07 15:45:32 +0200660 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);
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200666
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;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200670 }
671}
672
673/*
674 * "win_findbuf()" function
675 */
676 void
677f_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
687f_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
696f_win_gotoid(typval_T *argvars, typval_T *rettv)
697{
Bram Moolenaara046b372019-09-15 17:26:07 +0200698 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 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200716}
717
718/*
719 * "win_id2tabwin()" function
720 */
721 void
722f_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
732f_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
741f_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/*
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200754 * Move the window wp into a new split of targetwin in a given direction
755 */
756 static void
757win_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
801f_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/*
Bram Moolenaar261f3462019-09-07 15:45:32 +0200840 * "winbufnr(nr)" function
841 */
842 void
843f_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
858f_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
868f_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
883f_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
906f_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
916f_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
928f_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
954f_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
1005f_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
1031f_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
1054switch_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
1069switch_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
1104restore_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
1117restore_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