blob: d47680c7592830918d8c2891179118020e4c0766 [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 }
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100106#ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +0200107 // popup windows are in separate lists
108 FOR_ALL_TABPAGES(tp)
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200109 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200110 if (wp->w_id == id)
111 {
112 if (tpp != NULL)
113 *tpp = tp;
114 return wp;
115 }
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200116 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200117 if (wp->w_id == id)
118 {
119 if (tpp != NULL)
Bram Moolenaar1f42f5a2020-09-03 18:52:24 +0200120 *tpp = curtab; // any tabpage would do
Bram Moolenaar261f3462019-09-07 15:45:32 +0200121 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 {
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100184#ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +0200185 // check tab-local popup windows
Bram Moolenaaree93b732020-01-14 19:05:39 +0100186 for (wp = (tp == NULL ? curtab : tp)->tp_first_popupwin;
187 wp != NULL; wp = wp->w_next)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200188 if (wp->w_id == nr)
189 return wp;
190 // check global popup windows
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200191 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200192 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.
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100203 * Returns NULL when not found.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200204 */
205 win_T *
206find_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 *
220find_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
265get_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
315get_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;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200335 }
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 }
Bram Moolenaar631ebc42020-02-03 22:15:26 +0100361 if (twin == NULL)
362 nr = 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200363
364 if (invalid_arg)
365 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200366 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200367 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 *
390get_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 *
432get_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 {
Bram Moolenaar00d253e2020-04-06 22:13:01 +0200447 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200448 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
462f_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
497f_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 }
Bram Moolenaar99ca9c42020-09-22 21:55:41 +0200533#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
Bram Moolenaar261f3462019-09-07 15:45:32 +0200549}
550
551/*
552 * "getwinpos({timeout})" function
553 */
554 void
555f_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
583f_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
603f_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
622f_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;
Bram Moolenaar62a23252020-08-09 14:04:42 +0200635 else if (STRCMP(arg, "#") == 0)
636 nr = valid_tabpage(lastused_tabpage) ?
637 tabpage_index(lastused_tabpage) : 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200638 else
Bram Moolenaar108010a2021-06-27 22:03:33 +0200639 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200640 }
641 }
642 else
643 nr = tabpage_index(curtab);
644 rettv->vval.v_number = nr;
645}
646
647/*
648 * "tabpagewinnr()" function
649 */
650 void
651f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
652{
653 int nr = 1;
654 tabpage_T *tp;
655
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200656 if (in_vim9script()
657 && (check_for_number_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200658 || check_for_opt_string_arg(argvars, 1) == FAIL))
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200659 return;
660
Bram Moolenaar261f3462019-09-07 15:45:32 +0200661 tp = find_tabpage((int)tv_get_number(&argvars[0]));
662 if (tp == NULL)
663 nr = 0;
664 else
665 nr = get_winnr(tp, &argvars[1]);
666 rettv->vval.v_number = nr;
667}
668
669/*
670 * "win_execute()" function
671 */
672 void
673f_win_execute(typval_T *argvars, typval_T *rettv)
674{
675 int id = (int)tv_get_number(argvars);
676 tabpage_T *tp;
677 win_T *wp = win_id2wp_tp(id, &tp);
678 win_T *save_curwin;
679 tabpage_T *save_curtab;
680
Bram Moolenaar37487e12021-01-12 22:08:53 +0100681 // Return an empty string if something fails.
682 rettv->v_type = VAR_STRING;
683 rettv->vval.v_string = NULL;
684
Bram Moolenaar261f3462019-09-07 15:45:32 +0200685 if (wp != NULL && tp != NULL)
686 {
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200687 pos_T curpos = wp->w_cursor;
688
Bram Moolenaar261f3462019-09-07 15:45:32 +0200689 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
690 {
691 check_cursor();
692 execute_common(argvars, rettv, 1);
693 }
694 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200695
696 // Update the status line if the cursor moved.
697 if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
698 wp->w_redr_status = TRUE;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200699 }
700}
701
702/*
703 * "win_findbuf()" function
704 */
705 void
706f_win_findbuf(typval_T *argvars, typval_T *rettv)
707{
708 if (rettv_list_alloc(rettv) != FAIL)
709 win_findbuf(argvars, rettv->vval.v_list);
710}
711
712/*
713 * "win_getid()" function
714 */
715 void
716f_win_getid(typval_T *argvars, typval_T *rettv)
717{
718 rettv->vval.v_number = win_getid(argvars);
719}
720
721/*
722 * "win_gotoid()" function
723 */
724 void
725f_win_gotoid(typval_T *argvars, typval_T *rettv)
726{
Bram Moolenaara046b372019-09-15 17:26:07 +0200727 win_T *wp;
728 tabpage_T *tp;
729 int id = tv_get_number(&argvars[0]);
730
731#ifdef FEAT_CMDWIN
732 if (cmdwin_type != 0)
733 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200734 emsg(_(e_invalid_in_cmdline_window));
Bram Moolenaara046b372019-09-15 17:26:07 +0200735 return;
736 }
737#endif
738 FOR_ALL_TAB_WINDOWS(tp, wp)
739 if (wp->w_id == id)
740 {
741 goto_tabpage_win(tp, wp);
742 rettv->vval.v_number = 1;
743 return;
744 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200745}
746
747/*
748 * "win_id2tabwin()" function
749 */
750 void
751f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
752{
753 if (rettv_list_alloc(rettv) != FAIL)
754 win_id2tabwin(argvars, rettv->vval.v_list);
755}
756
757/*
758 * "win_id2win()" function
759 */
760 void
761f_win_id2win(typval_T *argvars, typval_T *rettv)
762{
763 rettv->vval.v_number = win_id2win(argvars);
764}
765
766/*
767 * "win_screenpos()" function
768 */
769 void
770f_win_screenpos(typval_T *argvars, typval_T *rettv)
771{
772 win_T *wp;
773
774 if (rettv_list_alloc(rettv) == FAIL)
775 return;
776
777 wp = find_win_by_nr_or_id(&argvars[0]);
778 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
779 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
780}
781
782/*
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200783 * Move the window wp into a new split of targetwin in a given direction
784 */
785 static void
786win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
787{
788 int dir;
789 int height = wp->w_height;
790 win_T *oldwin = curwin;
791
792 if (wp == targetwin)
793 return;
794
795 // Jump to the target window
796 if (curwin != targetwin)
797 win_goto(targetwin);
798
799 // Remove the old window and frame from the tree of frames
800 (void)winframe_remove(wp, &dir, NULL);
801 win_remove(wp, NULL);
802 last_status(FALSE); // may need to remove last status line
803 (void)win_comp_pos(); // recompute window positions
804
805 // Split a window on the desired side and put the old window there
806 (void)win_split_ins(size, flags, wp, dir);
807
808 // If splitting horizontally, try to preserve height
809 if (size == 0 && !(flags & WSP_VERT))
810 {
811 win_setheight_win(height, wp);
812 if (p_ea)
813 win_equal(wp, TRUE, 'v');
814 }
815
816#if defined(FEAT_GUI)
817 // When 'guioptions' includes 'L' or 'R' may have to remove or add
818 // scrollbars. Have to update them anyway.
819 gui_may_update_scrollbars();
820#endif
821
822 if (oldwin != curwin)
823 win_goto(oldwin);
824}
825
826/*
827 * "win_splitmove()" function
828 */
829 void
830f_win_splitmove(typval_T *argvars, typval_T *rettv)
831{
832 win_T *wp;
833 win_T *targetwin;
834 int flags = 0, size = 0;
835
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200836 if (in_vim9script()
837 && (check_for_number_arg(argvars, 0) == FAIL
838 || check_for_number_arg(argvars, 1) == FAIL
839 || check_for_opt_dict_arg(argvars, 2) == FAIL))
840 return;
841
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200842 wp = find_win_by_nr_or_id(&argvars[0]);
843 targetwin = find_win_by_nr_or_id(&argvars[1]);
844
Bram Moolenaar7b94e772020-01-06 21:03:24 +0100845 if (wp == NULL || targetwin == NULL || wp == targetwin
Bram Moolenaar0f1563f2020-03-20 21:15:51 +0100846 || !win_valid(wp) || !win_valid(targetwin)
847 || win_valid_popup(wp) || win_valid_popup(targetwin))
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200848 {
849 emsg(_(e_invalwindow));
850 rettv->vval.v_number = -1;
851 return;
852 }
853
854 if (argvars[2].v_type != VAR_UNKNOWN)
855 {
856 dict_T *d;
857 dictitem_T *di;
858
859 if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL)
860 {
861 emsg(_(e_invarg));
862 return;
863 }
864
865 d = argvars[2].vval.v_dict;
Bram Moolenaar4b9bd692020-09-05 21:57:53 +0200866 if (dict_get_bool(d, (char_u *)"vertical", FALSE))
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200867 flags |= WSP_VERT;
868 if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
Bram Moolenaar4b9bd692020-09-05 21:57:53 +0200869 flags |= tv_get_bool(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200870 size = (int)dict_get_number(d, (char_u *)"size");
871 }
872
873 win_move_into_split(wp, targetwin, size, flags);
874}
875
876/*
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +0100877 * "win_gettype(nr)" function
878 */
879 void
880f_win_gettype(typval_T *argvars, typval_T *rettv)
881{
882 win_T *wp = curwin;
883
884 rettv->v_type = VAR_STRING;
885 rettv->vval.v_string = NULL;
886 if (argvars[0].v_type != VAR_UNKNOWN)
887 {
888 wp = find_win_by_nr_or_id(&argvars[0]);
889 if (wp == NULL)
890 {
891 rettv->vval.v_string = vim_strsave((char_u *)"unknown");
892 return;
893 }
894 }
Bram Moolenaar0fe937f2020-06-16 22:42:04 +0200895 if (wp == aucmd_win)
Bram Moolenaar40a019f2020-06-17 21:41:35 +0200896 rettv->vval.v_string = vim_strsave((char_u *)"autocmd");
Bram Moolenaar0fe937f2020-06-16 22:42:04 +0200897#if defined(FEAT_QUICKFIX)
898 else if (wp->w_p_pvw)
899 rettv->vval.v_string = vim_strsave((char_u *)"preview");
900#endif
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +0100901#ifdef FEAT_PROP_POPUP
Bram Moolenaar0fe937f2020-06-16 22:42:04 +0200902 else if (WIN_IS_POPUP(wp))
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +0100903 rettv->vval.v_string = vim_strsave((char_u *)"popup");
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +0100904#endif
905#ifdef FEAT_CMDWIN
Bram Moolenaar0fe937f2020-06-16 22:42:04 +0200906 else if (wp == curwin && cmdwin_type != 0)
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +0100907 rettv->vval.v_string = vim_strsave((char_u *)"command");
908#endif
909}
910
911/*
912 * "getcmdwintype()" function
913 */
914 void
915f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
916{
917 rettv->v_type = VAR_STRING;
918 rettv->vval.v_string = NULL;
919#ifdef FEAT_CMDWIN
920 rettv->vval.v_string = alloc(2);
921 if (rettv->vval.v_string != NULL)
922 {
923 rettv->vval.v_string[0] = cmdwin_type;
924 rettv->vval.v_string[1] = NUL;
925 }
926#endif
927}
928
929/*
Bram Moolenaar261f3462019-09-07 15:45:32 +0200930 * "winbufnr(nr)" function
931 */
932 void
933f_winbufnr(typval_T *argvars, typval_T *rettv)
934{
935 win_T *wp;
936
937 wp = find_win_by_nr_or_id(&argvars[0]);
938 if (wp == NULL)
939 rettv->vval.v_number = -1;
940 else
941 rettv->vval.v_number = wp->w_buffer->b_fnum;
942}
943
944/*
945 * "wincol()" function
946 */
947 void
948f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
949{
950 validate_cursor();
951 rettv->vval.v_number = curwin->w_wcol + 1;
952}
953
954/*
955 * "winheight(nr)" function
956 */
957 void
958f_winheight(typval_T *argvars, typval_T *rettv)
959{
960 win_T *wp;
961
962 wp = find_win_by_nr_or_id(&argvars[0]);
963 if (wp == NULL)
964 rettv->vval.v_number = -1;
965 else
966 rettv->vval.v_number = wp->w_height;
967}
968
969/*
970 * "winlayout()" function
971 */
972 void
973f_winlayout(typval_T *argvars, typval_T *rettv)
974{
975 tabpage_T *tp;
976
977 if (rettv_list_alloc(rettv) != OK)
978 return;
979
980 if (argvars[0].v_type == VAR_UNKNOWN)
981 tp = curtab;
982 else
983 {
984 tp = find_tabpage((int)tv_get_number(&argvars[0]));
985 if (tp == NULL)
986 return;
987 }
988
989 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
990}
991
992/*
993 * "winline()" function
994 */
995 void
996f_winline(typval_T *argvars UNUSED, typval_T *rettv)
997{
998 validate_cursor();
999 rettv->vval.v_number = curwin->w_wrow + 1;
1000}
1001
1002/*
1003 * "winnr()" function
1004 */
1005 void
1006f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
1007{
1008 int nr = 1;
1009
1010 nr = get_winnr(curtab, &argvars[0]);
1011 rettv->vval.v_number = nr;
1012}
1013
1014/*
1015 * "winrestcmd()" function
1016 */
1017 void
1018f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
1019{
1020 win_T *wp;
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001021 int i;
1022 int winnr;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001023 garray_T ga;
1024 char_u buf[50];
1025
1026 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001027
1028 // Do this twice to handle some window layouts properly.
1029 for (i = 0; i < 2; ++i)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001030 {
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001031 winnr = 1;
1032 FOR_ALL_WINDOWS(wp)
1033 {
1034 sprintf((char *)buf, ":%dresize %d|", winnr, wp->w_height);
1035 ga_concat(&ga, buf);
1036 sprintf((char *)buf, "vert :%dresize %d|", winnr, wp->w_width);
1037 ga_concat(&ga, buf);
1038 ++winnr;
1039 }
Bram Moolenaar261f3462019-09-07 15:45:32 +02001040 }
1041 ga_append(&ga, NUL);
1042
1043 rettv->vval.v_string = ga.ga_data;
1044 rettv->v_type = VAR_STRING;
1045}
1046
1047/*
1048 * "winrestview()" function
1049 */
1050 void
1051f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
1052{
1053 dict_T *dict;
1054
1055 if (argvars[0].v_type != VAR_DICT
1056 || (dict = argvars[0].vval.v_dict) == NULL)
1057 emsg(_(e_invarg));
1058 else
1059 {
1060 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
1061 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
1062 if (dict_find(dict, (char_u *)"col", -1) != NULL)
1063 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
1064 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
1065 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
1066 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
1067 {
1068 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
1069 curwin->w_set_curswant = FALSE;
1070 }
1071
1072 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
1073 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
1074#ifdef FEAT_DIFF
1075 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
1076 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
1077#endif
1078 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
1079 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
1080 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
1081 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
1082
1083 check_cursor();
1084 win_new_height(curwin, curwin->w_height);
1085 win_new_width(curwin, curwin->w_width);
1086 changed_window_setting();
1087
1088 if (curwin->w_topline <= 0)
1089 curwin->w_topline = 1;
1090 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1091 curwin->w_topline = curbuf->b_ml.ml_line_count;
1092#ifdef FEAT_DIFF
1093 check_topfill(curwin, TRUE);
1094#endif
1095 }
1096}
1097
1098/*
1099 * "winsaveview()" function
1100 */
1101 void
1102f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1103{
1104 dict_T *dict;
1105
1106 if (rettv_dict_alloc(rettv) == FAIL)
1107 return;
1108 dict = rettv->vval.v_dict;
1109
1110 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1111 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1112 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1113 update_curswant();
1114 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1115
1116 dict_add_number(dict, "topline", (long)curwin->w_topline);
1117#ifdef FEAT_DIFF
1118 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1119#endif
1120 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1121 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1122}
1123
1124/*
1125 * "winwidth(nr)" function
1126 */
1127 void
1128f_winwidth(typval_T *argvars, typval_T *rettv)
1129{
1130 win_T *wp;
1131
1132 wp = find_win_by_nr_or_id(&argvars[0]);
1133 if (wp == NULL)
1134 rettv->vval.v_number = -1;
1135 else
1136 rettv->vval.v_number = wp->w_width;
1137}
1138#endif // FEAT_EVAL
1139
1140#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1141 || defined(PROTO)
1142/*
1143 * Set "win" to be the curwin and "tp" to be the current tab page.
1144 * restore_win() MUST be called to undo, also when FAIL is returned.
1145 * No autocommands will be executed until restore_win() is called.
1146 * When "no_display" is TRUE the display won't be affected, no redraw is
1147 * triggered, another tabpage access is limited.
1148 * Returns FAIL if switching to "win" failed.
1149 */
1150 int
1151switch_win(
1152 win_T **save_curwin,
1153 tabpage_T **save_curtab,
1154 win_T *win,
1155 tabpage_T *tp,
1156 int no_display)
1157{
1158 block_autocmds();
1159 return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
1160}
1161
1162/*
1163 * As switch_win() but without blocking autocommands.
1164 */
1165 int
1166switch_win_noblock(
1167 win_T **save_curwin,
1168 tabpage_T **save_curtab,
1169 win_T *win,
1170 tabpage_T *tp,
1171 int no_display)
1172{
1173 *save_curwin = curwin;
1174 if (tp != NULL)
1175 {
1176 *save_curtab = curtab;
1177 if (no_display)
1178 {
1179 curtab->tp_firstwin = firstwin;
1180 curtab->tp_lastwin = lastwin;
1181 curtab = tp;
1182 firstwin = curtab->tp_firstwin;
1183 lastwin = curtab->tp_lastwin;
1184 }
1185 else
1186 goto_tabpage_tp(tp, FALSE, FALSE);
1187 }
1188 if (!win_valid(win))
1189 return FAIL;
1190 curwin = win;
1191 curbuf = curwin->w_buffer;
1192 return OK;
1193}
1194
1195/*
1196 * Restore current tabpage and window saved by switch_win(), if still valid.
1197 * When "no_display" is TRUE the display won't be affected, no redraw is
1198 * triggered.
1199 */
1200 void
1201restore_win(
1202 win_T *save_curwin,
1203 tabpage_T *save_curtab,
1204 int no_display)
1205{
1206 restore_win_noblock(save_curwin, save_curtab, no_display);
1207 unblock_autocmds();
1208}
1209
1210/*
1211 * As restore_win() but without unblocking autocommands.
1212 */
1213 void
1214restore_win_noblock(
1215 win_T *save_curwin,
1216 tabpage_T *save_curtab,
1217 int no_display)
1218{
1219 if (save_curtab != NULL && valid_tabpage(save_curtab))
1220 {
1221 if (no_display)
1222 {
1223 curtab->tp_firstwin = firstwin;
1224 curtab->tp_lastwin = lastwin;
1225 curtab = save_curtab;
1226 firstwin = curtab->tp_firstwin;
1227 lastwin = curtab->tp_lastwin;
1228 }
1229 else
1230 goto_tabpage_tp(save_curtab, FALSE, FALSE);
1231 }
1232 if (win_valid(save_curwin))
1233 {
1234 curwin = save_curwin;
1235 curbuf = curwin->w_buffer;
1236 }
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01001237# ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +02001238 else if (WIN_IS_POPUP(curwin))
1239 // original window was closed and now we're in a popup window: Go
1240 // to the first valid window.
1241 win_goto(firstwin);
1242# endif
1243}
1244#endif