blob: bc5925182ea0a7b3a4f271d0d856cf80883c3f5a [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".
Bram Moolenaar6ed545e2022-05-09 20:09:23 +0100158 * Returns current window if "vp" is number zero.
159 * Returns NULL if not found.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200160 */
161 win_T *
162find_win_by_nr(
163 typval_T *vp,
164 tabpage_T *tp) // NULL for current tab page
165{
166 win_T *wp;
167 int nr = (int)tv_get_number_chk(vp, NULL);
168
169 if (nr < 0)
170 return NULL;
171 if (nr == 0)
172 return curwin;
173
174 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
175 {
176 if (nr >= LOWEST_WIN_ID)
177 {
178 if (wp->w_id == nr)
179 return wp;
180 }
181 else if (--nr <= 0)
182 break;
183 }
184 if (nr >= LOWEST_WIN_ID)
185 {
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100186#ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +0200187 // check tab-local popup windows
Bram Moolenaaree93b732020-01-14 19:05:39 +0100188 for (wp = (tp == NULL ? curtab : tp)->tp_first_popupwin;
189 wp != NULL; wp = wp->w_next)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200190 if (wp->w_id == nr)
191 return wp;
192 // check global popup windows
Bram Moolenaaraeea7212020-04-02 18:50:46 +0200193 FOR_ALL_POPUPWINS(wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200194 if (wp->w_id == nr)
195 return wp;
196#endif
197 return NULL;
198 }
199 return wp;
200}
201
202/*
203 * Find a window: When using a Window ID in any tab page, when using a number
204 * in the current tab page.
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100205 * Returns NULL when not found.
Bram Moolenaar261f3462019-09-07 15:45:32 +0200206 */
207 win_T *
208find_win_by_nr_or_id(typval_T *vp)
209{
210 int nr = (int)tv_get_number_chk(vp, NULL);
211
212 if (nr >= LOWEST_WIN_ID)
213 return win_id2wp(tv_get_number(vp));
214 return find_win_by_nr(vp, NULL);
215}
216
217/*
218 * Find window specified by "wvp" in tabpage "tvp".
219 * Returns the tab page in 'ptp'
220 */
221 win_T *
222find_tabwin(
223 typval_T *wvp, // VAR_UNKNOWN for current window
224 typval_T *tvp, // VAR_UNKNOWN for current tab page
225 tabpage_T **ptp)
226{
227 win_T *wp = NULL;
228 tabpage_T *tp = NULL;
229 long n;
230
231 if (wvp->v_type != VAR_UNKNOWN)
232 {
233 if (tvp->v_type != VAR_UNKNOWN)
234 {
235 n = (long)tv_get_number(tvp);
236 if (n >= 0)
237 tp = find_tabpage(n);
238 }
239 else
240 tp = curtab;
241
242 if (tp != NULL)
243 {
244 wp = find_win_by_nr(wvp, tp);
245 if (wp == NULL && wvp->v_type == VAR_NUMBER
246 && wvp->vval.v_number != -1)
247 // A window with the specified number is not found
248 tp = NULL;
249 }
250 }
251 else
252 {
253 wp = curwin;
254 tp = curtab;
255 }
256
257 if (ptp != NULL)
258 *ptp = tp;
259
260 return wp;
261}
262
263/*
Bram Moolenaar9ba61942022-08-31 11:25:06 +0100264 * Get the layout of the given tab page for winlayout() and add it to "l".
Bram Moolenaar261f3462019-09-07 15:45:32 +0200265 */
266 static void
267get_framelayout(frame_T *fr, list_T *l, int outer)
268{
269 frame_T *child;
270 list_T *fr_list;
271 list_T *win_list;
272
273 if (fr == NULL)
274 return;
275
276 if (outer)
277 // outermost call from f_winlayout()
278 fr_list = l;
279 else
280 {
281 fr_list = list_alloc();
282 if (fr_list == NULL)
283 return;
Bram Moolenaar9ba61942022-08-31 11:25:06 +0100284 if (list_append_list(l, fr_list) == FAIL)
285 {
286 vim_free(fr_list);
287 return;
288 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200289 }
290
291 if (fr->fr_layout == FR_LEAF)
292 {
293 if (fr->fr_win != NULL)
294 {
295 list_append_string(fr_list, (char_u *)"leaf", -1);
296 list_append_number(fr_list, fr->fr_win->w_id);
297 }
298 }
299 else
300 {
301 list_append_string(fr_list,
302 fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1);
303
304 win_list = list_alloc();
305 if (win_list == NULL)
306 return;
Bram Moolenaar9ba61942022-08-31 11:25:06 +0100307 if (list_append_list(fr_list, win_list) == FAIL)
308 {
309 vim_free(win_list);
310 return;
311 }
312
Bram Moolenaar261f3462019-09-07 15:45:32 +0200313 child = fr->fr_child;
314 while (child != NULL)
315 {
316 get_framelayout(child, win_list, FALSE);
317 child = child->fr_next;
318 }
319 }
320}
321
322/*
323 * Common code for tabpagewinnr() and winnr().
324 */
325 static int
326get_winnr(tabpage_T *tp, typval_T *argvar)
327{
328 win_T *twin;
329 int nr = 1;
330 win_T *wp;
331 char_u *arg;
332
333 twin = (tp == curtab) ? curwin : tp->tp_curwin;
334 if (argvar->v_type != VAR_UNKNOWN)
335 {
336 int invalid_arg = FALSE;
337
338 arg = tv_get_string_chk(argvar);
339 if (arg == NULL)
340 nr = 0; // type error; errmsg already given
341 else if (STRCMP(arg, "$") == 0)
342 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
343 else if (STRCMP(arg, "#") == 0)
344 {
345 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200346 }
347 else
348 {
349 long count;
350 char_u *endp;
351
352 // Extract the window count (if specified). e.g. winnr('3j')
353 count = strtol((char *)arg, (char **)&endp, 10);
354 if (count <= 0)
355 count = 1; // if count is not specified, default to 1
356 if (endp != NULL && *endp != '\0')
357 {
358 if (STRCMP(endp, "j") == 0)
359 twin = win_vert_neighbor(tp, twin, FALSE, count);
360 else if (STRCMP(endp, "k") == 0)
361 twin = win_vert_neighbor(tp, twin, TRUE, count);
362 else if (STRCMP(endp, "h") == 0)
363 twin = win_horz_neighbor(tp, twin, TRUE, count);
364 else if (STRCMP(endp, "l") == 0)
365 twin = win_horz_neighbor(tp, twin, FALSE, count);
366 else
367 invalid_arg = TRUE;
368 }
369 else
370 invalid_arg = TRUE;
371 }
Bram Moolenaar631ebc42020-02-03 22:15:26 +0100372 if (twin == NULL)
373 nr = 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200374
375 if (invalid_arg)
376 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200377 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200378 nr = 0;
379 }
380 }
381
382 if (nr > 0)
383 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
384 wp != twin; wp = wp->w_next)
385 {
386 if (wp == NULL)
387 {
388 // didn't find it in this tabpage
389 nr = 0;
390 break;
391 }
392 ++nr;
393 }
394 return nr;
395}
396
397/*
398 * Returns information about a window as a dictionary.
399 */
400 static dict_T *
401get_win_info(win_T *wp, short tpnr, short winnr)
402{
403 dict_T *dict;
404
405 dict = dict_alloc();
406 if (dict == NULL)
407 return NULL;
408
LemonBoy8530b412022-04-20 19:00:36 +0100409 // make sure w_botline is valid
410 validate_botline_win(wp);
411
Bram Moolenaar261f3462019-09-07 15:45:32 +0200412 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);
Bram Moolenaarcdf5fdb2021-11-20 11:14:24 +0000424 dict_add_number(dict, "textoff", win_col_off(wp));
Bram Moolenaar261f3462019-09-07 15:45:32 +0200425 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
426
427#ifdef FEAT_TERMINAL
428 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
429#endif
430#ifdef FEAT_QUICKFIX
431 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
432 dict_add_number(dict, "loclist",
433 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
434#endif
435
436 // Add a reference to window variables
437 dict_add_dict(dict, "variables", wp->w_vars);
438
439 return dict;
440}
441
442/*
443 * Returns information (variables, options, etc.) about a tab page
444 * as a dictionary.
445 */
446 static dict_T *
447get_tabpage_info(tabpage_T *tp, int tp_idx)
448{
449 win_T *wp;
450 dict_T *dict;
451 list_T *l;
452
453 dict = dict_alloc();
454 if (dict == NULL)
455 return NULL;
456
457 dict_add_number(dict, "tabnr", tp_idx);
458
459 l = list_alloc();
460 if (l != NULL)
461 {
Bram Moolenaar00d253e2020-04-06 22:13:01 +0200462 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200463 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
Bram Moolenaar93a10962022-06-16 11:42:09 +0100483 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200484 return;
485
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200486 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
487 return;
488
Bram Moolenaar261f3462019-09-07 15:45:32 +0200489 if (argvars[0].v_type != VAR_UNKNOWN)
490 {
491 // Information about one tab page
492 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
493 if (tparg == NULL)
494 return;
495 }
496
497 // Get information about a specific tab page or all tab pages
498 FOR_ALL_TABPAGES(tp)
499 {
500 tpnr++;
501 if (tparg != NULL && tp != tparg)
502 continue;
503 d = get_tabpage_info(tp, tpnr);
504 if (d != NULL)
505 list_append_dict(rettv->vval.v_list, d);
506 if (tparg != NULL)
507 return;
508 }
509}
510
511/*
512 * "getwininfo()" function
513 */
514 void
515f_getwininfo(typval_T *argvars, typval_T *rettv)
516{
517 tabpage_T *tp;
518 win_T *wp = NULL, *wparg = NULL;
519 dict_T *d;
520 short tabnr = 0, winnr;
521
Bram Moolenaar93a10962022-06-16 11:42:09 +0100522 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200523 return;
524
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200525 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
526 return;
527
Bram Moolenaar261f3462019-09-07 15:45:32 +0200528 if (argvars[0].v_type != VAR_UNKNOWN)
529 {
530 wparg = win_id2wp(tv_get_number(&argvars[0]));
531 if (wparg == NULL)
532 return;
533 }
534
535 // Collect information about either all the windows across all the tab
536 // pages or one particular window.
537 FOR_ALL_TABPAGES(tp)
538 {
539 tabnr++;
540 winnr = 0;
541 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
542 {
543 winnr++;
544 if (wparg != NULL && wp != wparg)
545 continue;
546 d = get_win_info(wp, tabnr, winnr);
547 if (d != NULL)
548 list_append_dict(rettv->vval.v_list, d);
549 if (wparg != NULL)
550 // found information about a specific window
551 return;
552 }
553 }
Bram Moolenaar99ca9c42020-09-22 21:55:41 +0200554#ifdef FEAT_PROP_POPUP
555 if (wparg != NULL)
556 {
557 tabnr = 0;
558 FOR_ALL_TABPAGES(tp)
559 {
560 tabnr++;
561 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
562 if (wp == wparg)
563 break;
564 }
565 d = get_win_info(wparg, tp == NULL ? 0 : tabnr, 0);
566 if (d != NULL)
567 list_append_dict(rettv->vval.v_list, d);
568 }
569#endif
Bram Moolenaar261f3462019-09-07 15:45:32 +0200570}
571
572/*
573 * "getwinpos({timeout})" function
574 */
575 void
576f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
577{
578 int x = -1;
579 int y = -1;
580
581 if (rettv_list_alloc(rettv) == FAIL)
582 return;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200583
584 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
585 return;
586
Bram Moolenaar261f3462019-09-07 15:45:32 +0200587#if defined(FEAT_GUI) \
588 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
589 || defined(MSWIN)
590 {
591 varnumber_T timeout = 100;
592
593 if (argvars[0].v_type != VAR_UNKNOWN)
594 timeout = tv_get_number(&argvars[0]);
595
596 (void)ui_get_winpos(&x, &y, timeout);
597 }
598#endif
599 list_append_number(rettv->vval.v_list, (varnumber_T)x);
600 list_append_number(rettv->vval.v_list, (varnumber_T)y);
601}
602
603
604/*
605 * "getwinposx()" function
606 */
607 void
608f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
609{
610 rettv->vval.v_number = -1;
611#if defined(FEAT_GUI) \
612 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
613 || defined(MSWIN)
614
615 {
616 int x, y;
617
618 if (ui_get_winpos(&x, &y, 100) == OK)
619 rettv->vval.v_number = x;
620 }
621#endif
622}
623
624/*
625 * "getwinposy()" function
626 */
627 void
628f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
629{
630 rettv->vval.v_number = -1;
631#if defined(FEAT_GUI) \
632 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
633 || defined(MSWIN)
634 {
635 int x, y;
636
637 if (ui_get_winpos(&x, &y, 100) == OK)
638 rettv->vval.v_number = y;
639 }
640#endif
641}
642
643/*
644 * "tabpagenr()" function
645 */
646 void
647f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
648{
649 int nr = 1;
650 char_u *arg;
651
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200652 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
653 return;
654
Bram Moolenaar261f3462019-09-07 15:45:32 +0200655 if (argvars[0].v_type != VAR_UNKNOWN)
656 {
657 arg = tv_get_string_chk(&argvars[0]);
658 nr = 0;
659 if (arg != NULL)
660 {
661 if (STRCMP(arg, "$") == 0)
662 nr = tabpage_index(NULL) - 1;
Bram Moolenaar62a23252020-08-09 14:04:42 +0200663 else if (STRCMP(arg, "#") == 0)
664 nr = valid_tabpage(lastused_tabpage) ?
665 tabpage_index(lastused_tabpage) : 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200666 else
Bram Moolenaar108010a2021-06-27 22:03:33 +0200667 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200668 }
669 }
670 else
671 nr = tabpage_index(curtab);
672 rettv->vval.v_number = nr;
673}
674
675/*
676 * "tabpagewinnr()" function
677 */
678 void
679f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
680{
681 int nr = 1;
682 tabpage_T *tp;
683
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200684 if (in_vim9script()
685 && (check_for_number_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200686 || check_for_opt_string_arg(argvars, 1) == FAIL))
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200687 return;
688
Bram Moolenaar261f3462019-09-07 15:45:32 +0200689 tp = find_tabpage((int)tv_get_number(&argvars[0]));
690 if (tp == NULL)
691 nr = 0;
692 else
693 nr = get_winnr(tp, &argvars[1]);
694 rettv->vval.v_number = nr;
695}
696
697/*
698 * "win_execute()" function
699 */
700 void
701f_win_execute(typval_T *argvars, typval_T *rettv)
702{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200703 int id;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200704 tabpage_T *tp;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200705 win_T *wp;
Bram Moolenaar18f47402022-01-06 13:24:51 +0000706 switchwin_T switchwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200707
Bram Moolenaar37487e12021-01-12 22:08:53 +0100708 // Return an empty string if something fails.
709 rettv->v_type = VAR_STRING;
710 rettv->vval.v_string = NULL;
711
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200712 if (in_vim9script()
713 && (check_for_number_arg(argvars, 0) == FAIL
714 || check_for_string_or_list_arg(argvars, 1) == FAIL
715 || check_for_opt_string_arg(argvars, 2) == FAIL))
716 return;
717
718 id = (int)tv_get_number(argvars);
719 wp = win_id2wp_tp(id, &tp);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200720 if (wp != NULL && tp != NULL)
721 {
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200722 pos_T curpos = wp->w_cursor;
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000723 char_u cwd[MAXPATHL];
Bram Moolenaard6f27c62022-01-11 12:37:20 +0000724 int cwd_status = FAIL;
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000725#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000726 char_u autocwd[MAXPATHL];
727 int apply_acd = FALSE;
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000728#endif
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000729
Bram Moolenaard6f27c62022-01-11 12:37:20 +0000730 // Getting and setting directory can be slow on some systems, only do
731 // this when the current or target window/tab have a local directory or
732 // 'acd' is set.
733 if (curwin != wp
734 && (curwin->w_localdir != NULL
735 || wp->w_localdir != NULL
736 || (curtab != tp
737 && (curtab->tp_localdir != NULL
738 || tp->tp_localdir != NULL))
739#ifdef FEAT_AUTOCHDIR
740 || p_acd
741#endif
742 ))
743 cwd_status = mch_dirname(cwd, MAXPATHL);
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000744
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000745#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000746 // If 'acd' is set, check we are using that directory. If yes, then
747 // apply 'acd' afterwards, otherwise restore the current directory.
748 if (cwd_status == OK && p_acd)
749 {
750 do_autochdir();
751 apply_acd = mch_dirname(autocwd, MAXPATHL) == OK
752 && STRCMP(cwd, autocwd) == 0;
753 }
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000754#endif
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200755
Bram Moolenaar18f47402022-01-06 13:24:51 +0000756 if (switch_win_noblock(&switchwin, wp, tp, TRUE) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200757 {
758 check_cursor();
759 execute_common(argvars, rettv, 1);
760 }
Bram Moolenaar18f47402022-01-06 13:24:51 +0000761 restore_win_noblock(&switchwin, TRUE);
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000762#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000763 if (apply_acd)
764 do_autochdir();
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000765 else
766#endif
767 if (cwd_status == OK)
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000768 mch_chdir((char *)cwd);
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200769
770 // Update the status line if the cursor moved.
771 if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
772 wp->w_redr_status = TRUE;
Bram Moolenaare664a322022-01-07 14:08:03 +0000773
774 // In case the command moved the cursor or changed the Visual area,
775 // check it is valid.
776 check_cursor();
777 if (VIsual_active)
778 check_pos(curbuf, &VIsual);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200779 }
780}
781
782/*
783 * "win_findbuf()" function
784 */
785 void
786f_win_findbuf(typval_T *argvars, typval_T *rettv)
787{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200788 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
789 return;
790
Bram Moolenaar93a10962022-06-16 11:42:09 +0100791 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200792 win_findbuf(argvars, rettv->vval.v_list);
793}
794
795/*
796 * "win_getid()" function
797 */
798 void
799f_win_getid(typval_T *argvars, typval_T *rettv)
800{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200801 if (in_vim9script()
802 && (check_for_opt_number_arg(argvars, 0) == FAIL
803 || (argvars[0].v_type != VAR_UNKNOWN
804 && check_for_opt_number_arg(argvars, 1) == FAIL)))
805 return;
806
Bram Moolenaar261f3462019-09-07 15:45:32 +0200807 rettv->vval.v_number = win_getid(argvars);
808}
809
810/*
811 * "win_gotoid()" function
812 */
813 void
814f_win_gotoid(typval_T *argvars, typval_T *rettv)
815{
Bram Moolenaara046b372019-09-15 17:26:07 +0200816 win_T *wp;
817 tabpage_T *tp;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200818 int id;
Bram Moolenaara046b372019-09-15 17:26:07 +0200819
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200820 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
821 return;
822
823 id = tv_get_number(&argvars[0]);
Bram Moolenaara046b372019-09-15 17:26:07 +0200824 if (cmdwin_type != 0)
825 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200826 emsg(_(e_invalid_in_cmdline_window));
Bram Moolenaara046b372019-09-15 17:26:07 +0200827 return;
828 }
LemonBoy4a392d22022-04-23 14:07:56 +0100829#if defined(FEAT_PROP_POPUP) && defined(FEAT_TERMINAL)
830 if (popup_is_popup(curwin) && curbuf->b_term != NULL)
831 {
832 emsg(_(e_not_allowed_for_terminal_in_popup_window));
833 return;
834 }
835#endif
Bram Moolenaara046b372019-09-15 17:26:07 +0200836 FOR_ALL_TAB_WINDOWS(tp, wp)
837 if (wp->w_id == id)
838 {
Bram Moolenaar3aca0912022-04-18 18:32:19 +0100839 // When jumping to another buffer stop Visual mode.
840 if (VIsual_active && wp->w_buffer != curbuf)
841 end_visual_mode();
Bram Moolenaara046b372019-09-15 17:26:07 +0200842 goto_tabpage_win(tp, wp);
843 rettv->vval.v_number = 1;
844 return;
845 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200846}
847
848/*
849 * "win_id2tabwin()" function
850 */
851 void
852f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
853{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200854 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
855 return;
856
Bram Moolenaar93a10962022-06-16 11:42:09 +0100857 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200858 win_id2tabwin(argvars, rettv->vval.v_list);
859}
860
861/*
862 * "win_id2win()" function
863 */
864 void
865f_win_id2win(typval_T *argvars, typval_T *rettv)
866{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200867 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
868 return;
869
Bram Moolenaar261f3462019-09-07 15:45:32 +0200870 rettv->vval.v_number = win_id2win(argvars);
871}
872
873/*
Daniel Steinbergee630312022-01-10 13:36:34 +0000874 * "win_move_separator()" function
875 */
876 void
877f_win_move_separator(typval_T *argvars, typval_T *rettv)
878{
879 win_T *wp;
880 int offset;
881
882 rettv->vval.v_number = FALSE;
883
884 if (in_vim9script()
885 && (check_for_number_arg(argvars, 0) == FAIL
886 || check_for_number_arg(argvars, 1) == FAIL))
887 return;
888
889 wp = find_win_by_nr_or_id(&argvars[0]);
890 if (wp == NULL || win_valid_popup(wp))
891 return;
zeertzjq873f41a2022-11-01 11:44:43 +0000892 if (!win_valid(wp))
893 {
894 emsg(_(e_cannot_resize_window_in_another_tab_page));
895 return;
896 }
Daniel Steinbergee630312022-01-10 13:36:34 +0000897
898 offset = (int)tv_get_number(&argvars[1]);
899 win_drag_vsep_line(wp, offset);
900 rettv->vval.v_number = TRUE;
901}
902
903/*
904 * "win_move_statusline()" function
905 */
906 void
907f_win_move_statusline(typval_T *argvars, typval_T *rettv)
908{
909 win_T *wp;
910 int offset;
911
912 rettv->vval.v_number = FALSE;
913
914 if (in_vim9script()
915 && (check_for_number_arg(argvars, 0) == FAIL
916 || check_for_number_arg(argvars, 1) == FAIL))
917 return;
918
919 wp = find_win_by_nr_or_id(&argvars[0]);
920 if (wp == NULL || win_valid_popup(wp))
921 return;
Bram Moolenaar86e67172022-10-31 12:24:12 +0000922 if (!win_valid(wp))
923 {
924 emsg(_(e_cannot_resize_window_in_another_tab_page));
925 return;
926 }
Daniel Steinbergee630312022-01-10 13:36:34 +0000927
928 offset = (int)tv_get_number(&argvars[1]);
929 win_drag_status_line(wp, offset);
930 rettv->vval.v_number = TRUE;
931}
932
933/*
Bram Moolenaar261f3462019-09-07 15:45:32 +0200934 * "win_screenpos()" function
935 */
936 void
937f_win_screenpos(typval_T *argvars, typval_T *rettv)
938{
939 win_T *wp;
940
941 if (rettv_list_alloc(rettv) == FAIL)
942 return;
943
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200944 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
945 return;
946
Bram Moolenaar261f3462019-09-07 15:45:32 +0200947 wp = find_win_by_nr_or_id(&argvars[0]);
948 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
949 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
950}
951
952/*
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200953 * Move the window wp into a new split of targetwin in a given direction
954 */
955 static void
956win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
957{
958 int dir;
959 int height = wp->w_height;
960 win_T *oldwin = curwin;
961
962 if (wp == targetwin)
963 return;
964
965 // Jump to the target window
966 if (curwin != targetwin)
967 win_goto(targetwin);
968
969 // Remove the old window and frame from the tree of frames
970 (void)winframe_remove(wp, &dir, NULL);
971 win_remove(wp, NULL);
972 last_status(FALSE); // may need to remove last status line
973 (void)win_comp_pos(); // recompute window positions
974
975 // Split a window on the desired side and put the old window there
976 (void)win_split_ins(size, flags, wp, dir);
977
978 // If splitting horizontally, try to preserve height
979 if (size == 0 && !(flags & WSP_VERT))
980 {
981 win_setheight_win(height, wp);
982 if (p_ea)
983 win_equal(wp, TRUE, 'v');
984 }
985
986#if defined(FEAT_GUI)
987 // When 'guioptions' includes 'L' or 'R' may have to remove or add
988 // scrollbars. Have to update them anyway.
989 gui_may_update_scrollbars();
990#endif
991
992 if (oldwin != curwin)
993 win_goto(oldwin);
994}
995
996/*
997 * "win_splitmove()" function
998 */
999 void
1000f_win_splitmove(typval_T *argvars, typval_T *rettv)
1001{
1002 win_T *wp;
1003 win_T *targetwin;
1004 int flags = 0, size = 0;
1005
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02001006 if (in_vim9script()
1007 && (check_for_number_arg(argvars, 0) == FAIL
1008 || check_for_number_arg(argvars, 1) == FAIL
1009 || check_for_opt_dict_arg(argvars, 2) == FAIL))
1010 return;
1011
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001012 wp = find_win_by_nr_or_id(&argvars[0]);
1013 targetwin = find_win_by_nr_or_id(&argvars[1]);
1014
Bram Moolenaar7b94e772020-01-06 21:03:24 +01001015 if (wp == NULL || targetwin == NULL || wp == targetwin
Bram Moolenaar0f1563f2020-03-20 21:15:51 +01001016 || !win_valid(wp) || !win_valid(targetwin)
1017 || win_valid_popup(wp) || win_valid_popup(targetwin))
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001018 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001019 emsg(_(e_invalid_window_number));
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001020 rettv->vval.v_number = -1;
1021 return;
1022 }
1023
1024 if (argvars[2].v_type != VAR_UNKNOWN)
1025 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001026 dict_T *d;
1027 dictitem_T *di;
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001028
Yegappan Lakshmanan04c4c572022-08-30 19:48:24 +01001029 if (check_for_nonnull_dict_arg(argvars, 2) == FAIL)
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001030 return;
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001031
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001032 d = argvars[2].vval.v_dict;
Bram Moolenaard61efa52022-07-23 09:52:04 +01001033 if (dict_get_bool(d, "vertical", FALSE))
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001034 flags |= WSP_VERT;
1035 if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
1036 flags |= tv_get_bool(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
Bram Moolenaard61efa52022-07-23 09:52:04 +01001037 size = (int)dict_get_number(d, "size");
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001038 }
1039
1040 win_move_into_split(wp, targetwin, size, flags);
1041}
1042
1043/*
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001044 * "win_gettype(nr)" function
1045 */
1046 void
1047f_win_gettype(typval_T *argvars, typval_T *rettv)
1048{
1049 win_T *wp = curwin;
1050
1051 rettv->v_type = VAR_STRING;
1052 rettv->vval.v_string = NULL;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001053
1054 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
1055 return;
1056
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001057 if (argvars[0].v_type != VAR_UNKNOWN)
1058 {
1059 wp = find_win_by_nr_or_id(&argvars[0]);
1060 if (wp == NULL)
1061 {
1062 rettv->vval.v_string = vim_strsave((char_u *)"unknown");
1063 return;
1064 }
1065 }
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001066 if (wp == aucmd_win)
Bram Moolenaar40a019f2020-06-17 21:41:35 +02001067 rettv->vval.v_string = vim_strsave((char_u *)"autocmd");
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001068#if defined(FEAT_QUICKFIX)
1069 else if (wp->w_p_pvw)
1070 rettv->vval.v_string = vim_strsave((char_u *)"preview");
1071#endif
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001072#ifdef FEAT_PROP_POPUP
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001073 else if (WIN_IS_POPUP(wp))
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001074 rettv->vval.v_string = vim_strsave((char_u *)"popup");
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001075#endif
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001076 else if (wp == curwin && cmdwin_type != 0)
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001077 rettv->vval.v_string = vim_strsave((char_u *)"command");
Yegappan Lakshmanan28d84212021-07-31 12:43:23 +02001078#ifdef FEAT_QUICKFIX
1079 else if (bt_quickfix(wp->w_buffer))
1080 rettv->vval.v_string = vim_strsave((char_u *)
1081 (wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
1082#endif
1083
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001084}
1085
1086/*
1087 * "getcmdwintype()" function
1088 */
1089 void
1090f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
1091{
1092 rettv->v_type = VAR_STRING;
1093 rettv->vval.v_string = NULL;
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001094 rettv->vval.v_string = alloc(2);
1095 if (rettv->vval.v_string != NULL)
1096 {
1097 rettv->vval.v_string[0] = cmdwin_type;
1098 rettv->vval.v_string[1] = NUL;
1099 }
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001100}
1101
1102/*
Bram Moolenaar261f3462019-09-07 15:45:32 +02001103 * "winbufnr(nr)" function
1104 */
1105 void
1106f_winbufnr(typval_T *argvars, typval_T *rettv)
1107{
1108 win_T *wp;
1109
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001110 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1111 return;
1112
Bram Moolenaar261f3462019-09-07 15:45:32 +02001113 wp = find_win_by_nr_or_id(&argvars[0]);
1114 if (wp == NULL)
1115 rettv->vval.v_number = -1;
1116 else
1117 rettv->vval.v_number = wp->w_buffer->b_fnum;
1118}
1119
1120/*
1121 * "wincol()" function
1122 */
1123 void
1124f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
1125{
1126 validate_cursor();
1127 rettv->vval.v_number = curwin->w_wcol + 1;
1128}
1129
1130/*
1131 * "winheight(nr)" function
1132 */
1133 void
1134f_winheight(typval_T *argvars, typval_T *rettv)
1135{
1136 win_T *wp;
1137
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001138 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1139 return;
1140
Bram Moolenaar261f3462019-09-07 15:45:32 +02001141 wp = find_win_by_nr_or_id(&argvars[0]);
1142 if (wp == NULL)
1143 rettv->vval.v_number = -1;
1144 else
1145 rettv->vval.v_number = wp->w_height;
1146}
1147
1148/*
1149 * "winlayout()" function
1150 */
1151 void
1152f_winlayout(typval_T *argvars, typval_T *rettv)
1153{
1154 tabpage_T *tp;
1155
Bram Moolenaar93a10962022-06-16 11:42:09 +01001156 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001157 return;
1158
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001159 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
1160 return;
1161
Bram Moolenaar261f3462019-09-07 15:45:32 +02001162 if (argvars[0].v_type == VAR_UNKNOWN)
1163 tp = curtab;
1164 else
1165 {
1166 tp = find_tabpage((int)tv_get_number(&argvars[0]));
1167 if (tp == NULL)
1168 return;
1169 }
1170
1171 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
1172}
1173
1174/*
1175 * "winline()" function
1176 */
1177 void
1178f_winline(typval_T *argvars UNUSED, typval_T *rettv)
1179{
1180 validate_cursor();
1181 rettv->vval.v_number = curwin->w_wrow + 1;
1182}
1183
1184/*
1185 * "winnr()" function
1186 */
1187 void
1188f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
1189{
1190 int nr = 1;
1191
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001192 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
1193 return;
1194
Bram Moolenaar261f3462019-09-07 15:45:32 +02001195 nr = get_winnr(curtab, &argvars[0]);
1196 rettv->vval.v_number = nr;
1197}
1198
1199/*
1200 * "winrestcmd()" function
1201 */
1202 void
1203f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
1204{
1205 win_T *wp;
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001206 int i;
1207 int winnr;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001208 garray_T ga;
1209 char_u buf[50];
1210
Bram Moolenaar04935fb2022-01-08 16:19:22 +00001211 ga_init2(&ga, sizeof(char), 70);
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001212
1213 // Do this twice to handle some window layouts properly.
1214 for (i = 0; i < 2; ++i)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001215 {
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001216 winnr = 1;
1217 FOR_ALL_WINDOWS(wp)
1218 {
1219 sprintf((char *)buf, ":%dresize %d|", winnr, wp->w_height);
1220 ga_concat(&ga, buf);
1221 sprintf((char *)buf, "vert :%dresize %d|", winnr, wp->w_width);
1222 ga_concat(&ga, buf);
1223 ++winnr;
1224 }
Bram Moolenaar261f3462019-09-07 15:45:32 +02001225 }
1226 ga_append(&ga, NUL);
1227
1228 rettv->vval.v_string = ga.ga_data;
1229 rettv->v_type = VAR_STRING;
1230}
1231
1232/*
1233 * "winrestview()" function
1234 */
1235 void
1236f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
1237{
1238 dict_T *dict;
1239
Yegappan Lakshmanan04c4c572022-08-30 19:48:24 +01001240 if (check_for_nonnull_dict_arg(argvars, 0) == FAIL)
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001241 return;
1242
Yegappan Lakshmanan04c4c572022-08-30 19:48:24 +01001243 dict = argvars[0].vval.v_dict;
1244 if (dict_has_key(dict, "lnum"))
1245 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, "lnum");
1246 if (dict_has_key(dict, "col"))
1247 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, "col");
1248 if (dict_has_key(dict, "coladd"))
1249 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, "coladd");
1250 if (dict_has_key(dict, "curswant"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001251 {
Yegappan Lakshmanan04c4c572022-08-30 19:48:24 +01001252 curwin->w_curswant = (colnr_T)dict_get_number(dict, "curswant");
1253 curwin->w_set_curswant = FALSE;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001254 }
Yegappan Lakshmanan04c4c572022-08-30 19:48:24 +01001255
1256 if (dict_has_key(dict, "topline"))
1257 set_topline(curwin, (linenr_T)dict_get_number(dict, "topline"));
1258#ifdef FEAT_DIFF
1259 if (dict_has_key(dict, "topfill"))
1260 curwin->w_topfill = (int)dict_get_number(dict, "topfill");
1261#endif
1262 if (dict_has_key(dict, "leftcol"))
1263 curwin->w_leftcol = (colnr_T)dict_get_number(dict, "leftcol");
1264 if (dict_has_key(dict, "skipcol"))
1265 curwin->w_skipcol = (colnr_T)dict_get_number(dict, "skipcol");
1266
1267 check_cursor();
1268 win_new_height(curwin, curwin->w_height);
1269 win_new_width(curwin, curwin->w_width);
1270 changed_window_setting();
1271
1272 if (curwin->w_topline <= 0)
1273 curwin->w_topline = 1;
1274 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1275 curwin->w_topline = curbuf->b_ml.ml_line_count;
1276#ifdef FEAT_DIFF
1277 check_topfill(curwin, TRUE);
1278#endif
Bram Moolenaar261f3462019-09-07 15:45:32 +02001279}
1280
1281/*
1282 * "winsaveview()" function
1283 */
1284 void
1285f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1286{
1287 dict_T *dict;
1288
1289 if (rettv_dict_alloc(rettv) == FAIL)
1290 return;
1291 dict = rettv->vval.v_dict;
1292
1293 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1294 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1295 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1296 update_curswant();
1297 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1298
1299 dict_add_number(dict, "topline", (long)curwin->w_topline);
1300#ifdef FEAT_DIFF
1301 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1302#endif
1303 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1304 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1305}
1306
1307/*
1308 * "winwidth(nr)" function
1309 */
1310 void
1311f_winwidth(typval_T *argvars, typval_T *rettv)
1312{
1313 win_T *wp;
1314
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001315 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1316 return;
1317
Bram Moolenaar261f3462019-09-07 15:45:32 +02001318 wp = find_win_by_nr_or_id(&argvars[0]);
1319 if (wp == NULL)
1320 rettv->vval.v_number = -1;
1321 else
1322 rettv->vval.v_number = wp->w_width;
1323}
1324#endif // FEAT_EVAL
1325
1326#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1327 || defined(PROTO)
1328/*
1329 * Set "win" to be the curwin and "tp" to be the current tab page.
1330 * restore_win() MUST be called to undo, also when FAIL is returned.
1331 * No autocommands will be executed until restore_win() is called.
1332 * When "no_display" is TRUE the display won't be affected, no redraw is
1333 * triggered, another tabpage access is limited.
1334 * Returns FAIL if switching to "win" failed.
1335 */
1336 int
1337switch_win(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001338 switchwin_T *switchwin,
1339 win_T *win,
1340 tabpage_T *tp,
1341 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001342{
1343 block_autocmds();
Bram Moolenaar18f47402022-01-06 13:24:51 +00001344 return switch_win_noblock(switchwin, win, tp, no_display);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001345}
1346
1347/*
1348 * As switch_win() but without blocking autocommands.
1349 */
1350 int
1351switch_win_noblock(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001352 switchwin_T *switchwin,
1353 win_T *win,
1354 tabpage_T *tp,
1355 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001356{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001357 CLEAR_POINTER(switchwin);
1358 switchwin->sw_curwin = curwin;
1359 if (win == curwin)
1360 switchwin->sw_same_win = TRUE;
1361 else
1362 {
1363 // Disable Visual selection, because redrawing may fail.
1364 switchwin->sw_visual_active = VIsual_active;
1365 VIsual_active = FALSE;
1366 }
1367
Bram Moolenaar261f3462019-09-07 15:45:32 +02001368 if (tp != NULL)
1369 {
Bram Moolenaar18f47402022-01-06 13:24:51 +00001370 switchwin->sw_curtab = curtab;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001371 if (no_display)
1372 {
1373 curtab->tp_firstwin = firstwin;
1374 curtab->tp_lastwin = lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001375 curtab->tp_topframe = topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001376 curtab = tp;
1377 firstwin = curtab->tp_firstwin;
1378 lastwin = curtab->tp_lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001379 topframe = curtab->tp_topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001380 }
1381 else
1382 goto_tabpage_tp(tp, FALSE, FALSE);
1383 }
1384 if (!win_valid(win))
1385 return FAIL;
1386 curwin = win;
1387 curbuf = curwin->w_buffer;
1388 return OK;
1389}
1390
1391/*
1392 * Restore current tabpage and window saved by switch_win(), if still valid.
1393 * When "no_display" is TRUE the display won't be affected, no redraw is
1394 * triggered.
1395 */
1396 void
1397restore_win(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001398 switchwin_T *switchwin,
1399 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001400{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001401 restore_win_noblock(switchwin, no_display);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001402 unblock_autocmds();
1403}
1404
1405/*
1406 * As restore_win() but without unblocking autocommands.
1407 */
1408 void
1409restore_win_noblock(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001410 switchwin_T *switchwin,
1411 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001412{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001413 if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001414 {
1415 if (no_display)
1416 {
1417 curtab->tp_firstwin = firstwin;
1418 curtab->tp_lastwin = lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001419 curtab->tp_topframe = topframe;
Bram Moolenaar18f47402022-01-06 13:24:51 +00001420 curtab = switchwin->sw_curtab;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001421 firstwin = curtab->tp_firstwin;
1422 lastwin = curtab->tp_lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001423 topframe = curtab->tp_topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001424 }
1425 else
Bram Moolenaar18f47402022-01-06 13:24:51 +00001426 goto_tabpage_tp(switchwin->sw_curtab, FALSE, FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001427 }
Bram Moolenaar18f47402022-01-06 13:24:51 +00001428
1429 if (!switchwin->sw_same_win)
1430 VIsual_active = switchwin->sw_visual_active;
1431
1432 if (win_valid(switchwin->sw_curwin))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001433 {
Bram Moolenaar18f47402022-01-06 13:24:51 +00001434 curwin = switchwin->sw_curwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001435 curbuf = curwin->w_buffer;
1436 }
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01001437# ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +02001438 else if (WIN_IS_POPUP(curwin))
1439 // original window was closed and now we're in a popup window: Go
1440 // to the first valid window.
1441 win_goto(firstwin);
1442# endif
Bram Moolenaar261f3462019-09-07 15:45:32 +02001443}
1444#endif