blob: 00d63cd3658c312f0c9c62c7e157decf110bc41a [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/*
264 * Get the layout of the given tab page for winlayout().
265 */
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;
284 list_append_list(l, fr_list);
285 }
286
287 if (fr->fr_layout == FR_LEAF)
288 {
289 if (fr->fr_win != NULL)
290 {
291 list_append_string(fr_list, (char_u *)"leaf", -1);
292 list_append_number(fr_list, fr->fr_win->w_id);
293 }
294 }
295 else
296 {
297 list_append_string(fr_list,
298 fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1);
299
300 win_list = list_alloc();
301 if (win_list == NULL)
302 return;
303 list_append_list(fr_list, win_list);
304 child = fr->fr_child;
305 while (child != NULL)
306 {
307 get_framelayout(child, win_list, FALSE);
308 child = child->fr_next;
309 }
310 }
311}
312
313/*
314 * Common code for tabpagewinnr() and winnr().
315 */
316 static int
317get_winnr(tabpage_T *tp, typval_T *argvar)
318{
319 win_T *twin;
320 int nr = 1;
321 win_T *wp;
322 char_u *arg;
323
324 twin = (tp == curtab) ? curwin : tp->tp_curwin;
325 if (argvar->v_type != VAR_UNKNOWN)
326 {
327 int invalid_arg = FALSE;
328
329 arg = tv_get_string_chk(argvar);
330 if (arg == NULL)
331 nr = 0; // type error; errmsg already given
332 else if (STRCMP(arg, "$") == 0)
333 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
334 else if (STRCMP(arg, "#") == 0)
335 {
336 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200337 }
338 else
339 {
340 long count;
341 char_u *endp;
342
343 // Extract the window count (if specified). e.g. winnr('3j')
344 count = strtol((char *)arg, (char **)&endp, 10);
345 if (count <= 0)
346 count = 1; // if count is not specified, default to 1
347 if (endp != NULL && *endp != '\0')
348 {
349 if (STRCMP(endp, "j") == 0)
350 twin = win_vert_neighbor(tp, twin, FALSE, count);
351 else if (STRCMP(endp, "k") == 0)
352 twin = win_vert_neighbor(tp, twin, TRUE, count);
353 else if (STRCMP(endp, "h") == 0)
354 twin = win_horz_neighbor(tp, twin, TRUE, count);
355 else if (STRCMP(endp, "l") == 0)
356 twin = win_horz_neighbor(tp, twin, FALSE, count);
357 else
358 invalid_arg = TRUE;
359 }
360 else
361 invalid_arg = TRUE;
362 }
Bram Moolenaar631ebc42020-02-03 22:15:26 +0100363 if (twin == NULL)
364 nr = 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200365
366 if (invalid_arg)
367 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200368 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200369 nr = 0;
370 }
371 }
372
373 if (nr > 0)
374 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
375 wp != twin; wp = wp->w_next)
376 {
377 if (wp == NULL)
378 {
379 // didn't find it in this tabpage
380 nr = 0;
381 break;
382 }
383 ++nr;
384 }
385 return nr;
386}
387
388/*
389 * Returns information about a window as a dictionary.
390 */
391 static dict_T *
392get_win_info(win_T *wp, short tpnr, short winnr)
393{
394 dict_T *dict;
395
396 dict = dict_alloc();
397 if (dict == NULL)
398 return NULL;
399
LemonBoy8530b412022-04-20 19:00:36 +0100400 // make sure w_botline is valid
401 validate_botline_win(wp);
402
Bram Moolenaar261f3462019-09-07 15:45:32 +0200403 dict_add_number(dict, "tabnr", tpnr);
404 dict_add_number(dict, "winnr", winnr);
405 dict_add_number(dict, "winid", wp->w_id);
406 dict_add_number(dict, "height", wp->w_height);
407 dict_add_number(dict, "winrow", wp->w_winrow + 1);
408 dict_add_number(dict, "topline", wp->w_topline);
409 dict_add_number(dict, "botline", wp->w_botline - 1);
410#ifdef FEAT_MENU
411 dict_add_number(dict, "winbar", wp->w_winbar_height);
412#endif
413 dict_add_number(dict, "width", wp->w_width);
414 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaarcdf5fdb2021-11-20 11:14:24 +0000415 dict_add_number(dict, "textoff", win_col_off(wp));
Bram Moolenaar261f3462019-09-07 15:45:32 +0200416 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
417
418#ifdef FEAT_TERMINAL
419 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
420#endif
421#ifdef FEAT_QUICKFIX
422 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
423 dict_add_number(dict, "loclist",
424 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
425#endif
426
427 // Add a reference to window variables
428 dict_add_dict(dict, "variables", wp->w_vars);
429
430 return dict;
431}
432
433/*
434 * Returns information (variables, options, etc.) about a tab page
435 * as a dictionary.
436 */
437 static dict_T *
438get_tabpage_info(tabpage_T *tp, int tp_idx)
439{
440 win_T *wp;
441 dict_T *dict;
442 list_T *l;
443
444 dict = dict_alloc();
445 if (dict == NULL)
446 return NULL;
447
448 dict_add_number(dict, "tabnr", tp_idx);
449
450 l = list_alloc();
451 if (l != NULL)
452 {
Bram Moolenaar00d253e2020-04-06 22:13:01 +0200453 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200454 list_append_number(l, (varnumber_T)wp->w_id);
455 dict_add_list(dict, "windows", l);
456 }
457
458 // Make a reference to tabpage variables
459 dict_add_dict(dict, "variables", tp->tp_vars);
460
461 return dict;
462}
463
464/*
465 * "gettabinfo()" function
466 */
467 void
468f_gettabinfo(typval_T *argvars, typval_T *rettv)
469{
470 tabpage_T *tp, *tparg = NULL;
471 dict_T *d;
472 int tpnr = 0;
473
Bram Moolenaar93a10962022-06-16 11:42:09 +0100474 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200475 return;
476
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200477 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
478 return;
479
Bram Moolenaar261f3462019-09-07 15:45:32 +0200480 if (argvars[0].v_type != VAR_UNKNOWN)
481 {
482 // Information about one tab page
483 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
484 if (tparg == NULL)
485 return;
486 }
487
488 // Get information about a specific tab page or all tab pages
489 FOR_ALL_TABPAGES(tp)
490 {
491 tpnr++;
492 if (tparg != NULL && tp != tparg)
493 continue;
494 d = get_tabpage_info(tp, tpnr);
495 if (d != NULL)
496 list_append_dict(rettv->vval.v_list, d);
497 if (tparg != NULL)
498 return;
499 }
500}
501
502/*
503 * "getwininfo()" function
504 */
505 void
506f_getwininfo(typval_T *argvars, typval_T *rettv)
507{
508 tabpage_T *tp;
509 win_T *wp = NULL, *wparg = NULL;
510 dict_T *d;
511 short tabnr = 0, winnr;
512
Bram Moolenaar93a10962022-06-16 11:42:09 +0100513 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200514 return;
515
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200516 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
517 return;
518
Bram Moolenaar261f3462019-09-07 15:45:32 +0200519 if (argvars[0].v_type != VAR_UNKNOWN)
520 {
521 wparg = win_id2wp(tv_get_number(&argvars[0]));
522 if (wparg == NULL)
523 return;
524 }
525
526 // Collect information about either all the windows across all the tab
527 // pages or one particular window.
528 FOR_ALL_TABPAGES(tp)
529 {
530 tabnr++;
531 winnr = 0;
532 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
533 {
534 winnr++;
535 if (wparg != NULL && wp != wparg)
536 continue;
537 d = get_win_info(wp, tabnr, winnr);
538 if (d != NULL)
539 list_append_dict(rettv->vval.v_list, d);
540 if (wparg != NULL)
541 // found information about a specific window
542 return;
543 }
544 }
Bram Moolenaar99ca9c42020-09-22 21:55:41 +0200545#ifdef FEAT_PROP_POPUP
546 if (wparg != NULL)
547 {
548 tabnr = 0;
549 FOR_ALL_TABPAGES(tp)
550 {
551 tabnr++;
552 FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
553 if (wp == wparg)
554 break;
555 }
556 d = get_win_info(wparg, tp == NULL ? 0 : tabnr, 0);
557 if (d != NULL)
558 list_append_dict(rettv->vval.v_list, d);
559 }
560#endif
Bram Moolenaar261f3462019-09-07 15:45:32 +0200561}
562
563/*
564 * "getwinpos({timeout})" function
565 */
566 void
567f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
568{
569 int x = -1;
570 int y = -1;
571
572 if (rettv_list_alloc(rettv) == FAIL)
573 return;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200574
575 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
576 return;
577
Bram Moolenaar261f3462019-09-07 15:45:32 +0200578#if defined(FEAT_GUI) \
579 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
580 || defined(MSWIN)
581 {
582 varnumber_T timeout = 100;
583
584 if (argvars[0].v_type != VAR_UNKNOWN)
585 timeout = tv_get_number(&argvars[0]);
586
587 (void)ui_get_winpos(&x, &y, timeout);
588 }
589#endif
590 list_append_number(rettv->vval.v_list, (varnumber_T)x);
591 list_append_number(rettv->vval.v_list, (varnumber_T)y);
592}
593
594
595/*
596 * "getwinposx()" function
597 */
598 void
599f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
600{
601 rettv->vval.v_number = -1;
602#if defined(FEAT_GUI) \
603 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
604 || defined(MSWIN)
605
606 {
607 int x, y;
608
609 if (ui_get_winpos(&x, &y, 100) == OK)
610 rettv->vval.v_number = x;
611 }
612#endif
613}
614
615/*
616 * "getwinposy()" function
617 */
618 void
619f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
620{
621 rettv->vval.v_number = -1;
622#if defined(FEAT_GUI) \
623 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
624 || defined(MSWIN)
625 {
626 int x, y;
627
628 if (ui_get_winpos(&x, &y, 100) == OK)
629 rettv->vval.v_number = y;
630 }
631#endif
632}
633
634/*
635 * "tabpagenr()" function
636 */
637 void
638f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
639{
640 int nr = 1;
641 char_u *arg;
642
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200643 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
644 return;
645
Bram Moolenaar261f3462019-09-07 15:45:32 +0200646 if (argvars[0].v_type != VAR_UNKNOWN)
647 {
648 arg = tv_get_string_chk(&argvars[0]);
649 nr = 0;
650 if (arg != NULL)
651 {
652 if (STRCMP(arg, "$") == 0)
653 nr = tabpage_index(NULL) - 1;
Bram Moolenaar62a23252020-08-09 14:04:42 +0200654 else if (STRCMP(arg, "#") == 0)
655 nr = valid_tabpage(lastused_tabpage) ?
656 tabpage_index(lastused_tabpage) : 0;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200657 else
Bram Moolenaar108010a2021-06-27 22:03:33 +0200658 semsg(_(e_invalid_expression_str), arg);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200659 }
660 }
661 else
662 nr = tabpage_index(curtab);
663 rettv->vval.v_number = nr;
664}
665
666/*
667 * "tabpagewinnr()" function
668 */
669 void
670f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
671{
672 int nr = 1;
673 tabpage_T *tp;
674
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200675 if (in_vim9script()
676 && (check_for_number_arg(argvars, 0) == FAIL
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200677 || check_for_opt_string_arg(argvars, 1) == FAIL))
Yegappan Lakshmanan1a71d312021-07-15 12:49:58 +0200678 return;
679
Bram Moolenaar261f3462019-09-07 15:45:32 +0200680 tp = find_tabpage((int)tv_get_number(&argvars[0]));
681 if (tp == NULL)
682 nr = 0;
683 else
684 nr = get_winnr(tp, &argvars[1]);
685 rettv->vval.v_number = nr;
686}
687
688/*
689 * "win_execute()" function
690 */
691 void
692f_win_execute(typval_T *argvars, typval_T *rettv)
693{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200694 int id;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200695 tabpage_T *tp;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200696 win_T *wp;
Bram Moolenaar18f47402022-01-06 13:24:51 +0000697 switchwin_T switchwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +0200698
Bram Moolenaar37487e12021-01-12 22:08:53 +0100699 // Return an empty string if something fails.
700 rettv->v_type = VAR_STRING;
701 rettv->vval.v_string = NULL;
702
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200703 if (in_vim9script()
704 && (check_for_number_arg(argvars, 0) == FAIL
705 || check_for_string_or_list_arg(argvars, 1) == FAIL
706 || check_for_opt_string_arg(argvars, 2) == FAIL))
707 return;
708
709 id = (int)tv_get_number(argvars);
710 wp = win_id2wp_tp(id, &tp);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200711 if (wp != NULL && tp != NULL)
712 {
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200713 pos_T curpos = wp->w_cursor;
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000714 char_u cwd[MAXPATHL];
Bram Moolenaard6f27c62022-01-11 12:37:20 +0000715 int cwd_status = FAIL;
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000716#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000717 char_u autocwd[MAXPATHL];
718 int apply_acd = FALSE;
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000719#endif
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000720
Bram Moolenaard6f27c62022-01-11 12:37:20 +0000721 // Getting and setting directory can be slow on some systems, only do
722 // this when the current or target window/tab have a local directory or
723 // 'acd' is set.
724 if (curwin != wp
725 && (curwin->w_localdir != NULL
726 || wp->w_localdir != NULL
727 || (curtab != tp
728 && (curtab->tp_localdir != NULL
729 || tp->tp_localdir != NULL))
730#ifdef FEAT_AUTOCHDIR
731 || p_acd
732#endif
733 ))
734 cwd_status = mch_dirname(cwd, MAXPATHL);
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000735
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000736#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000737 // If 'acd' is set, check we are using that directory. If yes, then
738 // apply 'acd' afterwards, otherwise restore the current directory.
739 if (cwd_status == OK && p_acd)
740 {
741 do_autochdir();
742 apply_acd = mch_dirname(autocwd, MAXPATHL) == OK
743 && STRCMP(cwd, autocwd) == 0;
744 }
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000745#endif
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200746
Bram Moolenaar18f47402022-01-06 13:24:51 +0000747 if (switch_win_noblock(&switchwin, wp, tp, TRUE) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200748 {
749 check_cursor();
750 execute_common(argvars, rettv, 1);
751 }
Bram Moolenaar18f47402022-01-06 13:24:51 +0000752 restore_win_noblock(&switchwin, TRUE);
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000753#ifdef FEAT_AUTOCHDIR
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000754 if (apply_acd)
755 do_autochdir();
Bram Moolenaar92f246e2021-12-28 20:03:43 +0000756 else
757#endif
758 if (cwd_status == OK)
Bram Moolenaar90c317f2021-12-28 13:15:05 +0000759 mch_chdir((char *)cwd);
Bram Moolenaar345f28d2019-10-08 22:20:35 +0200760
761 // Update the status line if the cursor moved.
762 if (win_valid(wp) && !EQUAL_POS(curpos, wp->w_cursor))
763 wp->w_redr_status = TRUE;
Bram Moolenaare664a322022-01-07 14:08:03 +0000764
765 // In case the command moved the cursor or changed the Visual area,
766 // check it is valid.
767 check_cursor();
768 if (VIsual_active)
769 check_pos(curbuf, &VIsual);
Bram Moolenaar261f3462019-09-07 15:45:32 +0200770 }
771}
772
773/*
774 * "win_findbuf()" function
775 */
776 void
777f_win_findbuf(typval_T *argvars, typval_T *rettv)
778{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200779 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
780 return;
781
Bram Moolenaar93a10962022-06-16 11:42:09 +0100782 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200783 win_findbuf(argvars, rettv->vval.v_list);
784}
785
786/*
787 * "win_getid()" function
788 */
789 void
790f_win_getid(typval_T *argvars, typval_T *rettv)
791{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200792 if (in_vim9script()
793 && (check_for_opt_number_arg(argvars, 0) == FAIL
794 || (argvars[0].v_type != VAR_UNKNOWN
795 && check_for_opt_number_arg(argvars, 1) == FAIL)))
796 return;
797
Bram Moolenaar261f3462019-09-07 15:45:32 +0200798 rettv->vval.v_number = win_getid(argvars);
799}
800
801/*
802 * "win_gotoid()" function
803 */
804 void
805f_win_gotoid(typval_T *argvars, typval_T *rettv)
806{
Bram Moolenaara046b372019-09-15 17:26:07 +0200807 win_T *wp;
808 tabpage_T *tp;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200809 int id;
Bram Moolenaara046b372019-09-15 17:26:07 +0200810
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200811 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
812 return;
813
814 id = tv_get_number(&argvars[0]);
Bram Moolenaara046b372019-09-15 17:26:07 +0200815#ifdef FEAT_CMDWIN
816 if (cmdwin_type != 0)
817 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200818 emsg(_(e_invalid_in_cmdline_window));
Bram Moolenaara046b372019-09-15 17:26:07 +0200819 return;
820 }
821#endif
LemonBoy4a392d22022-04-23 14:07:56 +0100822#if defined(FEAT_PROP_POPUP) && defined(FEAT_TERMINAL)
823 if (popup_is_popup(curwin) && curbuf->b_term != NULL)
824 {
825 emsg(_(e_not_allowed_for_terminal_in_popup_window));
826 return;
827 }
828#endif
Bram Moolenaara046b372019-09-15 17:26:07 +0200829 FOR_ALL_TAB_WINDOWS(tp, wp)
830 if (wp->w_id == id)
831 {
Bram Moolenaar3aca0912022-04-18 18:32:19 +0100832 // When jumping to another buffer stop Visual mode.
833 if (VIsual_active && wp->w_buffer != curbuf)
834 end_visual_mode();
Bram Moolenaara046b372019-09-15 17:26:07 +0200835 goto_tabpage_win(tp, wp);
836 rettv->vval.v_number = 1;
837 return;
838 }
Bram Moolenaar261f3462019-09-07 15:45:32 +0200839}
840
841/*
842 * "win_id2tabwin()" function
843 */
844 void
845f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
846{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200847 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
848 return;
849
Bram Moolenaar93a10962022-06-16 11:42:09 +0100850 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar261f3462019-09-07 15:45:32 +0200851 win_id2tabwin(argvars, rettv->vval.v_list);
852}
853
854/*
855 * "win_id2win()" function
856 */
857 void
858f_win_id2win(typval_T *argvars, typval_T *rettv)
859{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200860 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
861 return;
862
Bram Moolenaar261f3462019-09-07 15:45:32 +0200863 rettv->vval.v_number = win_id2win(argvars);
864}
865
866/*
Daniel Steinbergee630312022-01-10 13:36:34 +0000867 * "win_move_separator()" function
868 */
869 void
870f_win_move_separator(typval_T *argvars, typval_T *rettv)
871{
872 win_T *wp;
873 int offset;
874
875 rettv->vval.v_number = FALSE;
876
877 if (in_vim9script()
878 && (check_for_number_arg(argvars, 0) == FAIL
879 || check_for_number_arg(argvars, 1) == FAIL))
880 return;
881
882 wp = find_win_by_nr_or_id(&argvars[0]);
883 if (wp == NULL || win_valid_popup(wp))
884 return;
885
886 offset = (int)tv_get_number(&argvars[1]);
887 win_drag_vsep_line(wp, offset);
888 rettv->vval.v_number = TRUE;
889}
890
891/*
892 * "win_move_statusline()" function
893 */
894 void
895f_win_move_statusline(typval_T *argvars, typval_T *rettv)
896{
897 win_T *wp;
898 int offset;
899
900 rettv->vval.v_number = FALSE;
901
902 if (in_vim9script()
903 && (check_for_number_arg(argvars, 0) == FAIL
904 || check_for_number_arg(argvars, 1) == FAIL))
905 return;
906
907 wp = find_win_by_nr_or_id(&argvars[0]);
908 if (wp == NULL || win_valid_popup(wp))
909 return;
910
911 offset = (int)tv_get_number(&argvars[1]);
912 win_drag_status_line(wp, offset);
913 rettv->vval.v_number = TRUE;
914}
915
916/*
Bram Moolenaar261f3462019-09-07 15:45:32 +0200917 * "win_screenpos()" function
918 */
919 void
920f_win_screenpos(typval_T *argvars, typval_T *rettv)
921{
922 win_T *wp;
923
924 if (rettv_list_alloc(rettv) == FAIL)
925 return;
926
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +0200927 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
928 return;
929
Bram Moolenaar261f3462019-09-07 15:45:32 +0200930 wp = find_win_by_nr_or_id(&argvars[0]);
931 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
932 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
933}
934
935/*
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200936 * Move the window wp into a new split of targetwin in a given direction
937 */
938 static void
939win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
940{
941 int dir;
942 int height = wp->w_height;
943 win_T *oldwin = curwin;
944
945 if (wp == targetwin)
946 return;
947
948 // Jump to the target window
949 if (curwin != targetwin)
950 win_goto(targetwin);
951
952 // Remove the old window and frame from the tree of frames
953 (void)winframe_remove(wp, &dir, NULL);
954 win_remove(wp, NULL);
955 last_status(FALSE); // may need to remove last status line
956 (void)win_comp_pos(); // recompute window positions
957
958 // Split a window on the desired side and put the old window there
959 (void)win_split_ins(size, flags, wp, dir);
960
961 // If splitting horizontally, try to preserve height
962 if (size == 0 && !(flags & WSP_VERT))
963 {
964 win_setheight_win(height, wp);
965 if (p_ea)
966 win_equal(wp, TRUE, 'v');
967 }
968
969#if defined(FEAT_GUI)
970 // When 'guioptions' includes 'L' or 'R' may have to remove or add
971 // scrollbars. Have to update them anyway.
972 gui_may_update_scrollbars();
973#endif
974
975 if (oldwin != curwin)
976 win_goto(oldwin);
977}
978
979/*
980 * "win_splitmove()" function
981 */
982 void
983f_win_splitmove(typval_T *argvars, typval_T *rettv)
984{
985 win_T *wp;
986 win_T *targetwin;
987 int flags = 0, size = 0;
988
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200989 if (in_vim9script()
990 && (check_for_number_arg(argvars, 0) == FAIL
991 || check_for_number_arg(argvars, 1) == FAIL
992 || check_for_opt_dict_arg(argvars, 2) == FAIL))
993 return;
994
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200995 wp = find_win_by_nr_or_id(&argvars[0]);
996 targetwin = find_win_by_nr_or_id(&argvars[1]);
997
Bram Moolenaar7b94e772020-01-06 21:03:24 +0100998 if (wp == NULL || targetwin == NULL || wp == targetwin
Bram Moolenaar0f1563f2020-03-20 21:15:51 +0100999 || !win_valid(wp) || !win_valid(targetwin)
1000 || win_valid_popup(wp) || win_valid_popup(targetwin))
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001001 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001002 emsg(_(e_invalid_window_number));
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001003 rettv->vval.v_number = -1;
1004 return;
1005 }
1006
1007 if (argvars[2].v_type != VAR_UNKNOWN)
1008 {
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001009 dict_T *d;
1010 dictitem_T *di;
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001011
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001012 if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL)
1013 {
1014 emsg(_(e_invalid_argument));
1015 return;
1016 }
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001017
Bram Moolenaar6ed545e2022-05-09 20:09:23 +01001018 d = argvars[2].vval.v_dict;
1019 if (dict_get_bool(d, (char_u *)"vertical", FALSE))
1020 flags |= WSP_VERT;
1021 if ((di = dict_find(d, (char_u *)"rightbelow", -1)) != NULL)
1022 flags |= tv_get_bool(&di->di_tv) ? WSP_BELOW : WSP_ABOVE;
1023 size = (int)dict_get_number(d, (char_u *)"size");
Bram Moolenaard20dcb32019-09-10 21:22:58 +02001024 }
1025
1026 win_move_into_split(wp, targetwin, size, flags);
1027}
1028
1029/*
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001030 * "win_gettype(nr)" function
1031 */
1032 void
1033f_win_gettype(typval_T *argvars, typval_T *rettv)
1034{
1035 win_T *wp = curwin;
1036
1037 rettv->v_type = VAR_STRING;
1038 rettv->vval.v_string = NULL;
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001039
1040 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
1041 return;
1042
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001043 if (argvars[0].v_type != VAR_UNKNOWN)
1044 {
1045 wp = find_win_by_nr_or_id(&argvars[0]);
1046 if (wp == NULL)
1047 {
1048 rettv->vval.v_string = vim_strsave((char_u *)"unknown");
1049 return;
1050 }
1051 }
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001052 if (wp == aucmd_win)
Bram Moolenaar40a019f2020-06-17 21:41:35 +02001053 rettv->vval.v_string = vim_strsave((char_u *)"autocmd");
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001054#if defined(FEAT_QUICKFIX)
1055 else if (wp->w_p_pvw)
1056 rettv->vval.v_string = vim_strsave((char_u *)"preview");
1057#endif
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001058#ifdef FEAT_PROP_POPUP
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001059 else if (WIN_IS_POPUP(wp))
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001060 rettv->vval.v_string = vim_strsave((char_u *)"popup");
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001061#endif
1062#ifdef FEAT_CMDWIN
Bram Moolenaar0fe937f2020-06-16 22:42:04 +02001063 else if (wp == curwin && cmdwin_type != 0)
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001064 rettv->vval.v_string = vim_strsave((char_u *)"command");
1065#endif
Yegappan Lakshmanan28d84212021-07-31 12:43:23 +02001066#ifdef FEAT_QUICKFIX
1067 else if (bt_quickfix(wp->w_buffer))
1068 rettv->vval.v_string = vim_strsave((char_u *)
1069 (wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
1070#endif
1071
Bram Moolenaar00f3b4e2020-02-14 14:32:22 +01001072}
1073
1074/*
1075 * "getcmdwintype()" function
1076 */
1077 void
1078f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
1079{
1080 rettv->v_type = VAR_STRING;
1081 rettv->vval.v_string = NULL;
1082#ifdef FEAT_CMDWIN
1083 rettv->vval.v_string = alloc(2);
1084 if (rettv->vval.v_string != NULL)
1085 {
1086 rettv->vval.v_string[0] = cmdwin_type;
1087 rettv->vval.v_string[1] = NUL;
1088 }
1089#endif
1090}
1091
1092/*
Bram Moolenaar261f3462019-09-07 15:45:32 +02001093 * "winbufnr(nr)" function
1094 */
1095 void
1096f_winbufnr(typval_T *argvars, typval_T *rettv)
1097{
1098 win_T *wp;
1099
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001100 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1101 return;
1102
Bram Moolenaar261f3462019-09-07 15:45:32 +02001103 wp = find_win_by_nr_or_id(&argvars[0]);
1104 if (wp == NULL)
1105 rettv->vval.v_number = -1;
1106 else
1107 rettv->vval.v_number = wp->w_buffer->b_fnum;
1108}
1109
1110/*
1111 * "wincol()" function
1112 */
1113 void
1114f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
1115{
1116 validate_cursor();
1117 rettv->vval.v_number = curwin->w_wcol + 1;
1118}
1119
1120/*
1121 * "winheight(nr)" function
1122 */
1123 void
1124f_winheight(typval_T *argvars, typval_T *rettv)
1125{
1126 win_T *wp;
1127
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001128 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1129 return;
1130
Bram Moolenaar261f3462019-09-07 15:45:32 +02001131 wp = find_win_by_nr_or_id(&argvars[0]);
1132 if (wp == NULL)
1133 rettv->vval.v_number = -1;
1134 else
1135 rettv->vval.v_number = wp->w_height;
1136}
1137
1138/*
1139 * "winlayout()" function
1140 */
1141 void
1142f_winlayout(typval_T *argvars, typval_T *rettv)
1143{
1144 tabpage_T *tp;
1145
Bram Moolenaar93a10962022-06-16 11:42:09 +01001146 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001147 return;
1148
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001149 if (in_vim9script() && check_for_opt_number_arg(argvars, 0) == FAIL)
1150 return;
1151
Bram Moolenaar261f3462019-09-07 15:45:32 +02001152 if (argvars[0].v_type == VAR_UNKNOWN)
1153 tp = curtab;
1154 else
1155 {
1156 tp = find_tabpage((int)tv_get_number(&argvars[0]));
1157 if (tp == NULL)
1158 return;
1159 }
1160
1161 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
1162}
1163
1164/*
1165 * "winline()" function
1166 */
1167 void
1168f_winline(typval_T *argvars UNUSED, typval_T *rettv)
1169{
1170 validate_cursor();
1171 rettv->vval.v_number = curwin->w_wrow + 1;
1172}
1173
1174/*
1175 * "winnr()" function
1176 */
1177 void
1178f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
1179{
1180 int nr = 1;
1181
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001182 if (in_vim9script() && check_for_opt_string_arg(argvars, 0) == FAIL)
1183 return;
1184
Bram Moolenaar261f3462019-09-07 15:45:32 +02001185 nr = get_winnr(curtab, &argvars[0]);
1186 rettv->vval.v_number = nr;
1187}
1188
1189/*
1190 * "winrestcmd()" function
1191 */
1192 void
1193f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
1194{
1195 win_T *wp;
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001196 int i;
1197 int winnr;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001198 garray_T ga;
1199 char_u buf[50];
1200
Bram Moolenaar04935fb2022-01-08 16:19:22 +00001201 ga_init2(&ga, sizeof(char), 70);
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001202
1203 // Do this twice to handle some window layouts properly.
1204 for (i = 0; i < 2; ++i)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001205 {
Bram Moolenaara0c8aea2021-03-20 19:55:35 +01001206 winnr = 1;
1207 FOR_ALL_WINDOWS(wp)
1208 {
1209 sprintf((char *)buf, ":%dresize %d|", winnr, wp->w_height);
1210 ga_concat(&ga, buf);
1211 sprintf((char *)buf, "vert :%dresize %d|", winnr, wp->w_width);
1212 ga_concat(&ga, buf);
1213 ++winnr;
1214 }
Bram Moolenaar261f3462019-09-07 15:45:32 +02001215 }
1216 ga_append(&ga, NUL);
1217
1218 rettv->vval.v_string = ga.ga_data;
1219 rettv->v_type = VAR_STRING;
1220}
1221
1222/*
1223 * "winrestview()" function
1224 */
1225 void
1226f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
1227{
1228 dict_T *dict;
1229
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001230 if (in_vim9script() && check_for_dict_arg(argvars, 0) == FAIL)
1231 return;
1232
Bram Moolenaar261f3462019-09-07 15:45:32 +02001233 if (argvars[0].v_type != VAR_DICT
1234 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00001235 emsg(_(e_invalid_argument));
Bram Moolenaar261f3462019-09-07 15:45:32 +02001236 else
1237 {
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001238 if (dict_has_key(dict, "lnum"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001239 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001240 if (dict_has_key(dict, "col"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001241 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001242 if (dict_has_key(dict, "coladd"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001243 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001244 if (dict_has_key(dict, "curswant"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001245 {
1246 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
1247 curwin->w_set_curswant = FALSE;
1248 }
1249
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001250 if (dict_has_key(dict, "topline"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001251 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
1252#ifdef FEAT_DIFF
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001253 if (dict_has_key(dict, "topfill"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001254 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
1255#endif
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001256 if (dict_has_key(dict, "leftcol"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001257 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Yegappan Lakshmanan4829c1c2022-04-04 15:16:54 +01001258 if (dict_has_key(dict, "skipcol"))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001259 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
1260
1261 check_cursor();
1262 win_new_height(curwin, curwin->w_height);
1263 win_new_width(curwin, curwin->w_width);
1264 changed_window_setting();
1265
1266 if (curwin->w_topline <= 0)
1267 curwin->w_topline = 1;
1268 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
1269 curwin->w_topline = curbuf->b_ml.ml_line_count;
1270#ifdef FEAT_DIFF
1271 check_topfill(curwin, TRUE);
1272#endif
1273 }
1274}
1275
1276/*
1277 * "winsaveview()" function
1278 */
1279 void
1280f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
1281{
1282 dict_T *dict;
1283
1284 if (rettv_dict_alloc(rettv) == FAIL)
1285 return;
1286 dict = rettv->vval.v_dict;
1287
1288 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
1289 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
1290 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
1291 update_curswant();
1292 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
1293
1294 dict_add_number(dict, "topline", (long)curwin->w_topline);
1295#ifdef FEAT_DIFF
1296 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
1297#endif
1298 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
1299 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
1300}
1301
1302/*
1303 * "winwidth(nr)" function
1304 */
1305 void
1306f_winwidth(typval_T *argvars, typval_T *rettv)
1307{
1308 win_T *wp;
1309
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001310 if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
1311 return;
1312
Bram Moolenaar261f3462019-09-07 15:45:32 +02001313 wp = find_win_by_nr_or_id(&argvars[0]);
1314 if (wp == NULL)
1315 rettv->vval.v_number = -1;
1316 else
1317 rettv->vval.v_number = wp->w_width;
1318}
1319#endif // FEAT_EVAL
1320
1321#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
1322 || defined(PROTO)
1323/*
1324 * Set "win" to be the curwin and "tp" to be the current tab page.
1325 * restore_win() MUST be called to undo, also when FAIL is returned.
1326 * No autocommands will be executed until restore_win() is called.
1327 * When "no_display" is TRUE the display won't be affected, no redraw is
1328 * triggered, another tabpage access is limited.
1329 * Returns FAIL if switching to "win" failed.
1330 */
1331 int
1332switch_win(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001333 switchwin_T *switchwin,
1334 win_T *win,
1335 tabpage_T *tp,
1336 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001337{
1338 block_autocmds();
Bram Moolenaar18f47402022-01-06 13:24:51 +00001339 return switch_win_noblock(switchwin, win, tp, no_display);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001340}
1341
1342/*
1343 * As switch_win() but without blocking autocommands.
1344 */
1345 int
1346switch_win_noblock(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001347 switchwin_T *switchwin,
1348 win_T *win,
1349 tabpage_T *tp,
1350 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001351{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001352 CLEAR_POINTER(switchwin);
1353 switchwin->sw_curwin = curwin;
1354 if (win == curwin)
1355 switchwin->sw_same_win = TRUE;
1356 else
1357 {
1358 // Disable Visual selection, because redrawing may fail.
1359 switchwin->sw_visual_active = VIsual_active;
1360 VIsual_active = FALSE;
1361 }
1362
Bram Moolenaar261f3462019-09-07 15:45:32 +02001363 if (tp != NULL)
1364 {
Bram Moolenaar18f47402022-01-06 13:24:51 +00001365 switchwin->sw_curtab = curtab;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001366 if (no_display)
1367 {
1368 curtab->tp_firstwin = firstwin;
1369 curtab->tp_lastwin = lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001370 curtab->tp_topframe = topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001371 curtab = tp;
1372 firstwin = curtab->tp_firstwin;
1373 lastwin = curtab->tp_lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001374 topframe = curtab->tp_topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001375 }
1376 else
1377 goto_tabpage_tp(tp, FALSE, FALSE);
1378 }
1379 if (!win_valid(win))
1380 return FAIL;
1381 curwin = win;
1382 curbuf = curwin->w_buffer;
1383 return OK;
1384}
1385
1386/*
1387 * Restore current tabpage and window saved by switch_win(), if still valid.
1388 * When "no_display" is TRUE the display won't be affected, no redraw is
1389 * triggered.
1390 */
1391 void
1392restore_win(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001393 switchwin_T *switchwin,
1394 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001395{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001396 restore_win_noblock(switchwin, no_display);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001397 unblock_autocmds();
1398}
1399
1400/*
1401 * As restore_win() but without unblocking autocommands.
1402 */
1403 void
1404restore_win_noblock(
Bram Moolenaar18f47402022-01-06 13:24:51 +00001405 switchwin_T *switchwin,
1406 int no_display)
Bram Moolenaar261f3462019-09-07 15:45:32 +02001407{
Bram Moolenaar18f47402022-01-06 13:24:51 +00001408 if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001409 {
1410 if (no_display)
1411 {
1412 curtab->tp_firstwin = firstwin;
1413 curtab->tp_lastwin = lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001414 curtab->tp_topframe = topframe;
Bram Moolenaar18f47402022-01-06 13:24:51 +00001415 curtab = switchwin->sw_curtab;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001416 firstwin = curtab->tp_firstwin;
1417 lastwin = curtab->tp_lastwin;
Bram Moolenaardab17a02021-12-20 21:35:59 +00001418 topframe = curtab->tp_topframe;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001419 }
1420 else
Bram Moolenaar18f47402022-01-06 13:24:51 +00001421 goto_tabpage_tp(switchwin->sw_curtab, FALSE, FALSE);
Bram Moolenaar261f3462019-09-07 15:45:32 +02001422 }
Bram Moolenaar18f47402022-01-06 13:24:51 +00001423
1424 if (!switchwin->sw_same_win)
1425 VIsual_active = switchwin->sw_visual_active;
1426
1427 if (win_valid(switchwin->sw_curwin))
Bram Moolenaar261f3462019-09-07 15:45:32 +02001428 {
Bram Moolenaar18f47402022-01-06 13:24:51 +00001429 curwin = switchwin->sw_curwin;
Bram Moolenaar261f3462019-09-07 15:45:32 +02001430 curbuf = curwin->w_buffer;
1431 }
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01001432# ifdef FEAT_PROP_POPUP
Bram Moolenaar261f3462019-09-07 15:45:32 +02001433 else if (WIN_IS_POPUP(curwin))
1434 // original window was closed and now we're in a popup window: Go
1435 // to the first valid window.
1436 win_goto(firstwin);
1437# endif
Bram Moolenaar261f3462019-09-07 15:45:32 +02001438}
1439#endif