blob: c4b543de39586779ea75e3b70574696f3c4464a4 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read a list of people who contributed.
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#include "vim.h"
11
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010012static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, long Prenum);
13static void win_init(win_T *newp, win_T *oldp, int flags);
14static void win_init_some(win_T *newp, win_T *oldp);
15static void frame_comp_pos(frame_T *topfrp, int *row, int *col);
16static void frame_setheight(frame_T *curfrp, int height);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010017static void frame_setwidth(frame_T *curfrp, int width);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010018static void win_exchange(long);
19static void win_rotate(int, int);
20static void win_totop(int size, int flags);
21static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010022static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
23static frame_T *win_altframe(win_T *win, tabpage_T *tp);
24static tabpage_T *alt_tabpage(void);
25static win_T *frame2win(frame_T *frp);
26static int frame_has_win(frame_T *frp, win_T *wp);
27static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
28static int frame_fixed_height(frame_T *frp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010029static int frame_fixed_width(frame_T *frp);
30static void frame_add_statusline(frame_T *frp);
31static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw);
32static void frame_add_vsep(frame_T *frp);
33static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
34static void frame_fix_width(win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010035static int win_alloc_firstwin(win_T *oldwin);
36static void new_frame(win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010037static tabpage_T *alloc_tabpage(void);
38static int leave_tabpage(buf_T *new_curbuf, int trigger_leave_autocmds);
39static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds);
40static void frame_fix_height(win_T *wp);
41static int frame_minheight(frame_T *topfrp, win_T *next_curwin);
Bram Moolenaarc917da42016-07-19 22:31:36 +020042static void win_enter_ext(win_T *wp, int undo_sync, int no_curwin, int trigger_new_autocmds, int trigger_enter_autocmds, int trigger_leave_autocmds);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010043static void win_free(win_T *wp, tabpage_T *tp);
44static void frame_append(frame_T *after, frame_T *frp);
45static void frame_insert(frame_T *before, frame_T *frp);
46static void frame_remove(frame_T *frp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010047static void win_goto_ver(int up, long count);
48static void win_goto_hor(int left, long count);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010049static void frame_add_height(frame_T *frp, int n);
50static void last_status_rec(frame_T *fr, int statusline);
Bram Moolenaar071d4272004-06-13 20:20:40 +000051
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010052static void make_snapshot_rec(frame_T *fr, frame_T **frp);
53static void clear_snapshot(tabpage_T *tp, int idx);
54static void clear_snapshot_rec(frame_T *fr);
55static int check_snapshot_rec(frame_T *sn, frame_T *fr);
56static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000057
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010058static int frame_check_height(frame_T *topfrp, int height);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010059static int frame_check_width(frame_T *topfrp, int width);
Bram Moolenaarb893ac22013-06-26 14:04:47 +020060
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010061static win_T *win_alloc(win_T *after, int hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +000062
Bram Moolenaarb6799ac2007-05-10 16:44:05 +000063#define NOWIN (win_T *)-1 /* non-existing window */
Bram Moolenaar071d4272004-06-13 20:20:40 +000064
Bram Moolenaar4033c552017-09-16 20:54:51 +020065#define ROWS_AVAIL (Rows - p_ch - tabline_height())
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000066
67static char *m_onlyone = N_("Already only one window");
68
Bram Moolenaar071d4272004-06-13 20:20:40 +000069/*
70 * all CTRL-W window commands are handled here, called from normal_cmd().
71 */
72 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +010073do_window(
74 int nchar,
75 long Prenum,
76 int xchar) /* extra char from ":wincmd gx" or NUL */
Bram Moolenaar071d4272004-06-13 20:20:40 +000077{
78 long Prenum1;
79 win_T *wp;
80#if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
81 char_u *ptr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +000082 linenr_T lnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +000083#endif
84#ifdef FEAT_FIND_ID
85 int type = FIND_DEFINE;
86 int len;
87#endif
88 char_u cbuf[40];
89
90 if (Prenum == 0)
91 Prenum1 = 1;
92 else
93 Prenum1 = Prenum;
94
95#ifdef FEAT_CMDWIN
Bram Moolenaar6f470022018-04-10 18:47:20 +020096# define CHECK_CMDWIN \
97 do { \
98 if (cmdwin_type != 0) \
99 { \
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100100 emsg(_(e_cmdwin)); \
Bram Moolenaar6f470022018-04-10 18:47:20 +0200101 return; \
102 } \
103 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104#else
Bram Moolenaar6f470022018-04-10 18:47:20 +0200105# define CHECK_CMDWIN do { /**/ } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106#endif
107
108 switch (nchar)
109 {
110/* split current window in two parts, horizontally */
111 case 'S':
112 case Ctrl_S:
113 case 's':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200114 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000116#ifdef FEAT_QUICKFIX
117 /* When splitting the quickfix window open a new buffer in it,
118 * don't replicate the quickfix buffer. */
119 if (bt_quickfix(curbuf))
120 goto newwindow;
121#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122#ifdef FEAT_GUI
123 need_mouse_correct = TRUE;
124#endif
Bram Moolenaarcde88542015-08-11 19:14:00 +0200125 (void)win_split((int)Prenum, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000126 break;
127
Bram Moolenaar071d4272004-06-13 20:20:40 +0000128/* split current window in two parts, vertically */
129 case Ctrl_V:
130 case 'v':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200131 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100133#ifdef FEAT_QUICKFIX
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000134 /* When splitting the quickfix window open a new buffer in it,
135 * don't replicate the quickfix buffer. */
136 if (bt_quickfix(curbuf))
137 goto newwindow;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100138#endif
139#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140 need_mouse_correct = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100141#endif
Bram Moolenaarcde88542015-08-11 19:14:00 +0200142 (void)win_split((int)Prenum, WSP_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
145/* split current window and edit alternate file */
146 case Ctrl_HAT:
147 case '^':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200148 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar1bbb6192018-11-10 16:02:01 +0100150
151 if (buflist_findnr(Prenum == 0
152 ? curwin->w_alt_fnum : Prenum) == NULL)
153 {
154 if (Prenum == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100155 emsg(_(e_noalt));
Bram Moolenaar1bbb6192018-11-10 16:02:01 +0100156 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100157 semsg(_("E92: Buffer %ld not found"), Prenum);
Bram Moolenaar1bbb6192018-11-10 16:02:01 +0100158 break;
159 }
160
161 if (!curbuf_locked() && win_split(0, 0) == OK)
162 (void)buflist_getfile(
163 Prenum == 0 ? curwin->w_alt_fnum : Prenum,
164 (linenr_T)0, GETF_ALT, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165 break;
166
167/* open new window */
168 case Ctrl_N:
169 case 'n':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200170 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000172#ifdef FEAT_QUICKFIX
173newwindow:
174#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 if (Prenum)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000176 /* window height */
177 vim_snprintf((char *)cbuf, sizeof(cbuf) - 5, "%ld", Prenum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178 else
179 cbuf[0] = NUL;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100180#if defined(FEAT_QUICKFIX)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000181 if (nchar == 'v' || nchar == Ctrl_V)
182 STRCAT(cbuf, "v");
183#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184 STRCAT(cbuf, "new");
185 do_cmdline_cmd(cbuf);
186 break;
187
188/* quit current window */
189 case Ctrl_Q:
190 case 'q':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100192 cmd_with_count("quit", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100193 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194 break;
195
196/* close current window */
197 case Ctrl_C:
198 case 'c':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100200 cmd_with_count("close", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100201 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202 break;
203
Bram Moolenaar4033c552017-09-16 20:54:51 +0200204#if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205/* close preview window */
206 case Ctrl_Z:
207 case 'z':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200208 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 do_cmdline_cmd((char_u *)"pclose");
211 break;
212
213/* cursor to preview window */
214 case 'P':
Bram Moolenaar29323592016-07-24 22:04:11 +0200215 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216 if (wp->w_p_pvw)
217 break;
218 if (wp == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100219 emsg(_("E441: There is no preview window"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 else
221 win_goto(wp);
222 break;
223#endif
224
225/* close all but current window */
226 case Ctrl_O:
227 case 'o':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200228 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100230 cmd_with_count("only", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100231 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 break;
233
234/* cursor to next window with wrap around */
235 case Ctrl_W:
236 case 'w':
237/* cursor to previous window with wrap around */
238 case 'W':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200239 CHECK_CMDWIN;
Bram Moolenaara1f4cb92016-11-06 15:25:42 +0100240 if (ONE_WINDOW && Prenum != 1) /* just one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 beep_flush();
242 else
243 {
244 if (Prenum) /* go to specified window */
245 {
246 for (wp = firstwin; --Prenum > 0; )
247 {
248 if (wp->w_next == NULL)
249 break;
250 else
251 wp = wp->w_next;
252 }
253 }
254 else
255 {
256 if (nchar == 'W') /* go to previous window */
257 {
258 wp = curwin->w_prev;
259 if (wp == NULL)
260 wp = lastwin; /* wrap around */
261 }
262 else /* go to next window */
263 {
264 wp = curwin->w_next;
265 if (wp == NULL)
266 wp = firstwin; /* wrap around */
267 }
268 }
269 win_goto(wp);
270 }
271 break;
272
273/* cursor to window below */
274 case 'j':
275 case K_DOWN:
276 case Ctrl_J:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200277 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278 win_goto_ver(FALSE, Prenum1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279 break;
280
281/* cursor to window above */
282 case 'k':
283 case K_UP:
284 case Ctrl_K:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200285 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286 win_goto_ver(TRUE, Prenum1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287 break;
288
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289/* cursor to left window */
290 case 'h':
291 case K_LEFT:
292 case Ctrl_H:
293 case K_BS:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200294 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 win_goto_hor(TRUE, Prenum1);
296 break;
297
298/* cursor to right window */
299 case 'l':
300 case K_RIGHT:
301 case Ctrl_L:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200302 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000303 win_goto_hor(FALSE, Prenum1);
304 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000306/* move window to new tab page */
307 case 'T':
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000308 if (one_window())
Bram Moolenaar32526b32019-01-19 17:43:09 +0100309 msg(_(m_onlyone));
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000310 else
311 {
312 tabpage_T *oldtab = curtab;
313 tabpage_T *newtab;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000314
315 /* First create a new tab with the window, then go back to
316 * the old tab and close the window there. */
Bram Moolenaar89d40322006-08-29 15:30:07 +0000317 wp = curwin;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000318 if (win_new_tabpage((int)Prenum) == OK
319 && valid_tabpage(oldtab))
320 {
321 newtab = curtab;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200322 goto_tabpage_tp(oldtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000323 if (curwin == wp)
324 win_close(curwin, FALSE);
325 if (valid_tabpage(newtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200326 goto_tabpage_tp(newtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000327 }
328 }
329 break;
330
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331/* cursor to top-left window */
332 case 't':
333 case Ctrl_T:
334 win_goto(firstwin);
335 break;
336
337/* cursor to bottom-right window */
338 case 'b':
339 case Ctrl_B:
340 win_goto(lastwin);
341 break;
342
343/* cursor to last accessed (previous) window */
344 case 'p':
345 case Ctrl_P:
Bram Moolenaar3dda7db2016-04-03 21:22:58 +0200346 if (!win_valid(prevwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 beep_flush();
348 else
349 win_goto(prevwin);
350 break;
351
352/* exchange current and next window */
353 case 'x':
354 case Ctrl_X:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200355 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 win_exchange(Prenum);
357 break;
358
359/* rotate windows downwards */
360 case Ctrl_R:
361 case 'r':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200362 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 win_rotate(FALSE, (int)Prenum1); /* downwards */
365 break;
366
367/* rotate windows upwards */
368 case 'R':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200369 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 win_rotate(TRUE, (int)Prenum1); /* upwards */
372 break;
373
374/* move window to the very top/bottom/left/right */
375 case 'K':
376 case 'J':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 case 'H':
378 case 'L':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200379 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 win_totop((int)Prenum,
381 ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
382 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
383 break;
384
385/* make all windows the same height */
386 case '=':
387#ifdef FEAT_GUI
388 need_mouse_correct = TRUE;
389#endif
390 win_equal(NULL, FALSE, 'b');
391 break;
392
393/* increase current window height */
394 case '+':
395#ifdef FEAT_GUI
396 need_mouse_correct = TRUE;
397#endif
398 win_setheight(curwin->w_height + (int)Prenum1);
399 break;
400
401/* decrease current window height */
402 case '-':
403#ifdef FEAT_GUI
404 need_mouse_correct = TRUE;
405#endif
406 win_setheight(curwin->w_height - (int)Prenum1);
407 break;
408
409/* set current window height */
410 case Ctrl__:
411 case '_':
412#ifdef FEAT_GUI
413 need_mouse_correct = TRUE;
414#endif
415 win_setheight(Prenum ? (int)Prenum : 9999);
416 break;
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/* increase current window width */
419 case '>':
420#ifdef FEAT_GUI
421 need_mouse_correct = TRUE;
422#endif
423 win_setwidth(curwin->w_width + (int)Prenum1);
424 break;
425
426/* decrease current window width */
427 case '<':
428#ifdef FEAT_GUI
429 need_mouse_correct = TRUE;
430#endif
431 win_setwidth(curwin->w_width - (int)Prenum1);
432 break;
433
434/* set current window width */
435 case '|':
436#ifdef FEAT_GUI
437 need_mouse_correct = TRUE;
438#endif
439 win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
440 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441
442/* jump to tag and split window if tag exists (in preview window) */
443#if defined(FEAT_QUICKFIX)
444 case '}':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200445 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 if (Prenum)
447 g_do_tagpreview = Prenum;
448 else
449 g_do_tagpreview = p_pvh;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450#endif
Bram Moolenaar2f40d122017-10-24 21:49:36 +0200451 /* FALLTHROUGH */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452 case ']':
453 case Ctrl_RSB:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200454 CHECK_CMDWIN;
Bram Moolenaard355c502014-09-23 13:48:43 +0200455 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 if (Prenum)
457 postponed_split = Prenum;
458 else
459 postponed_split = -1;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200460#ifdef FEAT_QUICKFIX
Bram Moolenaar56095e12014-10-09 10:44:37 +0200461 if (nchar != '}')
462 g_do_tagpreview = 0;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200463#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464
Bram Moolenaard355c502014-09-23 13:48:43 +0200465 /* Execute the command right here, required when "wincmd ]"
466 * was used in a function. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467 do_nv_ident(Ctrl_RSB, NUL);
468 break;
469
470#ifdef FEAT_SEARCHPATH
471/* edit file name under cursor in a new window */
472 case 'f':
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000473 case 'F':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000474 case Ctrl_F:
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000475wingotofile:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200476 CHECK_CMDWIN;
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000477
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000478 ptr = grab_file_name(Prenum1, &lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 if (ptr != NULL)
480 {
Bram Moolenaar5d2ca042016-06-26 17:11:21 +0200481 tabpage_T *oldtab = curtab;
482 win_T *oldwin = curwin;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000483# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484 need_mouse_correct = TRUE;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000485# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 setpcmark();
487 if (win_split(0, 0) == OK)
488 {
Bram Moolenaar3368ea22010-09-21 16:56:35 +0200489 RESET_BINDING(curwin);
Bram Moolenaar5d2ca042016-06-26 17:11:21 +0200490 if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
491 ECMD_HIDE, NULL) == FAIL)
492 {
493 /* Failed to open the file, close the window
494 * opened for it. */
495 win_close(curwin, FALSE);
496 goto_tabpage_win(oldtab, oldwin);
497 }
498 else if (nchar == 'F' && lnum >= 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000499 {
500 curwin->w_cursor.lnum = lnum;
501 check_cursor_lnum();
502 beginline(BL_SOL | BL_FIX);
503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 }
505 vim_free(ptr);
506 }
507 break;
508#endif
509
510#ifdef FEAT_FIND_ID
Bram Moolenaarb6799ac2007-05-10 16:44:05 +0000511/* Go to the first occurrence of the identifier under cursor along path in a
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 * new window -- webb
513 */
514 case 'i': /* Go to any match */
515 case Ctrl_I:
516 type = FIND_ANY;
517 /* FALLTHROUGH */
518 case 'd': /* Go to definition, using 'define' */
519 case Ctrl_D:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200520 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
522 break;
523 find_pattern_in_path(ptr, 0, len, TRUE,
524 Prenum == 0 ? TRUE : FALSE, type,
525 Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
526 curwin->w_set_curswant = TRUE;
527 break;
528#endif
529
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200530/* Quickfix window only: view the result under the cursor in a new split. */
531#if defined(FEAT_QUICKFIX)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000532 case K_KENTER:
533 case CAR:
Bram Moolenaar05159a02005-02-26 23:04:13 +0000534 if (bt_quickfix(curbuf))
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200535 qf_view_result(TRUE);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000536 break;
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200537#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000538
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539/* CTRL-W g extended commands */
540 case 'g':
541 case Ctrl_G:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200542 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543#ifdef USE_ON_FLY_SCROLL
544 dont_scroll = TRUE; /* disallow scrolling here */
545#endif
546 ++no_mapping;
547 ++allow_keys; /* no mapping for xchar, but allow key codes */
548 if (xchar == NUL)
Bram Moolenaar61abfd12007-09-13 16:26:47 +0000549 xchar = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 LANGMAP_ADJUST(xchar, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 --no_mapping;
552 --allow_keys;
553#ifdef FEAT_CMDL_INFO
554 (void)add_to_showcmd(xchar);
555#endif
556 switch (xchar)
557 {
558#if defined(FEAT_QUICKFIX)
559 case '}':
560 xchar = Ctrl_RSB;
561 if (Prenum)
562 g_do_tagpreview = Prenum;
563 else
564 g_do_tagpreview = p_pvh;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565#endif
Bram Moolenaar2f40d122017-10-24 21:49:36 +0200566 /* FALLTHROUGH */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 case ']':
568 case Ctrl_RSB:
Bram Moolenaard355c502014-09-23 13:48:43 +0200569 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 if (Prenum)
571 postponed_split = Prenum;
572 else
573 postponed_split = -1;
574
575 /* Execute the command right here, required when
576 * "wincmd g}" was used in a function. */
577 do_nv_ident('g', xchar);
578 break;
579
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000580#ifdef FEAT_SEARCHPATH
581 case 'f': /* CTRL-W gf: "gf" in a new tab page */
Bram Moolenaar57657d82006-04-21 22:12:41 +0000582 case 'F': /* CTRL-W gF: "gF" in a new tab page */
Bram Moolenaar6d1dcff2010-01-27 20:26:46 +0100583 cmdmod.tab = tabpage_index(curtab) + 1;
Bram Moolenaar57657d82006-04-21 22:12:41 +0000584 nchar = xchar;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000585 goto wingotofile;
586#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587 default:
588 beep_flush();
589 break;
590 }
591 break;
592
593 default: beep_flush();
594 break;
595 }
596}
597
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100598/*
599 * Figure out the address type for ":wnncmd".
600 */
601 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100602get_wincmd_addr_type(char_u *arg, exarg_T *eap)
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100603{
604 switch (*arg)
605 {
606 case 'S':
607 case Ctrl_S:
608 case 's':
609 case Ctrl_N:
610 case 'n':
611 case 'j':
612 case Ctrl_J:
613 case 'k':
614 case Ctrl_K:
615 case 'T':
616 case Ctrl_R:
617 case 'r':
618 case 'R':
619 case 'K':
620 case 'J':
621 case '+':
622 case '-':
623 case Ctrl__:
624 case '_':
625 case '|':
626 case ']':
627 case Ctrl_RSB:
628 case 'g':
629 case Ctrl_G:
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100630 case Ctrl_V:
631 case 'v':
632 case 'h':
633 case Ctrl_H:
634 case 'l':
635 case Ctrl_L:
636 case 'H':
637 case 'L':
638 case '>':
639 case '<':
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100640#if defined(FEAT_QUICKFIX)
641 case '}':
642#endif
643#ifdef FEAT_SEARCHPATH
644 case 'f':
645 case 'F':
646 case Ctrl_F:
647#endif
648#ifdef FEAT_FIND_ID
649 case 'i':
650 case Ctrl_I:
651 case 'd':
652 case Ctrl_D:
653#endif
654 /* window size or any count */
655 eap->addr_type = ADDR_LINES;
656 break;
657
658 case Ctrl_HAT:
659 case '^':
660 /* buffer number */
661 eap->addr_type = ADDR_BUFFERS;
662 break;
663
664 case Ctrl_Q:
665 case 'q':
666 case Ctrl_C:
667 case 'c':
668 case Ctrl_O:
669 case 'o':
670 case Ctrl_W:
671 case 'w':
672 case 'W':
673 case 'x':
674 case Ctrl_X:
675 /* window number */
676 eap->addr_type = ADDR_WINDOWS;
677 break;
678
679#if defined(FEAT_QUICKFIX)
680 case Ctrl_Z:
681 case 'z':
682 case 'P':
683#endif
684 case 't':
685 case Ctrl_T:
686 case 'b':
687 case Ctrl_B:
688 case 'p':
689 case Ctrl_P:
690 case '=':
691 case CAR:
692 /* no count */
693 eap->addr_type = 0;
694 break;
695 }
696}
697
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100698 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100699cmd_with_count(
700 char *cmd,
701 char_u *bufp,
702 size_t bufsize,
703 long Prenum)
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100704{
705 size_t len = STRLEN(cmd);
706
707 STRCPY(bufp, cmd);
708 if (Prenum > 0)
709 vim_snprintf((char *)bufp + len, bufsize - len, "%ld", Prenum);
710}
711
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712/*
713 * split the current window, implements CTRL-W s and :split
714 *
715 * "size" is the height or width for the new window, 0 to use half of current
716 * height or width.
717 *
718 * "flags":
719 * WSP_ROOM: require enough room for new window
720 * WSP_VERT: vertical split.
721 * WSP_TOP: open window at the top-left of the shell (help window).
722 * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
723 * WSP_HELP: creating the help window, keep layout snapshot
724 *
725 * return FAIL for failure, OK otherwise
726 */
727 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100728win_split(int size, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729{
Bram Moolenaar80a94a52006-02-23 21:26:58 +0000730 /* When the ":tab" modifier was used open a new tab page instead. */
731 if (may_open_tabpage() == OK)
732 return OK;
733
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 /* Add flags from ":vertical", ":topleft" and ":botright". */
735 flags |= cmdmod.split;
736 if ((flags & WSP_TOP) && (flags & WSP_BOT))
737 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100738 emsg(_("E442: Can't split topleft and botright at the same time"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 return FAIL;
740 }
741
742 /* When creating the help window make a snapshot of the window layout.
743 * Otherwise clear the snapshot, it's now invalid. */
744 if (flags & WSP_HELP)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000745 make_snapshot(SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000747 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748
749 return win_split_ins(size, flags, NULL, 0);
750}
751
752/*
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100753 * When "new_wp" is NULL: split the current window in two.
754 * When "new_wp" is not NULL: insert this window at the far
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 * top/left/right/bottom.
756 * return FAIL for failure, OK otherwise
757 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000758 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100759win_split_ins(
760 int size,
761 int flags,
762 win_T *new_wp,
763 int dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764{
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100765 win_T *wp = new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 win_T *oldwin;
767 int new_size = size;
768 int i;
769 int need_status = 0;
770 int do_equal = FALSE;
771 int needed;
772 int available;
773 int oldwin_height = 0;
774 int layout;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200775 frame_T *frp, *curfrp, *frp2, *prevfrp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 int before;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200777 int minheight;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200778 int wmh1;
Bram Moolenaar98da6ec2018-04-13 22:15:46 +0200779 int did_set_fraction = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780
781 if (flags & WSP_TOP)
782 oldwin = firstwin;
783 else if (flags & WSP_BOT)
784 oldwin = lastwin;
785 else
786 oldwin = curwin;
787
788 /* add a status line when p_ls == 1 and splitting the first window */
Bram Moolenaar459ca562016-11-10 18:16:33 +0100789 if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 {
Bram Moolenaar415a6932017-12-05 20:31:07 +0100791 if (VISIBLE_HEIGHT(oldwin) <= p_wmh && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100793 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 return FAIL;
795 }
796 need_status = STATUS_HEIGHT;
797 }
798
Bram Moolenaaree79cbc2007-05-02 19:50:14 +0000799#ifdef FEAT_GUI
800 /* May be needed for the scrollbars that are going to change. */
801 if (gui.in_use)
802 out_flush();
803#endif
804
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 if (flags & WSP_VERT)
806 {
Bram Moolenaara0485492014-07-16 23:39:54 +0200807 int wmw1;
808 int minwidth;
809
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 layout = FR_ROW;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811
812 /*
813 * Check if we are able to split the current window and compute its
814 * width.
815 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200816 /* Current window requires at least 1 space. */
817 wmw1 = (p_wmw == 0 ? 1 : p_wmw);
818 needed = wmw1 + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200820 needed += p_wiw - wmw1;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200821 if (flags & (WSP_BOT | WSP_TOP))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200823 minwidth = frame_minwidth(topframe, NOWIN);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 available = topframe->fr_width;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200825 needed += minwidth;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200827 else if (p_ea)
828 {
829 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
830 prevfrp = oldwin->w_frame;
831 for (frp = oldwin->w_frame->fr_parent; frp != NULL;
832 frp = frp->fr_parent)
833 {
834 if (frp->fr_layout == FR_ROW)
Bram Moolenaar3d1491e2018-12-22 17:07:50 +0100835 FOR_ALL_FRAMES(frp2, frp->fr_child)
Bram Moolenaar54368f22014-07-23 15:21:20 +0200836 if (frp2 != prevfrp)
837 minwidth += frame_minwidth(frp2, NOWIN);
838 prevfrp = frp;
839 }
840 available = topframe->fr_width;
841 needed += minwidth;
842 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 else
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200844 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200845 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
846 available = oldwin->w_frame->fr_width;
847 needed += minwidth;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200848 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100849 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100851 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 return FAIL;
853 }
854 if (new_size == 0)
855 new_size = oldwin->w_width / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200856 if (new_size > available - minwidth - 1)
857 new_size = available - minwidth - 1;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200858 if (new_size < wmw1)
859 new_size = wmw1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860
861 /* if it doesn't fit in the current window, need win_equal() */
862 if (oldwin->w_width - new_size - 1 < p_wmw)
863 do_equal = TRUE;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +0000864
865 /* We don't like to take lines for the new window from a
866 * 'winfixwidth' window. Take them from a window to the left or right
Bram Moolenaar38e34832017-03-19 20:22:36 +0100867 * instead, if possible. Add one for the separator. */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +0000868 if (oldwin->w_p_wfw)
Bram Moolenaar38e34832017-03-19 20:22:36 +0100869 win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
Bram Moolenaar67f71312007-08-12 14:55:56 +0000870
871 /* Only make all windows the same width if one of them (except oldwin)
872 * is wider than one of the split windows. */
873 if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
874 && oldwin->w_frame->fr_parent != NULL)
875 {
876 frp = oldwin->w_frame->fr_parent->fr_child;
877 while (frp != NULL)
878 {
879 if (frp->fr_win != oldwin && frp->fr_win != NULL
880 && (frp->fr_win->w_width > new_size
881 || frp->fr_win->w_width > oldwin->w_width
Bram Moolenaardf46f6f2014-11-19 13:40:08 +0100882 - new_size - 1))
Bram Moolenaar67f71312007-08-12 14:55:56 +0000883 {
884 do_equal = TRUE;
885 break;
886 }
887 frp = frp->fr_next;
888 }
889 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 }
891 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892 {
893 layout = FR_COL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894
895 /*
896 * Check if we are able to split the current window and compute its
897 * height.
898 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200899 /* Current window requires at least 1 space. */
Bram Moolenaar415a6932017-12-05 20:31:07 +0100900 wmh1 = (p_wmh == 0 ? 1 : p_wmh) + WINBAR_HEIGHT(curwin);
Bram Moolenaar1f538352014-07-16 18:19:27 +0200901 needed = wmh1 + STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200903 needed += p_wh - wmh1;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200904 if (flags & (WSP_BOT | WSP_TOP))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200906 minheight = frame_minheight(topframe, NOWIN) + need_status;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 available = topframe->fr_height;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200908 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200910 else if (p_ea)
911 {
912 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
913 prevfrp = oldwin->w_frame;
914 for (frp = oldwin->w_frame->fr_parent; frp != NULL;
915 frp = frp->fr_parent)
916 {
917 if (frp->fr_layout == FR_COL)
Bram Moolenaar3d1491e2018-12-22 17:07:50 +0100918 FOR_ALL_FRAMES(frp2, frp->fr_child)
Bram Moolenaar54368f22014-07-23 15:21:20 +0200919 if (frp2 != prevfrp)
920 minheight += frame_minheight(frp2, NOWIN);
921 prevfrp = frp;
922 }
923 available = topframe->fr_height;
924 needed += minheight;
925 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 else
927 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200928 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
929 available = oldwin->w_frame->fr_height;
930 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100932 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000933 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100934 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 return FAIL;
936 }
937 oldwin_height = oldwin->w_height;
938 if (need_status)
939 {
940 oldwin->w_status_height = STATUS_HEIGHT;
941 oldwin_height -= STATUS_HEIGHT;
942 }
943 if (new_size == 0)
944 new_size = oldwin_height / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200945 if (new_size > available - minheight - STATUS_HEIGHT)
946 new_size = available - minheight - STATUS_HEIGHT;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200947 if (new_size < wmh1)
948 new_size = wmh1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949
950 /* if it doesn't fit in the current window, need win_equal() */
951 if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
952 do_equal = TRUE;
953
954 /* We don't like to take lines for the new window from a
955 * 'winfixheight' window. Take them from a window above or below
956 * instead, if possible. */
957 if (oldwin->w_p_wfh)
958 {
Bram Moolenaar98da6ec2018-04-13 22:15:46 +0200959 /* Set w_fraction now so that the cursor keeps the same relative
960 * vertical position using the old height. */
961 set_fraction(oldwin);
962 did_set_fraction = TRUE;
963
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
965 oldwin);
966 oldwin_height = oldwin->w_height;
967 if (need_status)
968 oldwin_height -= STATUS_HEIGHT;
969 }
Bram Moolenaar67f71312007-08-12 14:55:56 +0000970
971 /* Only make all windows the same height if one of them (except oldwin)
972 * is higher than one of the split windows. */
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100973 if (!do_equal && p_ea && size == 0 && *p_ead != 'h'
Bram Moolenaar67f71312007-08-12 14:55:56 +0000974 && oldwin->w_frame->fr_parent != NULL)
975 {
976 frp = oldwin->w_frame->fr_parent->fr_child;
977 while (frp != NULL)
978 {
979 if (frp->fr_win != oldwin && frp->fr_win != NULL
980 && (frp->fr_win->w_height > new_size
981 || frp->fr_win->w_height > oldwin_height - new_size
982 - STATUS_HEIGHT))
983 {
984 do_equal = TRUE;
985 break;
986 }
987 frp = frp->fr_next;
988 }
989 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 }
991
992 /*
993 * allocate new window structure and link it in the window list
994 */
995 if ((flags & WSP_TOP) == 0
996 && ((flags & WSP_BOT)
997 || (flags & WSP_BELOW)
998 || (!(flags & WSP_ABOVE)
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100999 && ( (flags & WSP_VERT) ? p_spr : p_sb))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000 {
1001 /* new window below/right of current one */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001002 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001003 wp = win_alloc(oldwin, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004 else
1005 win_append(oldwin, wp);
1006 }
1007 else
1008 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001009 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001010 wp = win_alloc(oldwin->w_prev, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 else
1012 win_append(oldwin->w_prev, wp);
1013 }
1014
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001015 if (new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 {
1017 if (wp == NULL)
1018 return FAIL;
1019
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001020 new_frame(wp);
1021 if (wp->w_frame == NULL)
1022 {
1023 win_free(wp, NULL);
1024 return FAIL;
1025 }
1026
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001027 /* make the contents of the new window the same as the current one */
Bram Moolenaar884ae642009-02-22 01:37:59 +00001028 win_init(wp, curwin, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 }
1030
1031 /*
1032 * Reorganise the tree of frames to insert the new window.
1033 */
1034 if (flags & (WSP_TOP | WSP_BOT))
1035 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
1037 || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 {
1039 curfrp = topframe->fr_child;
1040 if (flags & WSP_BOT)
1041 while (curfrp->fr_next != NULL)
1042 curfrp = curfrp->fr_next;
1043 }
1044 else
1045 curfrp = topframe;
1046 before = (flags & WSP_TOP);
1047 }
1048 else
1049 {
1050 curfrp = oldwin->w_frame;
1051 if (flags & WSP_BELOW)
1052 before = FALSE;
1053 else if (flags & WSP_ABOVE)
1054 before = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001055 else if (flags & WSP_VERT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 before = !p_spr;
1057 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 before = !p_sb;
1059 }
1060 if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
1061 {
1062 /* Need to create a new frame in the tree to make a branch. */
1063 frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
1064 *frp = *curfrp;
1065 curfrp->fr_layout = layout;
1066 frp->fr_parent = curfrp;
1067 frp->fr_next = NULL;
1068 frp->fr_prev = NULL;
1069 curfrp->fr_child = frp;
1070 curfrp->fr_win = NULL;
1071 curfrp = frp;
1072 if (frp->fr_win != NULL)
1073 oldwin->w_frame = frp;
1074 else
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01001075 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 frp->fr_parent = curfrp;
1077 }
1078
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001079 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001080 frp = wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 else
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001082 frp = new_wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001083 frp->fr_parent = curfrp->fr_parent;
1084
1085 /* Insert the new frame at the right place in the frame list. */
1086 if (before)
1087 frame_insert(curfrp, frp);
1088 else
1089 frame_append(curfrp, frp);
1090
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001091 /* Set w_fraction now so that the cursor keeps the same relative
1092 * vertical position. */
Bram Moolenaar98da6ec2018-04-13 22:15:46 +02001093 if (!did_set_fraction)
1094 set_fraction(oldwin);
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001095 wp->w_fraction = oldwin->w_fraction;
1096
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 if (flags & WSP_VERT)
1098 {
1099 wp->w_p_scr = curwin->w_p_scr;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001100
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 if (need_status)
1102 {
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001103 win_new_height(oldwin, oldwin->w_height - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 oldwin->w_status_height = need_status;
1105 }
1106 if (flags & (WSP_TOP | WSP_BOT))
1107 {
1108 /* set height and row of new window to full height */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001109 wp->w_winrow = tabline_height();
Bram Moolenaard326ad62017-09-18 20:31:41 +02001110 win_new_height(wp, curfrp->fr_height - (p_ls > 0)
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01001111 - WINBAR_HEIGHT(wp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 wp->w_status_height = (p_ls > 0);
1113 }
1114 else
1115 {
1116 /* height and row of new window is same as current window */
1117 wp->w_winrow = oldwin->w_winrow;
Bram Moolenaar415a6932017-12-05 20:31:07 +01001118 win_new_height(wp, VISIBLE_HEIGHT(oldwin));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119 wp->w_status_height = oldwin->w_status_height;
1120 }
1121 frp->fr_height = curfrp->fr_height;
1122
1123 /* "new_size" of the current window goes to the new window, use
1124 * one column for the vertical separator */
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001125 win_new_width(wp, new_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 if (before)
1127 wp->w_vsep_width = 1;
1128 else
1129 {
1130 wp->w_vsep_width = oldwin->w_vsep_width;
1131 oldwin->w_vsep_width = 1;
1132 }
1133 if (flags & (WSP_TOP | WSP_BOT))
1134 {
1135 if (flags & WSP_BOT)
1136 frame_add_vsep(curfrp);
1137 /* Set width of neighbor frame */
1138 frame_new_width(curfrp, curfrp->fr_width
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001139 - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
1140 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 }
1142 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001143 win_new_width(oldwin, oldwin->w_width - (new_size + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001144 if (before) /* new window left of current one */
1145 {
1146 wp->w_wincol = oldwin->w_wincol;
1147 oldwin->w_wincol += new_size + 1;
1148 }
1149 else /* new window right of current one */
1150 wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
1151 frame_fix_width(oldwin);
1152 frame_fix_width(wp);
1153 }
1154 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 {
1156 /* width and column of new window is same as current window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001157 if (flags & (WSP_TOP | WSP_BOT))
1158 {
1159 wp->w_wincol = 0;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001160 win_new_width(wp, Columns);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 wp->w_vsep_width = 0;
1162 }
1163 else
1164 {
1165 wp->w_wincol = oldwin->w_wincol;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001166 win_new_width(wp, oldwin->w_width);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 wp->w_vsep_width = oldwin->w_vsep_width;
1168 }
1169 frp->fr_width = curfrp->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170
1171 /* "new_size" of the current window goes to the new window, use
1172 * one row for the status line */
1173 win_new_height(wp, new_size);
1174 if (flags & (WSP_TOP | WSP_BOT))
Bram Moolenaar991dea32016-05-24 11:31:32 +02001175 {
Bram Moolenaard326ad62017-09-18 20:31:41 +02001176 int new_fr_height = curfrp->fr_height - new_size
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01001177 + WINBAR_HEIGHT(wp) ;
Bram Moolenaar991dea32016-05-24 11:31:32 +02001178
1179 if (!((flags & WSP_BOT) && p_ls == 0))
1180 new_fr_height -= STATUS_HEIGHT;
1181 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
1182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183 else
1184 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1185 if (before) /* new window above current one */
1186 {
1187 wp->w_winrow = oldwin->w_winrow;
1188 wp->w_status_height = STATUS_HEIGHT;
1189 oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
1190 }
1191 else /* new window below current one */
1192 {
Bram Moolenaar415a6932017-12-05 20:31:07 +01001193 wp->w_winrow = oldwin->w_winrow + VISIBLE_HEIGHT(oldwin)
1194 + STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001195 wp->w_status_height = oldwin->w_status_height;
Bram Moolenaar991dea32016-05-24 11:31:32 +02001196 if (!(flags & WSP_BOT))
1197 oldwin->w_status_height = STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001199 if (flags & WSP_BOT)
1200 frame_add_statusline(curfrp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201 frame_fix_height(wp);
1202 frame_fix_height(oldwin);
1203 }
1204
1205 if (flags & (WSP_TOP | WSP_BOT))
1206 (void)win_comp_pos();
1207
1208 /*
1209 * Both windows need redrawing
1210 */
1211 redraw_win_later(wp, NOT_VALID);
1212 wp->w_redr_status = TRUE;
1213 redraw_win_later(oldwin, NOT_VALID);
1214 oldwin->w_redr_status = TRUE;
1215
1216 if (need_status)
1217 {
1218 msg_row = Rows - 1;
1219 msg_col = sc_col;
1220 msg_clr_eos_force(); /* Old command/ruler may still be there */
1221 comp_col();
1222 msg_row = Rows - 1;
1223 msg_col = 0; /* put position back at start of line */
1224 }
1225
1226 /*
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001227 * equalize the window sizes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228 */
1229 if (do_equal || dir != 0)
1230 win_equal(wp, TRUE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001232 : dir == 'h' ? 'b' : 'v');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233
1234 /* Don't change the window height/width to 'winheight' / 'winwidth' if a
1235 * size was given. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 if (flags & WSP_VERT)
1237 {
1238 i = p_wiw;
1239 if (size != 0)
1240 p_wiw = size;
1241
1242# ifdef FEAT_GUI
1243 /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
1244 if (gui.in_use)
1245 gui_init_which_components(NULL);
1246# endif
1247 }
1248 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 {
1250 i = p_wh;
1251 if (size != 0)
1252 p_wh = size;
1253 }
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001254
Bram Moolenaar23fb7a92014-07-30 14:05:00 +02001255#ifdef FEAT_JUMPLIST
1256 /* Keep same changelist position in new window. */
1257 wp->w_changelistidx = oldwin->w_changelistidx;
1258#endif
1259
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001260 /*
1261 * make the new window the current window
1262 */
Bram Moolenaarc917da42016-07-19 22:31:36 +02001263 win_enter_ext(wp, FALSE, FALSE, TRUE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264 if (flags & WSP_VERT)
1265 p_wiw = i;
1266 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001267 p_wh = i;
1268
1269 return OK;
1270}
1271
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001272
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001273/*
1274 * Initialize window "newp" from window "oldp".
1275 * Used when splitting a window and when creating a new tab page.
1276 * The windows will both edit the same buffer.
Bram Moolenaar884ae642009-02-22 01:37:59 +00001277 * WSP_NEWLOC may be specified in flags to prevent the location list from
1278 * being copied.
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001279 */
1280 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001281win_init(win_T *newp, win_T *oldp, int flags UNUSED)
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001282{
1283 int i;
1284
1285 newp->w_buffer = oldp->w_buffer;
Bram Moolenaar860cae12010-06-05 23:22:07 +02001286#ifdef FEAT_SYN_HL
Bram Moolenaarfd29f462010-06-06 16:11:09 +02001287 newp->w_s = &(oldp->w_buffer->b_s);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001288#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001289 oldp->w_buffer->b_nwindows++;
1290 newp->w_cursor = oldp->w_cursor;
1291 newp->w_valid = 0;
1292 newp->w_curswant = oldp->w_curswant;
1293 newp->w_set_curswant = oldp->w_set_curswant;
1294 newp->w_topline = oldp->w_topline;
1295#ifdef FEAT_DIFF
1296 newp->w_topfill = oldp->w_topfill;
1297#endif
1298 newp->w_leftcol = oldp->w_leftcol;
1299 newp->w_pcmark = oldp->w_pcmark;
1300 newp->w_prev_pcmark = oldp->w_prev_pcmark;
1301 newp->w_alt_fnum = oldp->w_alt_fnum;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00001302 newp->w_wrow = oldp->w_wrow;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001303 newp->w_fraction = oldp->w_fraction;
1304 newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
1305#ifdef FEAT_JUMPLIST
1306 copy_jumplist(oldp, newp);
1307#endif
1308#ifdef FEAT_QUICKFIX
Bram Moolenaar884ae642009-02-22 01:37:59 +00001309 if (flags & WSP_NEWLOC)
1310 {
1311 /* Don't copy the location list. */
1312 newp->w_llist = NULL;
1313 newp->w_llist_ref = NULL;
1314 }
1315 else
Bram Moolenaar09037502018-09-25 22:08:14 +02001316 copy_loclist_stack(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001317#endif
Bram Moolenaarbd2dc342014-01-10 15:53:13 +01001318 newp->w_localdir = (oldp->w_localdir == NULL)
1319 ? NULL : vim_strsave(oldp->w_localdir);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001320
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001321 /* copy tagstack and folds */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001322 for (i = 0; i < oldp->w_tagstacklen; i++)
1323 {
1324 newp->w_tagstack[i] = oldp->w_tagstack[i];
1325 if (newp->w_tagstack[i].tagname != NULL)
1326 newp->w_tagstack[i].tagname =
1327 vim_strsave(newp->w_tagstack[i].tagname);
1328 }
1329 newp->w_tagstackidx = oldp->w_tagstackidx;
1330 newp->w_tagstacklen = oldp->w_tagstacklen;
Bram Moolenaara971b822011-09-14 14:43:25 +02001331#ifdef FEAT_FOLDING
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001332 copyFoldingState(oldp, newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001333#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001334
1335 win_init_some(newp, oldp);
Bram Moolenaar1a384422010-07-14 19:53:30 +02001336
Bram Moolenaara971b822011-09-14 14:43:25 +02001337#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02001338 check_colorcolumn(newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001339#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001340}
1341
1342/*
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02001343 * Initialize window "newp" from window "old".
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001344 * Only the essential things are copied.
1345 */
1346 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001347win_init_some(win_T *newp, win_T *oldp)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001348{
1349 /* Use the same argument list. */
1350 newp->w_alist = oldp->w_alist;
1351 ++newp->w_alist->al_refcount;
1352 newp->w_arg_idx = oldp->w_arg_idx;
1353
1354 /* copy options from existing window */
1355 win_copy_options(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001356}
1357
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359/*
Bram Moolenaare59215c2016-08-14 19:08:45 +02001360 * Check if "win" is a pointer to an existing window in the current tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361 */
1362 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001363win_valid(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364{
1365 win_T *wp;
1366
1367 if (win == NULL)
1368 return FALSE;
Bram Moolenaar29323592016-07-24 22:04:11 +02001369 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370 if (wp == win)
1371 return TRUE;
1372 return FALSE;
1373}
1374
1375/*
Bram Moolenaare59215c2016-08-14 19:08:45 +02001376 * Check if "win" is a pointer to an existing window in any tab page.
1377 */
1378 int
1379win_valid_any_tab(win_T *win)
1380{
1381 win_T *wp;
1382 tabpage_T *tp;
1383
1384 if (win == NULL)
1385 return FALSE;
1386 FOR_ALL_TABPAGES(tp)
1387 {
1388 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
1389 {
1390 if (wp == win)
1391 return TRUE;
1392 }
1393 }
1394 return FALSE;
1395}
1396
1397/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001398 * Return the number of windows.
1399 */
1400 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001401win_count(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402{
1403 win_T *wp;
1404 int count = 0;
1405
Bram Moolenaar29323592016-07-24 22:04:11 +02001406 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 ++count;
1408 return count;
1409}
1410
1411/*
1412 * Make "count" windows on the screen.
1413 * Return actual number of windows on the screen.
1414 * Must be called when there is just one window, filling the whole screen
1415 * (excluding the command line).
1416 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001418make_windows(
1419 int count,
1420 int vertical UNUSED) /* split windows vertically if TRUE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001421{
1422 int maxcount;
1423 int todo;
1424
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425 if (vertical)
1426 {
1427 /* Each windows needs at least 'winminwidth' lines and a separator
1428 * column. */
1429 maxcount = (curwin->w_width + curwin->w_vsep_width
1430 - (p_wiw - p_wmw)) / (p_wmw + 1);
1431 }
1432 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001433 {
1434 /* Each window needs at least 'winminheight' lines and a status line. */
Bram Moolenaar415a6932017-12-05 20:31:07 +01001435 maxcount = (VISIBLE_HEIGHT(curwin) + curwin->w_status_height
Bram Moolenaar071d4272004-06-13 20:20:40 +00001436 - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
1437 }
1438
1439 if (maxcount < 2)
1440 maxcount = 2;
1441 if (count > maxcount)
1442 count = maxcount;
1443
1444 /*
1445 * add status line now, otherwise first window will be too big
1446 */
1447 if (count > 1)
1448 last_status(TRUE);
1449
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 /*
1451 * Don't execute autocommands while creating the windows. Must do that
1452 * when putting the buffers in the windows.
1453 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001454 block_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001455
1456 /* todo is number of windows left to create */
1457 for (todo = count - 1; todo > 0; --todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458 if (vertical)
1459 {
1460 if (win_split(curwin->w_width - (curwin->w_width - todo)
1461 / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
1462 break;
1463 }
1464 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 {
1466 if (win_split(curwin->w_height - (curwin->w_height - todo
1467 * STATUS_HEIGHT) / (todo + 1)
1468 - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
1469 break;
1470 }
1471
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001472 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473
1474 /* return actual number of windows */
1475 return (count - todo);
1476}
1477
1478/*
1479 * Exchange current and next window
1480 */
1481 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001482win_exchange(long Prenum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001483{
1484 frame_T *frp;
1485 frame_T *frp2;
1486 win_T *wp;
1487 win_T *wp2;
1488 int temp;
1489
Bram Moolenaar459ca562016-11-10 18:16:33 +01001490 if (ONE_WINDOW) /* just one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001491 {
1492 beep_flush();
1493 return;
1494 }
1495
1496#ifdef FEAT_GUI
1497 need_mouse_correct = TRUE;
1498#endif
1499
1500 /*
1501 * find window to exchange with
1502 */
1503 if (Prenum)
1504 {
1505 frp = curwin->w_frame->fr_parent->fr_child;
1506 while (frp != NULL && --Prenum > 0)
1507 frp = frp->fr_next;
1508 }
1509 else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
1510 frp = curwin->w_frame->fr_next;
1511 else /* Swap last window in row/col with previous */
1512 frp = curwin->w_frame->fr_prev;
1513
1514 /* We can only exchange a window with another window, not with a frame
1515 * containing windows. */
1516 if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
1517 return;
1518 wp = frp->fr_win;
1519
1520/*
1521 * 1. remove curwin from the list. Remember after which window it was in wp2
1522 * 2. insert curwin before wp in the list
1523 * if wp != wp2
1524 * 3. remove wp from the list
1525 * 4. insert wp after wp2
1526 * 5. exchange the status line height and vsep width.
1527 */
1528 wp2 = curwin->w_prev;
1529 frp2 = curwin->w_frame->fr_prev;
1530 if (wp->w_prev != curwin)
1531 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001532 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001533 frame_remove(curwin->w_frame);
1534 win_append(wp->w_prev, curwin);
1535 frame_insert(frp, curwin->w_frame);
1536 }
1537 if (wp != wp2)
1538 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001539 win_remove(wp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 frame_remove(wp->w_frame);
1541 win_append(wp2, wp);
1542 if (frp2 == NULL)
1543 frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
1544 else
1545 frame_append(frp2, wp->w_frame);
1546 }
1547 temp = curwin->w_status_height;
1548 curwin->w_status_height = wp->w_status_height;
1549 wp->w_status_height = temp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 temp = curwin->w_vsep_width;
1551 curwin->w_vsep_width = wp->w_vsep_width;
1552 wp->w_vsep_width = temp;
1553
1554 /* If the windows are not in the same frame, exchange the sizes to avoid
1555 * messing up the window layout. Otherwise fix the frame sizes. */
1556 if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
1557 {
1558 temp = curwin->w_height;
1559 curwin->w_height = wp->w_height;
1560 wp->w_height = temp;
1561 temp = curwin->w_width;
1562 curwin->w_width = wp->w_width;
1563 wp->w_width = temp;
1564 }
1565 else
1566 {
1567 frame_fix_height(curwin);
1568 frame_fix_height(wp);
1569 frame_fix_width(curwin);
1570 frame_fix_width(wp);
1571 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572
1573 (void)win_comp_pos(); /* recompute window positions */
1574
1575 win_enter(wp, TRUE);
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01001576 redraw_all_later(NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001577}
1578
1579/*
1580 * rotate windows: if upwards TRUE the second window becomes the first one
1581 * if upwards FALSE the first window becomes the second one
1582 */
1583 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001584win_rotate(int upwards, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585{
1586 win_T *wp1;
1587 win_T *wp2;
1588 frame_T *frp;
1589 int n;
1590
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01001591 if (ONE_WINDOW) /* nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592 {
1593 beep_flush();
1594 return;
1595 }
1596
1597#ifdef FEAT_GUI
1598 need_mouse_correct = TRUE;
1599#endif
1600
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 /* Check if all frames in this row/col have one window. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01001602 FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 if (frp->fr_win == NULL)
1604 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001605 emsg(_("E443: Cannot rotate when another window is split"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 return;
1607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608
1609 while (count--)
1610 {
1611 if (upwards) /* first window becomes last window */
1612 {
1613 /* remove first window/frame from the list */
1614 frp = curwin->w_frame->fr_parent->fr_child;
1615 wp1 = frp->fr_win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001616 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 frame_remove(frp);
1618
1619 /* find last frame and append removed window/frame after it */
1620 for ( ; frp->fr_next != NULL; frp = frp->fr_next)
1621 ;
1622 win_append(frp->fr_win, wp1);
1623 frame_append(frp, wp1->w_frame);
1624
1625 wp2 = frp->fr_win; /* previously last window */
1626 }
1627 else /* last window becomes first window */
1628 {
1629 /* find last window/frame in the list and remove it */
1630 for (frp = curwin->w_frame; frp->fr_next != NULL;
1631 frp = frp->fr_next)
1632 ;
1633 wp1 = frp->fr_win;
1634 wp2 = wp1->w_prev; /* will become last window */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001635 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 frame_remove(frp);
1637
1638 /* append the removed window/frame before the first in the list */
1639 win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
1640 frame_insert(frp->fr_parent->fr_child, frp);
1641 }
1642
1643 /* exchange status height and vsep width of old and new last window */
1644 n = wp2->w_status_height;
1645 wp2->w_status_height = wp1->w_status_height;
1646 wp1->w_status_height = n;
1647 frame_fix_height(wp1);
1648 frame_fix_height(wp2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649 n = wp2->w_vsep_width;
1650 wp2->w_vsep_width = wp1->w_vsep_width;
1651 wp1->w_vsep_width = n;
1652 frame_fix_width(wp1);
1653 frame_fix_width(wp2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001655 /* recompute w_winrow and w_wincol for all windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656 (void)win_comp_pos();
1657 }
1658
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01001659 redraw_all_later(NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660}
1661
1662/*
1663 * Move the current window to the very top/bottom/left/right of the screen.
1664 */
1665 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001666win_totop(int size, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667{
1668 int dir;
1669 int height = curwin->w_height;
1670
Bram Moolenaar459ca562016-11-10 18:16:33 +01001671 if (ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 {
1673 beep_flush();
1674 return;
1675 }
1676
1677 /* Remove the window and frame from the tree of frames. */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001678 (void)winframe_remove(curwin, &dir, NULL);
1679 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001680 last_status(FALSE); /* may need to remove last status line */
1681 (void)win_comp_pos(); /* recompute window positions */
1682
1683 /* Split a window on the desired side and put the window there. */
1684 (void)win_split_ins(size, flags, curwin, dir);
1685 if (!(flags & WSP_VERT))
1686 {
1687 win_setheight(height);
1688 if (p_ea)
1689 win_equal(curwin, TRUE, 'v');
1690 }
1691
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001692#if defined(FEAT_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
1694 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001695 gui_may_update_scrollbars();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697}
1698
1699/*
1700 * Move window "win1" to below/right of "win2" and make "win1" the current
1701 * window. Only works within the same frame!
1702 */
1703 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001704win_move_after(win_T *win1, win_T *win2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705{
1706 int height;
1707
1708 /* check if the arguments are reasonable */
1709 if (win1 == win2)
1710 return;
1711
1712 /* check if there is something to do */
1713 if (win2->w_next != win1)
1714 {
1715 /* may need move the status line/vertical separator of the last window
1716 * */
1717 if (win1 == lastwin)
1718 {
1719 height = win1->w_prev->w_status_height;
1720 win1->w_prev->w_status_height = win1->w_status_height;
1721 win1->w_status_height = height;
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001722 if (win1->w_prev->w_vsep_width == 1)
1723 {
1724 /* Remove the vertical separator from the last-but-one window,
1725 * add it to the last window. Adjust the frame widths. */
1726 win1->w_prev->w_vsep_width = 0;
1727 win1->w_prev->w_frame->fr_width -= 1;
1728 win1->w_vsep_width = 1;
1729 win1->w_frame->fr_width += 1;
1730 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731 }
1732 else if (win2 == lastwin)
1733 {
1734 height = win1->w_status_height;
1735 win1->w_status_height = win2->w_status_height;
1736 win2->w_status_height = height;
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001737 if (win1->w_vsep_width == 1)
1738 {
1739 /* Remove the vertical separator from win1, add it to the last
1740 * window, win2. Adjust the frame widths. */
1741 win2->w_vsep_width = 1;
1742 win2->w_frame->fr_width += 1;
1743 win1->w_vsep_width = 0;
1744 win1->w_frame->fr_width -= 1;
1745 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00001747 win_remove(win1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748 frame_remove(win1->w_frame);
1749 win_append(win2, win1);
1750 frame_append(win2->w_frame, win1->w_frame);
1751
1752 (void)win_comp_pos(); /* recompute w_winrow for all windows */
1753 redraw_later(NOT_VALID);
1754 }
1755 win_enter(win1, FALSE);
1756}
1757
1758/*
1759 * Make all windows the same height.
1760 * 'next_curwin' will soon be the current window, make sure it has enough
1761 * rows.
1762 */
1763 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001764win_equal(
1765 win_T *next_curwin, /* pointer to current window to be or NULL */
1766 int current, /* do only frame with current window */
1767 int dir) /* 'v' for vertically, 'h' for horizontally,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 'b' for both, 0 for using p_ead */
1769{
1770 if (dir == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771 dir = *p_ead;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001773 topframe, dir, 0, tabline_height(),
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001774 (int)Columns, topframe->fr_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001775}
1776
1777/*
1778 * Set a frame to a new position and height, spreading the available room
1779 * equally over contained frames.
1780 * The window "next_curwin" (if not NULL) should at least get the size from
1781 * 'winheight' and 'winwidth' if possible.
1782 */
1783 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001784win_equal_rec(
1785 win_T *next_curwin, /* pointer to current window to be or NULL */
1786 int current, /* do only frame with current window */
1787 frame_T *topfr, /* frame to set size off */
1788 int dir, /* 'v', 'h' or 'b', see win_equal() */
1789 int col, /* horizontal position for frame */
1790 int row, /* vertical position for frame */
1791 int width, /* new width of frame */
1792 int height) /* new height of frame */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793{
1794 int n, m;
1795 int extra_sep = 0;
1796 int wincount, totwincount = 0;
1797 frame_T *fr;
1798 int next_curwin_size = 0;
1799 int room = 0;
1800 int new_size;
1801 int has_next_curwin = 0;
1802 int hnc;
1803
1804 if (topfr->fr_layout == FR_LEAF)
1805 {
1806 /* Set the width/height of this frame.
1807 * Redraw when size or position changes */
1808 if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
Bram Moolenaar071d4272004-06-13 20:20:40 +00001809 || topfr->fr_width != width || topfr->fr_win->w_wincol != col
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810 )
1811 {
1812 topfr->fr_win->w_winrow = row;
1813 frame_new_height(topfr, height, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 topfr->fr_win->w_wincol = col;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001815 frame_new_width(topfr, width, FALSE, FALSE);
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01001816 redraw_all_later(NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 }
1818 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819 else if (topfr->fr_layout == FR_ROW)
1820 {
1821 topfr->fr_width = width;
1822 topfr->fr_height = height;
1823
1824 if (dir != 'v') /* equalize frame widths */
1825 {
1826 /* Compute the maximum number of windows horizontally in this
1827 * frame. */
1828 n = frame_minwidth(topfr, NOWIN);
1829 /* add one for the rightmost window, it doesn't have a separator */
1830 if (col + width == Columns)
1831 extra_sep = 1;
1832 else
1833 extra_sep = 0;
1834 totwincount = (n + extra_sep) / (p_wmw + 1);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001835 has_next_curwin = frame_has_win(topfr, next_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001837 /*
1838 * Compute width for "next_curwin" window and room available for
1839 * other windows.
1840 * "m" is the minimal width when counting p_wiw for "next_curwin".
1841 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001842 m = frame_minwidth(topfr, next_curwin);
1843 room = width - m;
1844 if (room < 0)
1845 {
1846 next_curwin_size = p_wiw + room;
1847 room = 0;
1848 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 else
1850 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001851 next_curwin_size = -1;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01001852 FOR_ALL_FRAMES(fr, topfr->fr_child)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001853 {
1854 /* If 'winfixwidth' set keep the window width if
1855 * possible.
1856 * Watch out for this window being the next_curwin. */
1857 if (frame_fixed_width(fr))
1858 {
1859 n = frame_minwidth(fr, NOWIN);
1860 new_size = fr->fr_width;
1861 if (frame_has_win(fr, next_curwin))
1862 {
1863 room += p_wiw - p_wmw;
1864 next_curwin_size = 0;
1865 if (new_size < p_wiw)
1866 new_size = p_wiw;
1867 }
1868 else
1869 /* These windows don't use up room. */
1870 totwincount -= (n + (fr->fr_next == NULL
1871 ? extra_sep : 0)) / (p_wmw + 1);
1872 room -= new_size - n;
1873 if (room < 0)
1874 {
1875 new_size += room;
1876 room = 0;
1877 }
1878 fr->fr_newwidth = new_size;
1879 }
1880 }
1881 if (next_curwin_size == -1)
1882 {
1883 if (!has_next_curwin)
1884 next_curwin_size = 0;
1885 else if (totwincount > 1
1886 && (room + (totwincount - 2))
1887 / (totwincount - 1) > p_wiw)
1888 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001889 /* Can make all windows wider than 'winwidth', spread
1890 * the room equally. */
1891 next_curwin_size = (room + p_wiw
1892 + (totwincount - 1) * p_wmw
1893 + (totwincount - 1)) / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001894 room -= next_curwin_size - p_wiw;
1895 }
1896 else
1897 next_curwin_size = p_wiw;
1898 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001899 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001900
1901 if (has_next_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001902 --totwincount; /* don't count curwin */
1903 }
1904
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01001905 FOR_ALL_FRAMES(fr, topfr->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 wincount = 1;
1908 if (fr->fr_next == NULL)
1909 /* last frame gets all that remains (avoid roundoff error) */
1910 new_size = width;
1911 else if (dir == 'v')
1912 new_size = fr->fr_width;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001913 else if (frame_fixed_width(fr))
1914 {
1915 new_size = fr->fr_newwidth;
1916 wincount = 0; /* doesn't count as a sizeable window */
1917 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918 else
1919 {
1920 /* Compute the maximum number of windows horiz. in "fr". */
1921 n = frame_minwidth(fr, NOWIN);
1922 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
1923 / (p_wmw + 1);
1924 m = frame_minwidth(fr, next_curwin);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001925 if (has_next_curwin)
1926 hnc = frame_has_win(fr, next_curwin);
1927 else
1928 hnc = FALSE;
1929 if (hnc) /* don't count next_curwin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 --wincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001931 if (totwincount == 0)
1932 new_size = room;
1933 else
1934 new_size = (wincount * room + ((unsigned)totwincount >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001936 if (hnc) /* add next_curwin size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 {
1938 next_curwin_size -= p_wiw - (m - n);
1939 new_size += next_curwin_size;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001940 room -= new_size - next_curwin_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001942 else
1943 room -= new_size;
1944 new_size += n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 }
1946
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001947 /* Skip frame that is full width when splitting or closing a
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 * window, unless equalizing all frames. */
1949 if (!current || dir != 'v' || topfr->fr_parent != NULL
1950 || (new_size != fr->fr_width)
1951 || frame_has_win(fr, next_curwin))
1952 win_equal_rec(next_curwin, current, fr, dir, col, row,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001953 new_size, height);
1954 col += new_size;
1955 width -= new_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 totwincount -= wincount;
1957 }
1958 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 else /* topfr->fr_layout == FR_COL */
1960 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961 topfr->fr_width = width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 topfr->fr_height = height;
1963
1964 if (dir != 'h') /* equalize frame heights */
1965 {
1966 /* Compute maximum number of windows vertically in this frame. */
1967 n = frame_minheight(topfr, NOWIN);
1968 /* add one for the bottom window if it doesn't have a statusline */
1969 if (row + height == cmdline_row && p_ls == 0)
1970 extra_sep = 1;
1971 else
1972 extra_sep = 0;
1973 totwincount = (n + extra_sep) / (p_wmh + 1);
1974 has_next_curwin = frame_has_win(topfr, next_curwin);
1975
1976 /*
1977 * Compute height for "next_curwin" window and room available for
1978 * other windows.
1979 * "m" is the minimal height when counting p_wh for "next_curwin".
1980 */
1981 m = frame_minheight(topfr, next_curwin);
1982 room = height - m;
1983 if (room < 0)
1984 {
1985 /* The room is less then 'winheight', use all space for the
1986 * current window. */
1987 next_curwin_size = p_wh + room;
1988 room = 0;
1989 }
1990 else
1991 {
1992 next_curwin_size = -1;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01001993 FOR_ALL_FRAMES(fr, topfr->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001994 {
1995 /* If 'winfixheight' set keep the window height if
1996 * possible.
1997 * Watch out for this window being the next_curwin. */
1998 if (frame_fixed_height(fr))
1999 {
2000 n = frame_minheight(fr, NOWIN);
2001 new_size = fr->fr_height;
2002 if (frame_has_win(fr, next_curwin))
2003 {
2004 room += p_wh - p_wmh;
2005 next_curwin_size = 0;
2006 if (new_size < p_wh)
2007 new_size = p_wh;
2008 }
2009 else
2010 /* These windows don't use up room. */
2011 totwincount -= (n + (fr->fr_next == NULL
2012 ? extra_sep : 0)) / (p_wmh + 1);
2013 room -= new_size - n;
2014 if (room < 0)
2015 {
2016 new_size += room;
2017 room = 0;
2018 }
2019 fr->fr_newheight = new_size;
2020 }
2021 }
2022 if (next_curwin_size == -1)
2023 {
2024 if (!has_next_curwin)
2025 next_curwin_size = 0;
2026 else if (totwincount > 1
2027 && (room + (totwincount - 2))
2028 / (totwincount - 1) > p_wh)
2029 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00002030 /* can make all windows higher than 'winheight',
2031 * spread the room equally. */
2032 next_curwin_size = (room + p_wh
2033 + (totwincount - 1) * p_wmh
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034 + (totwincount - 1)) / totwincount;
2035 room -= next_curwin_size - p_wh;
2036 }
2037 else
2038 next_curwin_size = p_wh;
2039 }
2040 }
2041
2042 if (has_next_curwin)
2043 --totwincount; /* don't count curwin */
2044 }
2045
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01002046 FOR_ALL_FRAMES(fr, topfr->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 wincount = 1;
2049 if (fr->fr_next == NULL)
2050 /* last frame gets all that remains (avoid roundoff error) */
2051 new_size = height;
2052 else if (dir == 'h')
2053 new_size = fr->fr_height;
2054 else if (frame_fixed_height(fr))
2055 {
2056 new_size = fr->fr_newheight;
2057 wincount = 0; /* doesn't count as a sizeable window */
2058 }
2059 else
2060 {
2061 /* Compute the maximum number of windows vert. in "fr". */
2062 n = frame_minheight(fr, NOWIN);
2063 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
2064 / (p_wmh + 1);
2065 m = frame_minheight(fr, next_curwin);
2066 if (has_next_curwin)
2067 hnc = frame_has_win(fr, next_curwin);
2068 else
2069 hnc = FALSE;
2070 if (hnc) /* don't count next_curwin */
2071 --wincount;
2072 if (totwincount == 0)
2073 new_size = room;
2074 else
2075 new_size = (wincount * room + ((unsigned)totwincount >> 1))
2076 / totwincount;
2077 if (hnc) /* add next_curwin size */
2078 {
2079 next_curwin_size -= p_wh - (m - n);
2080 new_size += next_curwin_size;
2081 room -= new_size - next_curwin_size;
2082 }
2083 else
2084 room -= new_size;
2085 new_size += n;
2086 }
2087 /* Skip frame that is full width when splitting or closing a
2088 * window, unless equalizing all frames. */
2089 if (!current || dir != 'h' || topfr->fr_parent != NULL
2090 || (new_size != fr->fr_height)
2091 || frame_has_win(fr, next_curwin))
2092 win_equal_rec(next_curwin, current, fr, dir, col, row,
2093 width, new_size);
2094 row += new_size;
2095 height -= new_size;
2096 totwincount -= wincount;
2097 }
2098 }
2099}
2100
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002101#ifdef FEAT_JOB_CHANNEL
2102 static void
2103leaving_window(win_T *win)
2104{
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002105 // Only matters for a prompt window.
2106 if (!bt_prompt(win->w_buffer))
2107 return;
2108
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002109 // When leaving a prompt window stop Insert mode and perhaps restart
2110 // it when entering that window again.
2111 win->w_buffer->b_prompt_insert = restart_edit;
Bram Moolenaar942b4542018-06-17 16:23:34 +02002112 if (restart_edit != 0 && mode_displayed)
2113 clear_cmdline = TRUE; /* unshow mode later */
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002114 restart_edit = NUL;
2115
2116 // When leaving the window (or closing the window) was done from a
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002117 // callback we need to break out of the Insert mode loop and restart Insert
2118 // mode when entering the window again.
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002119 if (State & INSERT)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002120 {
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002121 stop_insert_mode = TRUE;
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002122 if (win->w_buffer->b_prompt_insert == NUL)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002123 win->w_buffer->b_prompt_insert = 'A';
2124 }
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002125}
2126
2127 static void
2128entering_window(win_T *win)
2129{
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002130 // Only matters for a prompt window.
2131 if (!bt_prompt(win->w_buffer))
2132 return;
2133
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002134 // When switching to a prompt buffer that was in Insert mode, don't stop
2135 // Insert mode, it may have been set in leaving_window().
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002136 if (win->w_buffer->b_prompt_insert != NUL)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002137 stop_insert_mode = FALSE;
2138
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002139 // When entering the prompt window restart Insert mode if we were in Insert
2140 // mode when we left it.
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002141 restart_edit = win->w_buffer->b_prompt_insert;
2142}
2143#endif
2144
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145/*
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01002146 * Close all windows for buffer "buf".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 */
2148 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002149close_windows(
2150 buf_T *buf,
2151 int keep_curwin) /* don't close "curwin" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152{
Bram Moolenaarf740b292006-02-16 22:11:02 +00002153 win_T *wp;
2154 tabpage_T *tp, *nexttp;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002155 int h = tabline_height();
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002156 int count = tabpage_index(NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157
2158 ++RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002159
Bram Moolenaar459ca562016-11-10 18:16:33 +01002160 for (wp = firstwin; wp != NULL && !ONE_WINDOW; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002161 {
Bram Moolenaar362ce482012-06-06 19:02:45 +02002162 if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002163 && !(wp->w_closing || wp->w_buffer->b_locked > 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164 {
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01002165 if (win_close(wp, FALSE) == FAIL)
2166 /* If closing the window fails give up, to avoid looping
2167 * forever. */
2168 break;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002169
2170 /* Start all over, autocommands may change the window layout. */
2171 wp = firstwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 }
2173 else
Bram Moolenaarf740b292006-02-16 22:11:02 +00002174 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00002176
2177 /* Also check windows in other tab pages. */
2178 for (tp = first_tabpage; tp != NULL; tp = nexttp)
2179 {
2180 nexttp = tp->tp_next;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002181 if (tp != curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002182 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002183 if (wp->w_buffer == buf
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002184 && !(wp->w_closing || wp->w_buffer->b_locked > 0))
Bram Moolenaarf740b292006-02-16 22:11:02 +00002185 {
2186 win_close_othertab(wp, FALSE, tp);
2187
2188 /* Start all over, the tab page may be closed and
2189 * autocommands may change the window layout. */
2190 nexttp = first_tabpage;
2191 break;
2192 }
2193 }
2194
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 --RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002196
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002197 if (count != tabpage_index(NULL))
2198 apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002199
Bram Moolenaar4c7e9db2013-04-15 15:55:19 +02002200 redraw_tabline = TRUE;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002201 if (h != tabline_height())
Bram Moolenaarf740b292006-02-16 22:11:02 +00002202 shell_new_rows();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203}
2204
2205/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002206 * Return TRUE if the current window is the only window that exists (ignoring
2207 * "aucmd_win").
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002208 * Returns FALSE if there is a window, possibly in another tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002209 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002210 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002211last_window(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002212{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002213 return (one_window() && first_tabpage->tp_next == NULL);
2214}
2215
2216/*
2217 * Return TRUE if there is only one window other than "aucmd_win" in the
2218 * current tab page.
2219 */
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002220 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002221one_window(void)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002222{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002223 win_T *wp;
2224 int seen_one = FALSE;
2225
2226 FOR_ALL_WINDOWS(wp)
2227 {
2228 if (wp != aucmd_win)
2229 {
2230 if (seen_one)
2231 return FALSE;
2232 seen_one = TRUE;
2233 }
2234 }
2235 return TRUE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002236}
2237
2238/*
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002239 * Close the possibly last window in a tab page.
2240 * Returns TRUE when the window was closed already.
2241 */
2242 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002243close_last_window_tabpage(
2244 win_T *win,
2245 int free_buf,
2246 tabpage_T *prev_curtab)
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002247{
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002248 if (ONE_WINDOW)
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002249 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002250 buf_T *old_curbuf = curbuf;
2251
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002252 /*
2253 * Closing the last window in a tab page. First go to another tab
2254 * page and then close the window and the tab page. This avoids that
2255 * curwin and curtab are invalid while we are freeing memory, they may
2256 * be used in GUI events.
Bram Moolenaara8596c42012-06-13 14:28:20 +02002257 * Don't trigger autocommands yet, they may use wrong values, so do
2258 * that below.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002259 */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002260 goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002261 redraw_tabline = TRUE;
2262
2263 /* Safety check: Autocommands may have closed the window when jumping
2264 * to the other tab page. */
2265 if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win)
2266 {
2267 int h = tabline_height();
2268
2269 win_close_othertab(win, free_buf, prev_curtab);
2270 if (h != tabline_height())
2271 shell_new_rows();
2272 }
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002273#ifdef FEAT_JOB_CHANNEL
2274 entering_window(curwin);
2275#endif
Bram Moolenaara8596c42012-06-13 14:28:20 +02002276 /* Since goto_tabpage_tp above did not trigger *Enter autocommands, do
2277 * that now. */
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002278 apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
Bram Moolenaara8596c42012-06-13 14:28:20 +02002279 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002280 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
2281 if (old_curbuf != curbuf)
2282 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002283 return TRUE;
2284 }
2285 return FALSE;
2286}
2287
2288/*
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002289 * Close window "win". Only works for the current tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 * If "free_buf" is TRUE related buffer may be unloaded.
2291 *
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002292 * Called by :quit, :close, :xit, :wq and findtag().
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002293 * Returns FAIL when the window was not closed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 */
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002295 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002296win_close(win_T *win, int free_buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297{
2298 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 int other_buffer = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 int close_curwin = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 int dir;
2302 int help_window = FALSE;
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002303 tabpage_T *prev_curtab = curtab;
Bram Moolenaar41cc0382017-06-26 09:59:35 +02002304 frame_T *win_frame = win->w_frame->fr_parent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002306 if (last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002308 emsg(_("E444: Cannot close last window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002309 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 }
2311
Bram Moolenaare0ab94e2016-09-04 19:50:54 +02002312 if (win->w_closing || (win->w_buffer != NULL
2313 && win->w_buffer->b_locked > 0))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002314 return FAIL; /* window is already being closed */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002315 if (win == aucmd_win)
2316 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002317 emsg(_("E813: Cannot close autocmd window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002318 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002319 }
2320 if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
2321 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002322 emsg(_("E814: Cannot close window, only autocmd window would remain"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002323 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002324 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002325
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002326 /* When closing the last window in a tab page first go to another tab page
2327 * and then close the window and the tab page to avoid that curwin and
2328 * curtab are invalid while we are freeing memory. */
2329 if (close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002330 return FAIL;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002331
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 /* When closing the help window, try restoring a snapshot after closing
2333 * the window. Otherwise clear the snapshot, it's now invalid. */
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02002334 if (bt_help(win->w_buffer))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 help_window = TRUE;
2336 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002337 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 if (win == curwin)
2340 {
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002341#ifdef FEAT_JOB_CHANNEL
2342 leaving_window(curwin);
2343#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002344 /*
2345 * Guess which window is going to be the new current window.
2346 * This may change because of the autocommands (sigh).
2347 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002348 wp = frame2win(win_altframe(win, NULL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349
2350 /*
Bram Moolenaar362ce482012-06-06 19:02:45 +02002351 * Be careful: If autocommands delete the window or cause this window
2352 * to be the last one left, return now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 */
2354 if (wp->w_buffer != curbuf)
2355 {
2356 other_buffer = TRUE;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002357 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002359 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002360 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002361 win->w_closing = FALSE;
2362 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002363 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002364 }
Bram Moolenaar362ce482012-06-06 19:02:45 +02002365 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002367 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002368 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002369 win->w_closing = FALSE;
2370 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002371 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002372#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 /* autocmds may abort script processing */
2374 if (aborting())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002375 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002377 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378
Bram Moolenaar053b9fa2007-04-26 14:09:42 +00002379#ifdef FEAT_GUI
2380 /* Avoid trouble with scrollbars that are going to be deleted in
2381 * win_free(). */
2382 if (gui.in_use)
2383 out_flush();
2384#endif
2385
Bram Moolenaara971b822011-09-14 14:43:25 +02002386#ifdef FEAT_SYN_HL
2387 /* Free independent synblock before the buffer is freed. */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002388 if (win->w_buffer != NULL)
2389 reset_synblock(win);
Bram Moolenaara971b822011-09-14 14:43:25 +02002390#endif
2391
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 /*
2393 * Close the link to the buffer.
2394 */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002395 if (win->w_buffer != NULL)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002396 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002397 bufref_T bufref;
2398
2399 set_bufref(&bufref, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002400 win->w_closing = TRUE;
Bram Moolenaar8f913992012-08-29 15:50:26 +02002401 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002402 if (win_valid_any_tab(win))
Bram Moolenaar362ce482012-06-06 19:02:45 +02002403 win->w_closing = FALSE;
Bram Moolenaar62ef7972016-01-19 14:51:54 +01002404 /* Make sure curbuf is valid. It can become invalid if 'bufhidden' is
2405 * "wipe". */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002406 if (!bufref_valid(&bufref))
Bram Moolenaar62ef7972016-01-19 14:51:54 +01002407 curbuf = firstbuf;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002408 }
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002409
Bram Moolenaar802418d2013-01-17 14:00:11 +01002410 if (only_one_window() && win_valid(win) && win->w_buffer == NULL
2411 && (last_window() || curtab != prev_curtab
2412 || close_last_window_tabpage(win, free_buf, prev_curtab)))
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002413 {
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02002414 /* Autocommands have closed all windows, quit now. Restore
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002415 * curwin->w_buffer, otherwise writing viminfo may fail. */
2416 if (curwin->w_buffer == NULL)
2417 curwin->w_buffer = curbuf;
Bram Moolenaar802418d2013-01-17 14:00:11 +01002418 getout(0);
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002419 }
Bram Moolenaar802418d2013-01-17 14:00:11 +01002420
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002421 /* Autocommands may have moved to another tab page. */
2422 if (curtab != prev_curtab && win_valid_any_tab(win)
2423 && win->w_buffer == NULL)
2424 {
2425 /* Need to close the window anyway, since the buffer is NULL. */
2426 win_close_othertab(win, FALSE, prev_curtab);
2427 return FAIL;
2428 }
2429
2430 /* Autocommands may have closed the window already or closed the only
2431 * other window. */
2432 if (!win_valid(win) || last_window()
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002433 || close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002434 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435
Bram Moolenaara971b822011-09-14 14:43:25 +02002436 /* Free the memory used for the window and get the window that received
2437 * the screen space. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002438 wp = win_free_mem(win, &dir, NULL);
2439
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 /* Make sure curwin isn't invalid. It can cause severe trouble when
2441 * printing an error message. For win_equal() curbuf needs to be valid
2442 * too. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002443 if (win == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 {
2445 curwin = wp;
2446#ifdef FEAT_QUICKFIX
2447 if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
2448 {
2449 /*
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002450 * If the cursor goes to the preview or the quickfix window, try
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451 * finding another window to go to.
2452 */
2453 for (;;)
2454 {
2455 if (wp->w_next == NULL)
2456 wp = firstwin;
2457 else
2458 wp = wp->w_next;
2459 if (wp == curwin)
2460 break;
2461 if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
2462 {
2463 curwin = wp;
2464 break;
2465 }
2466 }
2467 }
2468#endif
2469 curbuf = curwin->w_buffer;
2470 close_curwin = TRUE;
Bram Moolenaarf79225e2017-03-18 23:11:04 +01002471
2472 /* The cursor position may be invalid if the buffer changed after last
2473 * using the window. */
2474 check_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 }
Bram Moolenaar44a2f922016-03-19 22:11:51 +01002476 if (p_ea && (*p_ead == 'b' || *p_ead == dir))
Bram Moolenaar8eeeba82017-06-25 22:45:39 +02002477 /* If the frame of the closed window contains the new current window,
2478 * only resize that frame. Otherwise resize all windows. */
Bram Moolenaar41cc0382017-06-26 09:59:35 +02002479 win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 else
2481 win_comp_pos();
2482 if (close_curwin)
2483 {
Bram Moolenaarc917da42016-07-19 22:31:36 +02002484 win_enter_ext(wp, FALSE, TRUE, FALSE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485 if (other_buffer)
2486 /* careful: after this wp and win may be invalid! */
2487 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 }
2489
2490 /*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002491 * If last window has a status line now and we don't want one,
2492 * remove the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 */
2494 last_status(FALSE);
2495
2496 /* After closing the help window, try restoring the window layout from
2497 * before it was opened. */
2498 if (help_window)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002499 restore_snapshot(SNAP_HELP_IDX, close_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500
Bram Moolenaar44a2f922016-03-19 22:11:51 +01002501#if defined(FEAT_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
2503 if (gui.in_use && !win_hasvertsplit())
2504 gui_init_which_components(NULL);
2505#endif
2506
2507 redraw_all_later(NOT_VALID);
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002508 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509}
2510
2511/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002512 * Close window "win" in tab page "tp", which is not the current tab page.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002513 * This may be the last window in that tab page and result in closing the tab,
Bram Moolenaarf740b292006-02-16 22:11:02 +00002514 * thus "tp" may become invalid!
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002515 * Caller must check if buffer is hidden and whether the tabline needs to be
2516 * updated.
Bram Moolenaarf740b292006-02-16 22:11:02 +00002517 */
2518 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002519win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002520{
2521 win_T *wp;
2522 int dir;
2523 tabpage_T *ptp = NULL;
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002524 int free_tp = FALSE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002525
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002526 /* Get here with win->w_buffer == NULL when win_close() detects the tab
2527 * page changed. */
Bram Moolenaare0ab94e2016-09-04 19:50:54 +02002528 if (win->w_closing || (win->w_buffer != NULL
2529 && win->w_buffer->b_locked > 0))
Bram Moolenaar362ce482012-06-06 19:02:45 +02002530 return; /* window is already being closed */
Bram Moolenaar362ce482012-06-06 19:02:45 +02002531
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002532 if (win->w_buffer != NULL)
2533 /* Close the link to the buffer. */
2534 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002535
2536 /* Careful: Autocommands may have closed the tab page or made it the
2537 * current tab page. */
2538 for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
2539 ;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002540 if (ptp == NULL || tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002541 return;
2542
2543 /* Autocommands may have closed the window already. */
2544 for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
2545 ;
2546 if (wp == NULL)
2547 return;
2548
Bram Moolenaarf740b292006-02-16 22:11:02 +00002549 /* When closing the last window in a tab page remove the tab page. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02002550 if (tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002551 {
2552 if (tp == first_tabpage)
2553 first_tabpage = tp->tp_next;
2554 else
2555 {
2556 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
2557 ptp = ptp->tp_next)
2558 ;
2559 if (ptp == NULL)
2560 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01002561 internal_error("win_close_othertab()");
Bram Moolenaarf740b292006-02-16 22:11:02 +00002562 return;
2563 }
2564 ptp->tp_next = tp->tp_next;
2565 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002566 free_tp = TRUE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002567 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002568
2569 /* Free the memory used for the window. */
2570 win_free_mem(win, &dir, tp);
2571
2572 if (free_tp)
2573 free_tabpage(tp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002574}
2575
2576/*
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002577 * Free the memory used for a window.
2578 * Returns a pointer to the window that got the freed up space.
2579 */
2580 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002581win_free_mem(
2582 win_T *win,
2583 int *dirp, /* set to 'v' or 'h' for direction if 'ea' */
2584 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002585{
2586 frame_T *frp;
2587 win_T *wp;
2588
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002589 /* Remove the window and its frame from the tree of frames. */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002590 frp = win->w_frame;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002591 wp = winframe_remove(win, dirp, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002592 vim_free(frp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002593 win_free(win, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002594
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002595 /* When deleting the current window of another tab page select a new
2596 * current window. */
2597 if (tp != NULL && win == tp->tp_curwin)
2598 tp->tp_curwin = wp;
2599
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002600 return wp;
2601}
2602
2603#if defined(EXITFREE) || defined(PROTO)
2604 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002605win_free_all(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002606{
2607 int dummy;
2608
Bram Moolenaarf740b292006-02-16 22:11:02 +00002609 while (first_tabpage->tp_next != NULL)
2610 tabpage_close(TRUE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002611
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002612 if (aucmd_win != NULL)
2613 {
2614 (void)win_free_mem(aucmd_win, &dummy, NULL);
2615 aucmd_win = NULL;
2616 }
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00002617
2618 while (firstwin != NULL)
2619 (void)win_free_mem(firstwin, &dummy, NULL);
Bram Moolenaar4e036c92014-07-16 16:30:28 +02002620
2621 /* No window should be used after this. Set curwin to NULL to crash
2622 * instead of using freed memory. */
2623 curwin = NULL;
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002624}
2625#endif
2626
2627/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 * Remove a window and its frame from the tree of frames.
2629 * Returns a pointer to the window that got the freed up space.
2630 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002631 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002632winframe_remove(
2633 win_T *win,
2634 int *dirp UNUSED, /* set to 'v' or 'h' for direction if 'ea' */
2635 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636{
2637 frame_T *frp, *frp2, *frp3;
2638 frame_T *frp_close = win->w_frame;
2639 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640
2641 /*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002642 * If there is only one window there is nothing to remove.
2643 */
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002644 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002645 return NULL;
2646
2647 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 * Remove the window from its frame.
2649 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002650 frp2 = win_altframe(win, tp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 wp = frame2win(frp2);
2652
2653 /* Remove this frame from the list of frames. */
2654 frame_remove(frp_close);
2655
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 if (frp_close->fr_parent->fr_layout == FR_COL)
2657 {
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002658 /* When 'winfixheight' is set, try to find another frame in the column
2659 * (as close to the closed frame as possible) to distribute the height
2660 * to. */
2661 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
2662 {
2663 frp = frp_close->fr_prev;
2664 frp3 = frp_close->fr_next;
2665 while (frp != NULL || frp3 != NULL)
2666 {
2667 if (frp != NULL)
2668 {
2669 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh)
2670 {
2671 frp2 = frp;
2672 wp = frp->fr_win;
2673 break;
2674 }
2675 frp = frp->fr_prev;
2676 }
2677 if (frp3 != NULL)
2678 {
2679 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
2680 {
2681 frp2 = frp3;
2682 wp = frp3->fr_win;
2683 break;
2684 }
2685 frp3 = frp3->fr_next;
2686 }
2687 }
2688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
2690 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 *dirp = 'v';
2692 }
2693 else
2694 {
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002695 /* When 'winfixwidth' is set, try to find another frame in the column
2696 * (as close to the closed frame as possible) to distribute the width
2697 * to. */
2698 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
2699 {
2700 frp = frp_close->fr_prev;
2701 frp3 = frp_close->fr_next;
2702 while (frp != NULL || frp3 != NULL)
2703 {
2704 if (frp != NULL)
2705 {
2706 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw)
2707 {
2708 frp2 = frp;
2709 wp = frp->fr_win;
2710 break;
2711 }
2712 frp = frp->fr_prev;
2713 }
2714 if (frp3 != NULL)
2715 {
2716 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
2717 {
2718 frp2 = frp3;
2719 wp = frp3->fr_win;
2720 break;
2721 }
2722 frp3 = frp3->fr_next;
2723 }
2724 }
2725 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002727 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002728 *dirp = 'h';
2729 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730
2731 /* If rows/columns go to a window below/right its positions need to be
2732 * updated. Can only be done after the sizes have been updated. */
2733 if (frp2 == frp_close->fr_next)
2734 {
2735 int row = win->w_winrow;
Bram Moolenaar53f81742017-09-22 14:35:51 +02002736 int col = win->w_wincol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737
2738 frame_comp_pos(frp2, &row, &col);
2739 }
2740
2741 if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
2742 {
2743 /* There is no other frame in this list, move its info to the parent
2744 * and remove it. */
2745 frp2->fr_parent->fr_layout = frp2->fr_layout;
2746 frp2->fr_parent->fr_child = frp2->fr_child;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01002747 FOR_ALL_FRAMES(frp, frp2->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 frp->fr_parent = frp2->fr_parent;
2749 frp2->fr_parent->fr_win = frp2->fr_win;
2750 if (frp2->fr_win != NULL)
2751 frp2->fr_win->w_frame = frp2->fr_parent;
2752 frp = frp2->fr_parent;
Bram Moolenaar6f361c92018-01-31 19:06:50 +01002753 if (topframe->fr_child == frp2)
2754 topframe->fr_child = frp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 vim_free(frp2);
2756
2757 frp2 = frp->fr_parent;
2758 if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
2759 {
2760 /* The frame above the parent has the same layout, have to merge
2761 * the frames into this list. */
2762 if (frp2->fr_child == frp)
2763 frp2->fr_child = frp->fr_child;
2764 frp->fr_child->fr_prev = frp->fr_prev;
2765 if (frp->fr_prev != NULL)
2766 frp->fr_prev->fr_next = frp->fr_child;
2767 for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
2768 {
2769 frp3->fr_parent = frp2;
2770 if (frp3->fr_next == NULL)
2771 {
2772 frp3->fr_next = frp->fr_next;
2773 if (frp->fr_next != NULL)
2774 frp->fr_next->fr_prev = frp3;
2775 break;
2776 }
2777 }
Bram Moolenaar6f361c92018-01-31 19:06:50 +01002778 if (topframe->fr_child == frp)
2779 topframe->fr_child = frp2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780 vim_free(frp);
2781 }
2782 }
2783
2784 return wp;
2785}
2786
2787/*
Bram Moolenaarc136af22018-05-04 20:15:38 +02002788 * Return a pointer to the frame that will receive the empty screen space that
2789 * is left over after "win" is closed.
2790 *
2791 * If 'splitbelow' or 'splitright' is set, the space goes above or to the left
2792 * by default. Otherwise, the free space goes below or to the right. The
2793 * result is that opening a window and then immediately closing it will
2794 * preserve the initial window layout. The 'wfh' and 'wfw' settings are
2795 * respected when possible.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796 */
2797 static frame_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002798win_altframe(
2799 win_T *win,
2800 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801{
2802 frame_T *frp;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002803 frame_T *other_fr, *target_fr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002805 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002806 return alt_tabpage()->tp_curwin->w_frame;
2807
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808 frp = win->w_frame;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002809
2810 if (frp->fr_prev == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 return frp->fr_next;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002812 if (frp->fr_next == NULL)
2813 return frp->fr_prev;
2814
2815 target_fr = frp->fr_next;
2816 other_fr = frp->fr_prev;
2817 if (p_spr || p_sb)
2818 {
2819 target_fr = frp->fr_prev;
2820 other_fr = frp->fr_next;
2821 }
2822
2823 /* If 'wfh' or 'wfw' is set for the target and not for the alternate
2824 * window, reverse the selection. */
2825 if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
2826 {
2827 if (frame_fixed_width(target_fr) && !frame_fixed_width(other_fr))
2828 target_fr = other_fr;
2829 }
2830 else
2831 {
2832 if (frame_fixed_height(target_fr) && !frame_fixed_height(other_fr))
2833 target_fr = other_fr;
2834 }
2835
2836 return target_fr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837}
2838
2839/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002840 * Return the tabpage that will be used if the current one is closed.
2841 */
2842 static tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002843alt_tabpage(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002844{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002845 tabpage_T *tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002846
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002847 /* Use the next tab page if possible. */
2848 if (curtab->tp_next != NULL)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002849 return curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002850
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002851 /* Find the last but one tab page. */
2852 for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
2853 ;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002854 return tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002855}
2856
2857/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 * Find the left-upper window in frame "frp".
2859 */
2860 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002861frame2win(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862{
2863 while (frp->fr_win == NULL)
2864 frp = frp->fr_child;
2865 return frp->fr_win;
2866}
2867
2868/*
2869 * Return TRUE if frame "frp" contains window "wp".
2870 */
2871 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002872frame_has_win(frame_T *frp, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873{
2874 frame_T *p;
2875
2876 if (frp->fr_layout == FR_LEAF)
2877 return frp->fr_win == wp;
2878
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01002879 FOR_ALL_FRAMES(p, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880 if (frame_has_win(p, wp))
2881 return TRUE;
2882 return FALSE;
2883}
2884
2885/*
2886 * Set a new height for a frame. Recursively sets the height for contained
2887 * frames and windows. Caller must take care of positions.
2888 */
2889 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002890frame_new_height(
2891 frame_T *topfrp,
2892 int height,
2893 int topfirst, /* resize topmost contained frame first */
2894 int wfh) /* obey 'winfixheight' when there is a choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 may cause the height not to be set */
2896{
2897 frame_T *frp;
2898 int extra_lines;
2899 int h;
2900
2901 if (topfrp->fr_win != NULL)
2902 {
2903 /* Simple case: just one window. */
2904 win_new_height(topfrp->fr_win,
Bram Moolenaard326ad62017-09-18 20:31:41 +02002905 height - topfrp->fr_win->w_status_height
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01002906 - WINBAR_HEIGHT(topfrp->fr_win));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908 else if (topfrp->fr_layout == FR_ROW)
2909 {
2910 do
2911 {
2912 /* All frames in this row get the same new height. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01002913 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002914 {
2915 frame_new_height(frp, height, topfirst, wfh);
2916 if (frp->fr_height > height)
2917 {
2918 /* Could not fit the windows, make the whole row higher. */
2919 height = frp->fr_height;
2920 break;
2921 }
2922 }
2923 }
2924 while (frp != NULL);
2925 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002926 else /* fr_layout == FR_COL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927 {
2928 /* Complicated case: Resize a column of frames. Resize the bottom
2929 * frame first, frames above that when needed. */
2930
2931 frp = topfrp->fr_child;
2932 if (wfh)
2933 /* Advance past frames with one window with 'wfh' set. */
2934 while (frame_fixed_height(frp))
2935 {
2936 frp = frp->fr_next;
2937 if (frp == NULL)
2938 return; /* no frame without 'wfh', give up */
2939 }
2940 if (!topfirst)
2941 {
2942 /* Find the bottom frame of this column */
2943 while (frp->fr_next != NULL)
2944 frp = frp->fr_next;
2945 if (wfh)
2946 /* Advance back for frames with one window with 'wfh' set. */
2947 while (frame_fixed_height(frp))
2948 frp = frp->fr_prev;
2949 }
2950
2951 extra_lines = height - topfrp->fr_height;
2952 if (extra_lines < 0)
2953 {
2954 /* reduce height of contained frames, bottom or top frame first */
2955 while (frp != NULL)
2956 {
2957 h = frame_minheight(frp, NULL);
2958 if (frp->fr_height + extra_lines < h)
2959 {
2960 extra_lines += frp->fr_height - h;
2961 frame_new_height(frp, h, topfirst, wfh);
2962 }
2963 else
2964 {
2965 frame_new_height(frp, frp->fr_height + extra_lines,
2966 topfirst, wfh);
2967 break;
2968 }
2969 if (topfirst)
2970 {
2971 do
2972 frp = frp->fr_next;
2973 while (wfh && frp != NULL && frame_fixed_height(frp));
2974 }
2975 else
2976 {
2977 do
2978 frp = frp->fr_prev;
2979 while (wfh && frp != NULL && frame_fixed_height(frp));
2980 }
2981 /* Increase "height" if we could not reduce enough frames. */
2982 if (frp == NULL)
2983 height -= extra_lines;
2984 }
2985 }
2986 else if (extra_lines > 0)
2987 {
2988 /* increase height of bottom or top frame */
2989 frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
2990 }
2991 }
2992 topfrp->fr_height = height;
2993}
2994
2995/*
2996 * Return TRUE if height of frame "frp" should not be changed because of
2997 * the 'winfixheight' option.
2998 */
2999 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003000frame_fixed_height(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001{
3002 /* frame with one window: fixed height if 'winfixheight' set. */
3003 if (frp->fr_win != NULL)
3004 return frp->fr_win->w_p_wfh;
3005
3006 if (frp->fr_layout == FR_ROW)
3007 {
3008 /* The frame is fixed height if one of the frames in the row is fixed
3009 * height. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003010 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011 if (frame_fixed_height(frp))
3012 return TRUE;
3013 return FALSE;
3014 }
3015
3016 /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
3017 * frames in the row are fixed height. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003018 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 if (!frame_fixed_height(frp))
3020 return FALSE;
3021 return TRUE;
3022}
3023
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024/*
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003025 * Return TRUE if width of frame "frp" should not be changed because of
3026 * the 'winfixwidth' option.
3027 */
3028 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003029frame_fixed_width(frame_T *frp)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003030{
3031 /* frame with one window: fixed width if 'winfixwidth' set. */
3032 if (frp->fr_win != NULL)
3033 return frp->fr_win->w_p_wfw;
3034
3035 if (frp->fr_layout == FR_COL)
3036 {
3037 /* The frame is fixed width if one of the frames in the row is fixed
3038 * width. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003039 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003040 if (frame_fixed_width(frp))
3041 return TRUE;
3042 return FALSE;
3043 }
3044
3045 /* frp->fr_layout == FR_ROW: The frame is fixed width if all of the
3046 * frames in the row are fixed width. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003047 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003048 if (!frame_fixed_width(frp))
3049 return FALSE;
3050 return TRUE;
3051}
3052
3053/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054 * Add a status line to windows at the bottom of "frp".
3055 * Note: Does not check if there is room!
3056 */
3057 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003058frame_add_statusline(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059{
3060 win_T *wp;
3061
3062 if (frp->fr_layout == FR_LEAF)
3063 {
3064 wp = frp->fr_win;
3065 if (wp->w_status_height == 0)
3066 {
3067 if (wp->w_height > 0) /* don't make it negative */
3068 --wp->w_height;
3069 wp->w_status_height = STATUS_HEIGHT;
3070 }
3071 }
3072 else if (frp->fr_layout == FR_ROW)
3073 {
3074 /* Handle all the frames in the row. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003075 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 frame_add_statusline(frp);
3077 }
3078 else /* frp->fr_layout == FR_COL */
3079 {
3080 /* Only need to handle the last frame in the column. */
3081 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
3082 ;
3083 frame_add_statusline(frp);
3084 }
3085}
3086
3087/*
3088 * Set width of a frame. Handles recursively going through contained frames.
3089 * May remove separator line for windows at the right side (for win_close()).
3090 */
3091 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003092frame_new_width(
3093 frame_T *topfrp,
3094 int width,
3095 int leftfirst, /* resize leftmost contained frame first */
3096 int wfw) /* obey 'winfixwidth' when there is a choice;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003097 may cause the width not to be set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098{
3099 frame_T *frp;
3100 int extra_cols;
3101 int w;
3102 win_T *wp;
3103
3104 if (topfrp->fr_layout == FR_LEAF)
3105 {
3106 /* Simple case: just one window. */
3107 wp = topfrp->fr_win;
3108 /* Find out if there are any windows right of this one. */
3109 for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
3110 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
3111 break;
3112 if (frp->fr_parent == NULL)
3113 wp->w_vsep_width = 0;
3114 win_new_width(wp, width - wp->w_vsep_width);
3115 }
3116 else if (topfrp->fr_layout == FR_COL)
3117 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003118 do
3119 {
3120 /* All frames in this column get the same new width. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003121 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003122 {
3123 frame_new_width(frp, width, leftfirst, wfw);
3124 if (frp->fr_width > width)
3125 {
3126 /* Could not fit the windows, make whole column wider. */
3127 width = frp->fr_width;
3128 break;
3129 }
3130 }
3131 } while (frp != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 }
3133 else /* fr_layout == FR_ROW */
3134 {
3135 /* Complicated case: Resize a row of frames. Resize the rightmost
3136 * frame first, frames left of it when needed. */
3137
Bram Moolenaar071d4272004-06-13 20:20:40 +00003138 frp = topfrp->fr_child;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003139 if (wfw)
3140 /* Advance past frames with one window with 'wfw' set. */
3141 while (frame_fixed_width(frp))
3142 {
3143 frp = frp->fr_next;
3144 if (frp == NULL)
3145 return; /* no frame without 'wfw', give up */
3146 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147 if (!leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003148 {
3149 /* Find the rightmost frame of this row */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150 while (frp->fr_next != NULL)
3151 frp = frp->fr_next;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003152 if (wfw)
3153 /* Advance back for frames with one window with 'wfw' set. */
3154 while (frame_fixed_width(frp))
3155 frp = frp->fr_prev;
3156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157
3158 extra_cols = width - topfrp->fr_width;
3159 if (extra_cols < 0)
3160 {
3161 /* reduce frame width, rightmost frame first */
3162 while (frp != NULL)
3163 {
3164 w = frame_minwidth(frp, NULL);
3165 if (frp->fr_width + extra_cols < w)
3166 {
3167 extra_cols += frp->fr_width - w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003168 frame_new_width(frp, w, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 }
3170 else
3171 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003172 frame_new_width(frp, frp->fr_width + extra_cols,
3173 leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 break;
3175 }
3176 if (leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003177 {
3178 do
3179 frp = frp->fr_next;
3180 while (wfw && frp != NULL && frame_fixed_width(frp));
3181 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003182 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003183 {
3184 do
3185 frp = frp->fr_prev;
3186 while (wfw && frp != NULL && frame_fixed_width(frp));
3187 }
3188 /* Increase "width" if we could not reduce enough frames. */
3189 if (frp == NULL)
3190 width -= extra_cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191 }
3192 }
3193 else if (extra_cols > 0)
3194 {
3195 /* increase width of rightmost frame */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003196 frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 }
3198 }
3199 topfrp->fr_width = width;
3200}
3201
3202/*
3203 * Add the vertical separator to windows at the right side of "frp".
3204 * Note: Does not check if there is room!
3205 */
3206 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003207frame_add_vsep(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208{
3209 win_T *wp;
3210
3211 if (frp->fr_layout == FR_LEAF)
3212 {
3213 wp = frp->fr_win;
3214 if (wp->w_vsep_width == 0)
3215 {
3216 if (wp->w_width > 0) /* don't make it negative */
3217 --wp->w_width;
3218 wp->w_vsep_width = 1;
3219 }
3220 }
3221 else if (frp->fr_layout == FR_COL)
3222 {
3223 /* Handle all the frames in the column. */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003224 FOR_ALL_FRAMES(frp, frp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 frame_add_vsep(frp);
3226 }
3227 else /* frp->fr_layout == FR_ROW */
3228 {
3229 /* Only need to handle the last frame in the row. */
3230 frp = frp->fr_child;
3231 while (frp->fr_next != NULL)
3232 frp = frp->fr_next;
3233 frame_add_vsep(frp);
3234 }
3235}
3236
3237/*
3238 * Set frame width from the window it contains.
3239 */
3240 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003241frame_fix_width(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242{
3243 wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
3244}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245
3246/*
3247 * Set frame height from the window it contains.
3248 */
3249 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003250frame_fix_height(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251{
Bram Moolenaar415a6932017-12-05 20:31:07 +01003252 wp->w_frame->fr_height = VISIBLE_HEIGHT(wp) + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253}
3254
3255/*
3256 * Compute the minimal height for frame "topfrp".
3257 * Uses the 'winminheight' option.
3258 * When "next_curwin" isn't NULL, use p_wh for this window.
3259 * When "next_curwin" is NOWIN, don't use at least one line for the current
3260 * window.
3261 */
3262 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003263frame_minheight(frame_T *topfrp, win_T *next_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264{
3265 frame_T *frp;
3266 int m;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268
3269 if (topfrp->fr_win != NULL)
3270 {
3271 if (topfrp->fr_win == next_curwin)
3272 m = p_wh + topfrp->fr_win->w_status_height;
3273 else
3274 {
3275 /* window: minimal height of the window plus status line */
3276 m = p_wmh + topfrp->fr_win->w_status_height;
Bram Moolenaar415a6932017-12-05 20:31:07 +01003277 if (topfrp->fr_win == curwin && next_curwin == NULL)
3278 {
3279 /* Current window is minimal one line high and WinBar is
3280 * visible. */
3281 if (p_wmh == 0)
3282 ++m;
3283 m += WINBAR_HEIGHT(curwin);
3284 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 }
3286 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 else if (topfrp->fr_layout == FR_ROW)
3288 {
3289 /* get the minimal height from each frame in this row */
3290 m = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003291 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292 {
3293 n = frame_minheight(frp, next_curwin);
3294 if (n > m)
3295 m = n;
3296 }
3297 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 else
3299 {
3300 /* Add up the minimal heights for all frames in this column. */
3301 m = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003302 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003303 m += frame_minheight(frp, next_curwin);
3304 }
3305
3306 return m;
3307}
3308
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309/*
3310 * Compute the minimal width for frame "topfrp".
3311 * When "next_curwin" isn't NULL, use p_wiw for this window.
3312 * When "next_curwin" is NOWIN, don't use at least one column for the current
3313 * window.
3314 */
3315 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003316frame_minwidth(
3317 frame_T *topfrp,
3318 win_T *next_curwin) /* use p_wh and p_wiw for next_curwin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003319{
3320 frame_T *frp;
3321 int m, n;
3322
3323 if (topfrp->fr_win != NULL)
3324 {
3325 if (topfrp->fr_win == next_curwin)
3326 m = p_wiw + topfrp->fr_win->w_vsep_width;
3327 else
3328 {
3329 /* window: minimal width of the window plus separator column */
3330 m = p_wmw + topfrp->fr_win->w_vsep_width;
3331 /* Current window is minimal one column wide */
3332 if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
3333 ++m;
3334 }
3335 }
3336 else if (topfrp->fr_layout == FR_COL)
3337 {
3338 /* get the minimal width from each frame in this column */
3339 m = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003340 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003341 {
3342 n = frame_minwidth(frp, next_curwin);
3343 if (n > m)
3344 m = n;
3345 }
3346 }
3347 else
3348 {
3349 /* Add up the minimal widths for all frames in this row. */
3350 m = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01003351 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 m += frame_minwidth(frp, next_curwin);
3353 }
3354
3355 return m;
3356}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357
3358
3359/*
3360 * Try to close all windows except current one.
3361 * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
3362 * used and the buffer was modified.
3363 *
3364 * Used by ":bdel" and ":only".
3365 */
3366 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003367close_others(
3368 int message,
3369 int forceit) /* always hide all other windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370{
3371 win_T *wp;
3372 win_T *nextwp;
3373 int r;
3374
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003375 if (one_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003377 if (message && !autocmd_busy)
Bram Moolenaar32526b32019-01-19 17:43:09 +01003378 msg(_(m_onlyone));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379 return;
3380 }
3381
3382 /* Be very careful here: autocommands may change the window layout. */
3383 for (wp = firstwin; win_valid(wp); wp = nextwp)
3384 {
3385 nextwp = wp->w_next;
3386 if (wp != curwin) /* don't close current window */
3387 {
3388
3389 /* Check if it's allowed to abandon this window */
3390 r = can_abandon(wp->w_buffer, forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391 if (!win_valid(wp)) /* autocommands messed wp up */
3392 {
3393 nextwp = firstwin;
3394 continue;
3395 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 if (!r)
3397 {
3398#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3399 if (message && (p_confirm || cmdmod.confirm) && p_write)
3400 {
3401 dialog_changed(wp->w_buffer, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003402 if (!win_valid(wp)) /* autocommands messed wp up */
3403 {
3404 nextwp = firstwin;
3405 continue;
3406 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003407 }
3408 if (bufIsChanged(wp->w_buffer))
3409#endif
3410 continue;
3411 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02003412 win_close(wp, !buf_hide(wp->w_buffer)
3413 && !bufIsChanged(wp->w_buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414 }
3415 }
3416
Bram Moolenaar459ca562016-11-10 18:16:33 +01003417 if (message && !ONE_WINDOW)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003418 emsg(_("E445: Other window contains changes"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419}
3420
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003422 * Init the current window "curwin".
3423 * Called when a new file is being edited.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 */
3425 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003426curwin_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427{
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003428 win_init_empty(curwin);
3429}
3430
3431 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003432win_init_empty(win_T *wp)
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003433{
3434 redraw_win_later(wp, NOT_VALID);
3435 wp->w_lines_valid = 0;
3436 wp->w_cursor.lnum = 1;
3437 wp->w_curswant = wp->w_cursor.col = 0;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003438 wp->w_cursor.coladd = 0;
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003439 wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
3440 wp->w_pcmark.col = 0;
3441 wp->w_prev_pcmark.lnum = 0;
3442 wp->w_prev_pcmark.col = 0;
3443 wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444#ifdef FEAT_DIFF
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003445 wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003447 wp->w_botline = 2;
Bram Moolenaara971b822011-09-14 14:43:25 +02003448#ifdef FEAT_SYN_HL
3449 wp->w_s = &wp->w_buffer->b_s;
3450#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451}
3452
3453/*
3454 * Allocate the first window and put an empty buffer in it.
3455 * Called from main().
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003456 * Return FAIL when something goes wrong (out of memory).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003458 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003459win_alloc_first(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460{
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003461 if (win_alloc_firstwin(NULL) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003462 return FAIL;
3463
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003464 first_tabpage = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003465 if (first_tabpage == NULL)
3466 return FAIL;
3467 first_tabpage->tp_topframe = topframe;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003468 curtab = first_tabpage;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003469
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003470 return OK;
3471}
3472
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003473/*
3474 * Init "aucmd_win". This can only be done after the first
3475 * window is fully initialized, thus it can't be in win_alloc_first().
3476 */
3477 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003478win_alloc_aucmd_win(void)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003479{
3480 aucmd_win = win_alloc(NULL, TRUE);
3481 if (aucmd_win != NULL)
3482 {
3483 win_init_some(aucmd_win, curwin);
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003484 RESET_BINDING(aucmd_win);
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003485 new_frame(aucmd_win);
3486 }
3487}
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003488
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003489/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003490 * Allocate the first window or the first window in a new tab page.
3491 * When "oldwin" is NULL create an empty buffer for it.
Bram Moolenaar4033c552017-09-16 20:54:51 +02003492 * When "oldwin" is not NULL copy info from it to the new window.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003493 * Return FAIL when something goes wrong (out of memory).
3494 */
3495 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003496win_alloc_firstwin(win_T *oldwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003497{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003498 curwin = win_alloc(NULL, FALSE);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003499 if (oldwin == NULL)
3500 {
3501 /* Very first window, need to create an empty buffer for it and
3502 * initialize from scratch. */
3503 curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
3504 if (curwin == NULL || curbuf == NULL)
3505 return FAIL;
3506 curwin->w_buffer = curbuf;
Bram Moolenaar860cae12010-06-05 23:22:07 +02003507#ifdef FEAT_SYN_HL
3508 curwin->w_s = &(curbuf->b_s);
3509#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003510 curbuf->b_nwindows = 1; /* there is one window */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003511 curwin->w_alist = &global_alist;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003512 curwin_init(); /* init current window */
3513 }
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003514 else
3515 {
3516 /* First window in new tab page, initialize it from "oldwin". */
Bram Moolenaar884ae642009-02-22 01:37:59 +00003517 win_init(curwin, oldwin, 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003518
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003519 /* We don't want cursor- and scroll-binding in the first window. */
3520 RESET_BINDING(curwin);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003521 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003523 new_frame(curwin);
3524 if (curwin->w_frame == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003525 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003526 topframe = curwin->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527 topframe->fr_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528 topframe->fr_height = Rows - p_ch;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003529
3530 return OK;
3531}
3532
3533/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003534 * Create a frame for window "wp".
3535 */
3536 static void
3537new_frame(win_T *wp)
3538{
3539 frame_T *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
3540
3541 wp->w_frame = frp;
3542 if (frp != NULL)
3543 {
3544 frp->fr_layout = FR_LEAF;
3545 frp->fr_win = wp;
3546 }
3547}
3548
3549/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003550 * Initialize the window and frame size to the maximum.
3551 */
3552 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003553win_init_size(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003554{
3555 firstwin->w_height = ROWS_AVAIL;
3556 topframe->fr_height = ROWS_AVAIL;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003557 firstwin->w_width = Columns;
3558 topframe->fr_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559}
3560
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003561/*
3562 * Allocate a new tabpage_T and init the values.
3563 * Returns NULL when out of memory.
3564 */
3565 static tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003566alloc_tabpage(void)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003567{
3568 tabpage_T *tp;
Bram Moolenaar429fa852013-04-15 12:27:36 +02003569# ifdef FEAT_GUI
3570 int i;
3571# endif
3572
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003573
3574 tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02003575 if (tp == NULL)
3576 return NULL;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003577
Bram Moolenaar429fa852013-04-15 12:27:36 +02003578# ifdef FEAT_EVAL
3579 /* init t: variables */
3580 tp->tp_vars = dict_alloc();
3581 if (tp->tp_vars == NULL)
3582 {
3583 vim_free(tp);
3584 return NULL;
3585 }
3586 init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
3587# endif
3588
3589# ifdef FEAT_GUI
3590 for (i = 0; i < 3; i++)
3591 tp->tp_prev_which_scrollbars[i] = -1;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003592# endif
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003593# ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02003594 tp->tp_diff_invalid = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003595# endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02003596 tp->tp_ch_used = p_ch;
3597
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003598 return tp;
3599}
3600
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00003601 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003602free_tabpage(tabpage_T *tp)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003603{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003604 int idx;
3605
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003606# ifdef FEAT_DIFF
3607 diff_clear(tp);
3608# endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003609 for (idx = 0; idx < SNAP_COUNT; ++idx)
3610 clear_snapshot(tp, idx);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003611#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02003612 vars_clear(&tp->tp_vars->dv_hashtab); /* free all t: variables */
3613 hash_init(&tp->tp_vars->dv_hashtab);
3614 unref_var_dict(tp->tp_vars);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003615#endif
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02003616
3617#ifdef FEAT_PYTHON
3618 python_tabpage_free(tp);
3619#endif
3620
3621#ifdef FEAT_PYTHON3
3622 python3_tabpage_free(tp);
3623#endif
3624
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003625 vim_free(tp);
3626}
3627
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003628/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003629 * Create a new Tab page with one window.
3630 * It will edit the current buffer, like after ":split".
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003631 * When "after" is 0 put it just after the current Tab page.
3632 * Otherwise put it just before tab page "after".
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003633 * Return FAIL or OK.
3634 */
3635 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003636win_new_tabpage(int after)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003637{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003638 tabpage_T *tp = curtab;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003639 tabpage_T *newtp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003640 int n;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003641
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003642 newtp = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003643 if (newtp == NULL)
3644 return FAIL;
3645
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003646 /* Remember the current windows in this Tab page. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003647 if (leave_tabpage(curbuf, TRUE) == FAIL)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003648 {
3649 vim_free(newtp);
3650 return FAIL;
3651 }
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003652 curtab = newtp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003653
3654 /* Create a new empty window. */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003655 if (win_alloc_firstwin(tp->tp_curwin) == OK)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003656 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003657 /* Make the new Tab page the new topframe. */
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003658 if (after == 1)
3659 {
3660 /* New tab page becomes the first one. */
3661 newtp->tp_next = first_tabpage;
3662 first_tabpage = newtp;
3663 }
3664 else
3665 {
3666 if (after > 0)
3667 {
3668 /* Put new tab page before tab page "after". */
3669 n = 2;
3670 for (tp = first_tabpage; tp->tp_next != NULL
3671 && n < after; tp = tp->tp_next)
3672 ++n;
3673 }
3674 newtp->tp_next = tp->tp_next;
3675 tp->tp_next = newtp;
3676 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003677 win_init_size();
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003678 firstwin->w_winrow = tabline_height();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003679 win_comp_scroll(curwin);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003680
3681 newtp->tp_topframe = topframe;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003682 last_status(FALSE);
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003683
3684#if defined(FEAT_GUI)
3685 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3686 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003687 gui_may_update_scrollbars();
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003688#endif
Bram Moolenaar6d41c782018-06-06 09:11:12 +02003689#ifdef FEAT_JOB_CHANNEL
3690 entering_window(curwin);
3691#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003692
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01003693 redraw_all_later(NOT_VALID);
Bram Moolenaarc917da42016-07-19 22:31:36 +02003694 apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003695 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaarc917da42016-07-19 22:31:36 +02003696 apply_autocmds(EVENT_TABNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003697 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003698 return OK;
3699 }
3700
3701 /* Failed, get back the previous Tab page */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003702 enter_tabpage(curtab, curbuf, TRUE, TRUE);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003703 return FAIL;
3704}
3705
3706/*
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003707 * Open a new tab page if ":tab cmd" was used. It will edit the same buffer,
3708 * like with ":split".
3709 * Returns OK if a new tab page was created, FAIL otherwise.
3710 */
3711 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003712may_open_tabpage(void)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003713{
Bram Moolenaard326ce82007-03-11 14:48:29 +00003714 int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003715
Bram Moolenaard326ce82007-03-11 14:48:29 +00003716 if (n != 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003717 {
3718 cmdmod.tab = 0; /* reset it to avoid doing it twice */
Bram Moolenaard326ce82007-03-11 14:48:29 +00003719 postponed_split_tab = 0;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003720 return win_new_tabpage(n);
3721 }
3722 return FAIL;
3723}
3724
3725/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003726 * Create up to "maxcount" tabpages with empty windows.
3727 * Returns the number of resulting tab pages.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003728 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003729 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003730make_tabpages(int maxcount)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003731{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003732 int count = maxcount;
3733 int todo;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003734
Bram Moolenaare1438bb2006-03-01 22:01:55 +00003735 /* Limit to 'tabpagemax' tabs. */
3736 if (count > p_tpm)
3737 count = p_tpm;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003738
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003739 /*
3740 * Don't execute autocommands while creating the tab pages. Must do that
3741 * when putting the buffers in the windows.
3742 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003743 block_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003744
3745 for (todo = count - 1; todo > 0; --todo)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003746 if (win_new_tabpage(0) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003747 break;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003748
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003749 unblock_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003750
3751 /* return actual number of tab pages */
3752 return (count - todo);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003753}
3754
3755/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003756 * Return TRUE when "tpc" points to a valid tab page.
3757 */
3758 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003759valid_tabpage(tabpage_T *tpc)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003760{
3761 tabpage_T *tp;
3762
Bram Moolenaar29323592016-07-24 22:04:11 +02003763 FOR_ALL_TABPAGES(tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003764 if (tp == tpc)
3765 return TRUE;
3766 return FALSE;
3767}
3768
3769/*
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01003770 * Return TRUE when "tpc" points to a valid tab page and at least one window is
3771 * valid.
3772 */
3773 int
3774valid_tabpage_win(tabpage_T *tpc)
3775{
3776 tabpage_T *tp;
3777 win_T *wp;
3778
3779 FOR_ALL_TABPAGES(tp)
3780 {
3781 if (tp == tpc)
3782 {
3783 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
3784 {
3785 if (win_valid_any_tab(wp))
3786 return TRUE;
3787 }
3788 return FALSE;
3789 }
3790 }
3791 /* shouldn't happen */
3792 return FALSE;
3793}
3794
3795/*
3796 * Close tabpage "tab", assuming it has no windows in it.
3797 * There must be another tabpage or this will crash.
3798 */
3799 void
3800close_tabpage(tabpage_T *tab)
3801{
3802 tabpage_T *ptp;
3803
3804 if (tab == first_tabpage)
3805 {
3806 first_tabpage = tab->tp_next;
3807 ptp = first_tabpage;
3808 }
3809 else
3810 {
3811 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
3812 ptp = ptp->tp_next)
3813 ;
Bram Moolenaara37ffaa2017-03-21 21:58:00 +01003814 assert(ptp != NULL);
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01003815 ptp->tp_next = tab->tp_next;
3816 }
3817
3818 goto_tabpage_tp(ptp, FALSE, FALSE);
3819 free_tabpage(tab);
3820}
3821
3822/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003823 * Find tab page "n" (first one is 1). Returns NULL when not found.
3824 */
3825 tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003826find_tabpage(int n)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003827{
3828 tabpage_T *tp;
3829 int i = 1;
3830
3831 for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
3832 ++i;
3833 return tp;
3834}
3835
3836/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003837 * Get index of tab page "tp". First one has index 1.
Bram Moolenaarba6c0522006-02-25 21:45:02 +00003838 * When not found returns number of tab pages plus one.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003839 */
3840 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003841tabpage_index(tabpage_T *ftp)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003842{
3843 int i = 1;
3844 tabpage_T *tp;
3845
3846 for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
3847 ++i;
3848 return i;
3849}
3850
3851/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003852 * Prepare for leaving the current tab page.
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003853 * When autocommands change "curtab" we don't leave the tab page and return
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003854 * FAIL.
3855 * Careful: When OK is returned need to get a new tab page very very soon!
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003856 */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003857 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003858leave_tabpage(
3859 buf_T *new_curbuf UNUSED, /* what is going to be the new curbuf,
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003860 NULL if unknown */
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003861 int trigger_leave_autocmds UNUSED)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003862{
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003863 tabpage_T *tp = curtab;
3864
Bram Moolenaar6d41c782018-06-06 09:11:12 +02003865#ifdef FEAT_JOB_CHANNEL
3866 leaving_window(curwin);
3867#endif
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003868 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003869 if (trigger_leave_autocmds)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003870 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003871 if (new_curbuf != curbuf)
3872 {
3873 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
3874 if (curtab != tp)
3875 return FAIL;
3876 }
3877 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
3878 if (curtab != tp)
3879 return FAIL;
3880 apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003881 if (curtab != tp)
3882 return FAIL;
3883 }
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003884#if defined(FEAT_GUI)
3885 /* Remove the scrollbars. They may be added back later. */
3886 if (gui.in_use)
3887 gui_remove_scrollbars();
3888#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003889 tp->tp_curwin = curwin;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003890 tp->tp_prevwin = prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003891 tp->tp_firstwin = firstwin;
3892 tp->tp_lastwin = lastwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003893 tp->tp_old_Rows = Rows;
3894 tp->tp_old_Columns = Columns;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003895 firstwin = NULL;
3896 lastwin = NULL;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003897 return OK;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003898}
3899
3900/*
3901 * Start using tab page "tp".
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003902 * Only to be used after leave_tabpage() or freeing the current tab page.
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003903 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
3904 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003905 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003906 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003907enter_tabpage(
3908 tabpage_T *tp,
3909 buf_T *old_curbuf UNUSED,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01003910 int trigger_enter_autocmds,
3911 int trigger_leave_autocmds)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003912{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003913 int old_off = tp->tp_firstwin->w_winrow;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003914 win_T *next_prevwin = tp->tp_prevwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003915
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003916 curtab = tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003917 firstwin = tp->tp_firstwin;
3918 lastwin = tp->tp_lastwin;
3919 topframe = tp->tp_topframe;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003920
3921 /* We would like doing the TabEnter event first, but we don't have a
3922 * valid current window yet, which may break some commands.
3923 * This triggers autocommands, thus may make "tp" invalid. */
Bram Moolenaarc917da42016-07-19 22:31:36 +02003924 win_enter_ext(tp->tp_curwin, FALSE, TRUE, FALSE,
Bram Moolenaard6949742013-06-16 14:18:28 +02003925 trigger_enter_autocmds, trigger_leave_autocmds);
Bram Moolenaar773560b2006-05-06 21:38:18 +00003926 prevwin = next_prevwin;
3927
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003928 last_status(FALSE); /* status line may appear or disappear */
3929 (void)win_comp_pos(); /* recompute w_winrow for all windows */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003930#ifdef FEAT_DIFF
3931 diff_need_scrollbind = TRUE;
3932#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003933
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003934 /* The tabpage line may have appeared or disappeared, may need to resize
3935 * the frames for that. When the Vim window was resized need to update
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003936 * frame sizes too. Use the stored value of p_ch, so that it can be
3937 * different for each tab page. */
3938 p_ch = curtab->tp_ch_used;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003939 if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
3940#ifdef FEAT_GUI_TABLINE
3941 && !gui_use_tabline()
3942#endif
3943 ))
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003944 shell_new_rows();
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003945 if (curtab->tp_old_Columns != Columns && starting == 0)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003946 shell_new_columns(); /* update window widths */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003947
3948#if defined(FEAT_GUI)
3949 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3950 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003951 gui_may_update_scrollbars();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003952#endif
3953
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003954 /* Apply autocommands after updating the display, when 'rows' and
3955 * 'columns' have been set correctly. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003956 if (trigger_enter_autocmds)
Bram Moolenaara8596c42012-06-13 14:28:20 +02003957 {
3958 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
3959 if (old_curbuf != curbuf)
3960 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
3961 }
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003962
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01003963 redraw_all_later(NOT_VALID);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003964}
3965
3966/*
3967 * Go to tab page "n". For ":tab N" and "Ngt".
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003968 * When "n" is 9999 go to the last tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003969 */
3970 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003971goto_tabpage(int n)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003972{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003973 tabpage_T *tp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003974 tabpage_T *ttp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003975 int i;
3976
Bram Moolenaard68071d2006-05-02 22:08:30 +00003977 if (text_locked())
3978 {
3979 /* Not allowed when editing the command line. */
Bram Moolenaar5a497892016-09-03 16:29:04 +02003980 text_locked_msg();
Bram Moolenaard68071d2006-05-02 22:08:30 +00003981 return;
3982 }
3983
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003984 /* If there is only one it can't work. */
3985 if (first_tabpage->tp_next == NULL)
3986 {
3987 if (n > 1)
3988 beep_flush();
3989 return;
3990 }
3991
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003992 if (n == 0)
3993 {
3994 /* No count, go to next tab page, wrap around end. */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003995 if (curtab->tp_next == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003996 tp = first_tabpage;
3997 else
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003998 tp = curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003999 }
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004000 else if (n < 0)
4001 {
4002 /* "gT": go to previous tab page, wrap around end. "N gT" repeats
4003 * this N times. */
4004 ttp = curtab;
4005 for (i = n; i < 0; ++i)
4006 {
4007 for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
4008 tp = tp->tp_next)
4009 ;
4010 ttp = tp;
4011 }
4012 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004013 else if (n == 9999)
4014 {
4015 /* Go to last tab page. */
4016 for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
4017 ;
4018 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004019 else
4020 {
4021 /* Go to tab page "n". */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004022 tp = find_tabpage(n);
Bram Moolenaarf740b292006-02-16 22:11:02 +00004023 if (tp == NULL)
4024 {
4025 beep_flush();
4026 return;
4027 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004028 }
4029
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004030 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004031
4032#ifdef FEAT_GUI_TABLINE
4033 if (gui_use_tabline())
Bram Moolenaara226a6d2006-02-26 23:59:20 +00004034 gui_mch_set_curtab(tabpage_index(curtab));
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004035#endif
4036}
4037
4038/*
4039 * Go to tabpage "tp".
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004040 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
4041 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004042 * Note: doesn't update the GUI tab.
4043 */
4044 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004045goto_tabpage_tp(
4046 tabpage_T *tp,
4047 int trigger_enter_autocmds,
4048 int trigger_leave_autocmds)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004049{
Bram Moolenaarc6af8122010-05-21 12:04:55 +02004050 /* Don't repeat a message in another tab page. */
4051 set_keep_msg(NULL, 0);
4052
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004053 if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
4054 trigger_leave_autocmds) == OK)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004055 {
4056 if (valid_tabpage(tp))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004057 enter_tabpage(tp, curbuf, trigger_enter_autocmds,
4058 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004059 else
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004060 enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
4061 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004062 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004063}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064
4065/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004066 * Enter window "wp" in tab page "tp".
4067 * Also updates the GUI tab.
4068 */
4069 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004070goto_tabpage_win(tabpage_T *tp, win_T *wp)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004071{
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004072 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004073 if (curtab == tp && win_valid(wp))
4074 {
4075 win_enter(wp, TRUE);
4076# ifdef FEAT_GUI_TABLINE
4077 if (gui_use_tabline())
4078 gui_mch_set_curtab(tabpage_index(curtab));
4079# endif
4080 }
4081}
4082
4083/*
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004084 * Move the current tab page to after tab page "nr".
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004085 */
4086 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004087tabpage_move(int nr)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004088{
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004089 int n = 1;
4090 tabpage_T *tp, *tp_dst;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004091
4092 if (first_tabpage->tp_next == NULL)
4093 return;
4094
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004095 for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next)
4096 ++n;
4097
4098 if (tp == curtab || (nr > 0 && tp->tp_next != NULL
4099 && tp->tp_next == curtab))
4100 return;
4101
4102 tp_dst = tp;
4103
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004104 /* Remove the current tab page from the list of tab pages. */
4105 if (curtab == first_tabpage)
4106 first_tabpage = curtab->tp_next;
4107 else
4108 {
Bram Moolenaar29323592016-07-24 22:04:11 +02004109 FOR_ALL_TABPAGES(tp)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004110 if (tp->tp_next == curtab)
4111 break;
4112 if (tp == NULL) /* "cannot happen" */
4113 return;
4114 tp->tp_next = curtab->tp_next;
4115 }
4116
4117 /* Re-insert it at the specified position. */
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004118 if (nr <= 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004119 {
4120 curtab->tp_next = first_tabpage;
4121 first_tabpage = curtab;
4122 }
4123 else
4124 {
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004125 curtab->tp_next = tp_dst->tp_next;
4126 tp_dst->tp_next = curtab;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004127 }
4128
4129 /* Need to redraw the tabline. Tab page contents doesn't change. */
4130 redraw_tabline = TRUE;
4131}
4132
4133
4134/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 * Go to another window.
4136 * When jumping to another buffer, stop Visual mode. Do this before
4137 * changing windows so we can yank the selection into the '*' register.
4138 * When jumping to another window on the same buffer, adjust its cursor
4139 * position to keep the same Visual area.
4140 */
4141 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004142win_goto(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143{
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004144#ifdef FEAT_CONCEAL
4145 win_T *owp = curwin;
4146#endif
4147
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004148 if (text_locked())
Bram Moolenaar071d4272004-06-13 20:20:40 +00004149 {
4150 beep_flush();
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004151 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152 return;
4153 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004154 if (curbuf_locked())
4155 return;
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00004156
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 if (wp->w_buffer != curbuf)
4158 reset_VIsual_and_resel();
4159 else if (VIsual_active)
4160 wp->w_cursor = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161
4162#ifdef FEAT_GUI
4163 need_mouse_correct = TRUE;
4164#endif
4165 win_enter(wp, TRUE);
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004166
4167#ifdef FEAT_CONCEAL
Bram Moolenaar535d5b62019-01-11 20:45:36 +01004168 // Conceal cursor line in previous window, unconceal in current window.
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004169 if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
Bram Moolenaar535d5b62019-01-11 20:45:36 +01004170 redrawWinline(owp, owp->w_cursor.lnum);
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004171 if (curwin->w_p_cole > 0 && !msg_scrolled)
4172 need_cursor_line_redraw = TRUE;
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004173#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174}
4175
4176#if defined(FEAT_PERL) || defined(PROTO)
4177/*
4178 * Find window number "winnr" (counting top to bottom).
4179 */
4180 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004181win_find_nr(int winnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182{
4183 win_T *wp;
4184
Bram Moolenaar29323592016-07-24 22:04:11 +02004185 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 if (--winnr == 0)
4187 break;
4188 return wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189}
4190#endif
4191
Bram Moolenaar4033c552017-09-16 20:54:51 +02004192#if ((defined(FEAT_PYTHON) || defined(FEAT_PYTHON3))) || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004193/*
4194 * Find the tabpage for window "win".
4195 */
4196 tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004197win_find_tabpage(win_T *win)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004198{
4199 win_T *wp;
4200 tabpage_T *tp;
4201
Bram Moolenaar29323592016-07-24 22:04:11 +02004202 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004203 if (wp == win)
4204 return tp;
4205 return NULL;
4206}
4207#endif
4208
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209/*
4210 * Move to window above or below "count" times.
4211 */
4212 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004213win_goto_ver(
4214 int up, /* TRUE to go to win above */
4215 long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216{
4217 frame_T *fr;
4218 frame_T *nfr;
4219 frame_T *foundfr;
4220
4221 foundfr = curwin->w_frame;
4222 while (count--)
4223 {
4224 /*
4225 * First go upwards in the tree of frames until we find a upwards or
4226 * downwards neighbor.
4227 */
4228 fr = foundfr;
4229 for (;;)
4230 {
4231 if (fr == topframe)
4232 goto end;
4233 if (up)
4234 nfr = fr->fr_prev;
4235 else
4236 nfr = fr->fr_next;
4237 if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
4238 break;
4239 fr = fr->fr_parent;
4240 }
4241
4242 /*
4243 * Now go downwards to find the bottom or top frame in it.
4244 */
4245 for (;;)
4246 {
4247 if (nfr->fr_layout == FR_LEAF)
4248 {
4249 foundfr = nfr;
4250 break;
4251 }
4252 fr = nfr->fr_child;
4253 if (nfr->fr_layout == FR_ROW)
4254 {
4255 /* Find the frame at the cursor row. */
4256 while (fr->fr_next != NULL
4257 && frame2win(fr)->w_wincol + fr->fr_width
4258 <= curwin->w_wincol + curwin->w_wcol)
4259 fr = fr->fr_next;
4260 }
4261 if (nfr->fr_layout == FR_COL && up)
4262 while (fr->fr_next != NULL)
4263 fr = fr->fr_next;
4264 nfr = fr;
4265 }
4266 }
4267end:
4268 if (foundfr != NULL)
4269 win_goto(foundfr->fr_win);
4270}
4271
4272/*
4273 * Move to left or right window.
4274 */
4275 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004276win_goto_hor(
4277 int left, /* TRUE to go to left win */
4278 long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279{
4280 frame_T *fr;
4281 frame_T *nfr;
4282 frame_T *foundfr;
4283
4284 foundfr = curwin->w_frame;
4285 while (count--)
4286 {
4287 /*
4288 * First go upwards in the tree of frames until we find a left or
4289 * right neighbor.
4290 */
4291 fr = foundfr;
4292 for (;;)
4293 {
4294 if (fr == topframe)
4295 goto end;
4296 if (left)
4297 nfr = fr->fr_prev;
4298 else
4299 nfr = fr->fr_next;
4300 if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
4301 break;
4302 fr = fr->fr_parent;
4303 }
4304
4305 /*
4306 * Now go downwards to find the leftmost or rightmost frame in it.
4307 */
4308 for (;;)
4309 {
4310 if (nfr->fr_layout == FR_LEAF)
4311 {
4312 foundfr = nfr;
4313 break;
4314 }
4315 fr = nfr->fr_child;
4316 if (nfr->fr_layout == FR_COL)
4317 {
4318 /* Find the frame at the cursor row. */
4319 while (fr->fr_next != NULL
4320 && frame2win(fr)->w_winrow + fr->fr_height
4321 <= curwin->w_winrow + curwin->w_wrow)
4322 fr = fr->fr_next;
4323 }
4324 if (nfr->fr_layout == FR_ROW && left)
4325 while (fr->fr_next != NULL)
4326 fr = fr->fr_next;
4327 nfr = fr;
4328 }
4329 }
4330end:
4331 if (foundfr != NULL)
4332 win_goto(foundfr->fr_win);
4333}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334
4335/*
4336 * Make window "wp" the current window.
4337 */
4338 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004339win_enter(win_T *wp, int undo_sync)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340{
Bram Moolenaarc917da42016-07-19 22:31:36 +02004341 win_enter_ext(wp, undo_sync, FALSE, FALSE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342}
4343
4344/*
4345 * Make window wp the current window.
4346 * Can be called with "curwin_invalid" TRUE, which means that curwin has just
4347 * been closed and isn't valid.
4348 */
4349 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004350win_enter_ext(
4351 win_T *wp,
4352 int undo_sync,
4353 int curwin_invalid,
Bram Moolenaar6f470022018-04-10 18:47:20 +02004354 int trigger_new_autocmds,
4355 int trigger_enter_autocmds,
4356 int trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004358 int other_buffer = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359
4360 if (wp == curwin && !curwin_invalid) /* nothing to do */
4361 return;
4362
Bram Moolenaar6d41c782018-06-06 09:11:12 +02004363#ifdef FEAT_JOB_CHANNEL
4364 if (!curwin_invalid)
4365 leaving_window(curwin);
4366#endif
4367
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004368 if (!curwin_invalid && trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 {
4370 /*
4371 * Be careful: If autocommands delete the window, return now.
4372 */
4373 if (wp->w_buffer != curbuf)
4374 {
4375 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
4376 other_buffer = TRUE;
4377 if (!win_valid(wp))
4378 return;
4379 }
4380 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
4381 if (!win_valid(wp))
4382 return;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004383#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 /* autocmds may abort script processing */
4385 if (aborting())
4386 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004388 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389
4390 /* sync undo before leaving the current buffer */
4391 if (undo_sync && curbuf != wp->w_buffer)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004392 u_sync(FALSE);
Bram Moolenaarec1561c2014-06-17 13:52:40 +02004393
4394 /* Might need to scroll the old window before switching, e.g., when the
4395 * cursor was moved. */
4396 update_topline();
4397
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398 /* may have to copy the buffer options when 'cpo' contains 'S' */
4399 if (wp->w_buffer != curbuf)
4400 buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
4401 if (!curwin_invalid)
4402 {
4403 prevwin = curwin; /* remember for CTRL-W p */
4404 curwin->w_redr_status = TRUE;
4405 }
4406 curwin = wp;
4407 curbuf = wp->w_buffer;
4408 check_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004409 if (!virtual_active())
4410 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411 changed_line_abv_curs(); /* assume cursor position needs updating */
4412
4413 if (curwin->w_localdir != NULL)
4414 {
4415 /* Window has a local directory: Save current directory as global
4416 * directory (unless that was done already) and change to the local
4417 * directory. */
4418 if (globaldir == NULL)
4419 {
4420 char_u cwd[MAXPATHL];
4421
4422 if (mch_dirname(cwd, MAXPATHL) == OK)
4423 globaldir = vim_strsave(cwd);
4424 }
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004425 if (mch_chdir((char *)curwin->w_localdir) == 0)
4426 shorten_fnames(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004427 }
4428 else if (globaldir != NULL)
4429 {
4430 /* Window doesn't have a local directory and we are not in the global
4431 * directory: Change to the global directory. */
Bram Moolenaar42335f52018-09-13 15:33:43 +02004432 vim_ignored = mch_chdir((char *)globaldir);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004433 VIM_CLEAR(globaldir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 shorten_fnames(TRUE);
4435 }
4436
Bram Moolenaar6d41c782018-06-06 09:11:12 +02004437#ifdef FEAT_JOB_CHANNEL
4438 entering_window(curwin);
4439#endif
Bram Moolenaarc917da42016-07-19 22:31:36 +02004440 if (trigger_new_autocmds)
4441 apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004442 if (trigger_enter_autocmds)
4443 {
4444 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
4445 if (other_buffer)
4446 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
4447 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448
4449#ifdef FEAT_TITLE
4450 maketitle();
4451#endif
4452 curwin->w_redr_status = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00004453 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 if (restart_edit)
4455 redraw_later(VALID); /* causes status line redraw */
4456
4457 /* set window height to desired minimal value */
4458 if (curwin->w_height < p_wh && !curwin->w_p_wfh)
4459 win_setheight((int)p_wh);
4460 else if (curwin->w_height == 0)
4461 win_setheight(1);
4462
Bram Moolenaar071d4272004-06-13 20:20:40 +00004463 /* set window width to desired minimal value */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004464 if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 win_setwidth((int)p_wiw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466
4467#ifdef FEAT_MOUSE
4468 setmouse(); /* in case jumped to/from help buffer */
4469#endif
4470
Bram Moolenaar498efdb2006-09-05 14:31:54 +00004471 /* Change directories when the 'acd' option is set. */
Bram Moolenaar6f470022018-04-10 18:47:20 +02004472 DO_AUTOCHDIR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473}
4474
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475
Bram Moolenaar071d4272004-06-13 20:20:40 +00004476/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004477 * Jump to the first open window that contains buffer "buf", if one exists.
4478 * Returns a pointer to the window found, otherwise NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 */
4480 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004481buf_jump_open_win(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482{
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004483 win_T *wp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004485 if (curwin->w_buffer == buf)
4486 wp = curwin;
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004487 else
Bram Moolenaar29323592016-07-24 22:04:11 +02004488 FOR_ALL_WINDOWS(wp)
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004489 if (wp->w_buffer == buf)
4490 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 if (wp != NULL)
4492 win_enter(wp, FALSE);
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004493 return wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494}
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004495
4496/*
4497 * Jump to the first open window in any tab page that contains buffer "buf",
4498 * if one exists.
4499 * Returns a pointer to the window found, otherwise NULL.
4500 */
4501 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004502buf_jump_open_tab(buf_T *buf)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004503{
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004504 win_T *wp = buf_jump_open_win(buf);
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004505 tabpage_T *tp;
4506
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004507 if (wp != NULL)
4508 return wp;
4509
Bram Moolenaar29323592016-07-24 22:04:11 +02004510 FOR_ALL_TABPAGES(tp)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004511 if (tp != curtab)
4512 {
4513 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
4514 if (wp->w_buffer == buf)
4515 break;
4516 if (wp != NULL)
4517 {
4518 goto_tabpage_win(tp, wp);
4519 if (curwin != wp)
4520 wp = NULL; /* something went wrong */
4521 break;
4522 }
4523 }
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004524 return wp;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004525}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526
Bram Moolenaar888ccac2016-06-04 18:49:36 +02004527static int last_win_id = LOWEST_WIN_ID - 1;
Bram Moolenaar86edef62016-03-13 18:07:30 +01004528
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004530 * Allocate a window structure and link it in the window list when "hidden" is
4531 * FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004534win_alloc(win_T *after UNUSED, int hidden UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004536 win_T *new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537
4538 /*
4539 * allocate window structure and linesizes arrays
4540 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004541 new_wp = (win_T *)alloc_clear((unsigned)sizeof(win_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02004542 if (new_wp == NULL)
4543 return NULL;
4544
4545 if (win_alloc_lines(new_wp) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004547 vim_free(new_wp);
Bram Moolenaar429fa852013-04-15 12:27:36 +02004548 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 }
4550
Bram Moolenaar86edef62016-03-13 18:07:30 +01004551 new_wp->w_id = ++last_win_id;
4552
Bram Moolenaar429fa852013-04-15 12:27:36 +02004553#ifdef FEAT_EVAL
4554 /* init w: variables */
4555 new_wp->w_vars = dict_alloc();
4556 if (new_wp->w_vars == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 {
Bram Moolenaar429fa852013-04-15 12:27:36 +02004558 win_free_lsize(new_wp);
4559 vim_free(new_wp);
4560 return NULL;
4561 }
4562 init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004563#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004564
Bram Moolenaar429fa852013-04-15 12:27:36 +02004565 /* Don't execute autocommands while the window is not properly
4566 * initialized yet. gui_create_scrollbar() may trigger a FocusGained
4567 * event. */
4568 block_autocmds();
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004569
Bram Moolenaar429fa852013-04-15 12:27:36 +02004570 /*
4571 * link the window in the window list
4572 */
Bram Moolenaar429fa852013-04-15 12:27:36 +02004573 if (!hidden)
4574 win_append(after, new_wp);
Bram Moolenaar429fa852013-04-15 12:27:36 +02004575 new_wp->w_wincol = 0;
4576 new_wp->w_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577
Bram Moolenaar429fa852013-04-15 12:27:36 +02004578 /* position the display and the cursor at the top of the file. */
4579 new_wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580#ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02004581 new_wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004583 new_wp->w_botline = 2;
4584 new_wp->w_cursor.lnum = 1;
Bram Moolenaar429fa852013-04-15 12:27:36 +02004585 new_wp->w_scbind_pos = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586
Bram Moolenaar375e3392019-01-31 18:26:10 +01004587 // use global option value for global-local options
4588 new_wp->w_p_so = -1;
4589 new_wp->w_p_siso = -1;
4590
Bram Moolenaar429fa852013-04-15 12:27:36 +02004591 /* We won't calculate w_fraction until resizing the window */
4592 new_wp->w_fraction = 0;
4593 new_wp->w_prev_fraction_row = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
4595#ifdef FEAT_GUI
Bram Moolenaar429fa852013-04-15 12:27:36 +02004596 if (gui.in_use)
4597 {
4598 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
4599 SBAR_LEFT, new_wp);
4600 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
4601 SBAR_RIGHT, new_wp);
4602 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603#endif
4604#ifdef FEAT_FOLDING
Bram Moolenaar429fa852013-04-15 12:27:36 +02004605 foldInitWin(new_wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004607 unblock_autocmds();
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004608#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar429fa852013-04-15 12:27:36 +02004609 new_wp->w_match_head = NULL;
4610 new_wp->w_next_match_id = 4;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004611#endif
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004612 return new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613}
4614
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615/*
Bram Moolenaarff18df02013-07-24 17:51:57 +02004616 * Remove window 'wp' from the window list and free the structure.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 */
4618 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004619win_free(
4620 win_T *wp,
4621 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622{
4623 int i;
Bram Moolenaarff18df02013-07-24 17:51:57 +02004624 buf_T *buf;
4625 wininfo_T *wip;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004627#ifdef FEAT_FOLDING
4628 clearFolding(wp);
4629#endif
4630
4631 /* reduce the reference count to the argument list. */
4632 alist_unlink(wp->w_alist);
4633
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004634 /* Don't execute autocommands while the window is halfway being deleted.
4635 * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004636 block_autocmds();
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004637
Bram Moolenaar0ba04292010-07-14 23:23:17 +02004638#ifdef FEAT_LUA
4639 lua_window_free(wp);
4640#endif
4641
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004642#ifdef FEAT_MZSCHEME
4643 mzscheme_window_free(wp);
4644#endif
4645
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646#ifdef FEAT_PERL
4647 perl_win_free(wp);
4648#endif
4649
4650#ifdef FEAT_PYTHON
4651 python_window_free(wp);
4652#endif
4653
Bram Moolenaarbd5e15f2010-07-17 21:19:38 +02004654#ifdef FEAT_PYTHON3
4655 python3_window_free(wp);
4656#endif
4657
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658#ifdef FEAT_TCL
4659 tcl_window_free(wp);
4660#endif
4661
4662#ifdef FEAT_RUBY
4663 ruby_window_free(wp);
4664#endif
4665
4666 clear_winopt(&wp->w_onebuf_opt);
4667 clear_winopt(&wp->w_allbuf_opt);
4668
4669#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02004670 vars_clear(&wp->w_vars->dv_hashtab); /* free all w: variables */
4671 hash_init(&wp->w_vars->dv_hashtab);
4672 unref_var_dict(wp->w_vars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673#endif
4674
Bram Moolenaar3dda7db2016-04-03 21:22:58 +02004675 {
4676 tabpage_T *ttp;
4677
4678 if (prevwin == wp)
4679 prevwin = NULL;
Bram Moolenaar29323592016-07-24 22:04:11 +02004680 FOR_ALL_TABPAGES(ttp)
Bram Moolenaar3dda7db2016-04-03 21:22:58 +02004681 if (ttp->tp_prevwin == wp)
4682 ttp->tp_prevwin = NULL;
4683 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684 win_free_lsize(wp);
4685
4686 for (i = 0; i < wp->w_tagstacklen; ++i)
4687 vim_free(wp->w_tagstack[i].tagname);
4688
4689 vim_free(wp->w_localdir);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004690
Bram Moolenaarff18df02013-07-24 17:51:57 +02004691 /* Remove the window from the b_wininfo lists, it may happen that the
4692 * freed memory is re-used for another window. */
Bram Moolenaar29323592016-07-24 22:04:11 +02004693 FOR_ALL_BUFFERS(buf)
Bram Moolenaarff18df02013-07-24 17:51:57 +02004694 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
4695 if (wip->wi_win == wp)
4696 wip->wi_win = NULL;
4697
Bram Moolenaar071d4272004-06-13 20:20:40 +00004698#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004699 clear_matches(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004701
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702#ifdef FEAT_JUMPLIST
4703 free_jumplist(wp);
4704#endif
4705
Bram Moolenaar28c258f2006-01-25 22:02:51 +00004706#ifdef FEAT_QUICKFIX
4707 qf_free_all(wp);
4708#endif
4709
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710#ifdef FEAT_GUI
4711 if (gui.in_use)
4712 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
4714 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
4715 }
4716#endif /* FEAT_GUI */
4717
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004718#ifdef FEAT_MENU
4719 remove_winbar(wp);
4720#endif
4721
Bram Moolenaar860cae12010-06-05 23:22:07 +02004722#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02004723 vim_free(wp->w_p_cc_cols);
Bram Moolenaar860cae12010-06-05 23:22:07 +02004724#endif
4725
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004726 if (wp != aucmd_win)
Bram Moolenaarfd29f462010-06-06 16:11:09 +02004727 win_remove(wp, tp);
Bram Moolenaar3be85852014-06-12 14:01:31 +02004728 if (autocmd_busy)
4729 {
4730 wp->w_next = au_pending_free_win;
4731 au_pending_free_win = wp;
4732 }
4733 else
4734 vim_free(wp);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004735
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004736 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737}
4738
4739/*
4740 * Append window "wp" in the window list after window "after".
4741 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004742 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004743win_append(win_T *after, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744{
4745 win_T *before;
4746
4747 if (after == NULL) /* after NULL is in front of the first */
4748 before = firstwin;
4749 else
4750 before = after->w_next;
4751
4752 wp->w_next = before;
4753 wp->w_prev = after;
4754 if (after == NULL)
4755 firstwin = wp;
4756 else
4757 after->w_next = wp;
4758 if (before == NULL)
4759 lastwin = wp;
4760 else
4761 before->w_prev = wp;
4762}
4763
4764/*
4765 * Remove a window from the window list.
4766 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004767 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004768win_remove(
4769 win_T *wp,
4770 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771{
4772 if (wp->w_prev != NULL)
4773 wp->w_prev->w_next = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004774 else if (tp == NULL)
Bram Moolenaar816968d2017-09-29 21:29:18 +02004775 firstwin = curtab->tp_firstwin = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004776 else
4777 tp->tp_firstwin = wp->w_next;
Bram Moolenaar816968d2017-09-29 21:29:18 +02004778
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 if (wp->w_next != NULL)
4780 wp->w_next->w_prev = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004781 else if (tp == NULL)
Bram Moolenaar816968d2017-09-29 21:29:18 +02004782 lastwin = curtab->tp_lastwin = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004783 else
4784 tp->tp_lastwin = wp->w_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785}
4786
4787/*
4788 * Append frame "frp" in a frame list after frame "after".
4789 */
4790 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004791frame_append(frame_T *after, frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004792{
4793 frp->fr_next = after->fr_next;
4794 after->fr_next = frp;
4795 if (frp->fr_next != NULL)
4796 frp->fr_next->fr_prev = frp;
4797 frp->fr_prev = after;
4798}
4799
4800/*
4801 * Insert frame "frp" in a frame list before frame "before".
4802 */
4803 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004804frame_insert(frame_T *before, frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805{
4806 frp->fr_next = before;
4807 frp->fr_prev = before->fr_prev;
4808 before->fr_prev = frp;
4809 if (frp->fr_prev != NULL)
4810 frp->fr_prev->fr_next = frp;
4811 else
4812 frp->fr_parent->fr_child = frp;
4813}
4814
4815/*
4816 * Remove a frame from a frame list.
4817 */
4818 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004819frame_remove(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820{
4821 if (frp->fr_prev != NULL)
4822 frp->fr_prev->fr_next = frp->fr_next;
4823 else
Bram Moolenaar6f361c92018-01-31 19:06:50 +01004824 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825 frp->fr_parent->fr_child = frp->fr_next;
Bram Moolenaar6f361c92018-01-31 19:06:50 +01004826 /* special case: topframe->fr_child == frp */
4827 if (topframe->fr_child == frp)
4828 topframe->fr_child = frp->fr_next;
4829 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830 if (frp->fr_next != NULL)
4831 frp->fr_next->fr_prev = frp->fr_prev;
4832}
4833
Bram Moolenaar071d4272004-06-13 20:20:40 +00004834/*
4835 * Allocate w_lines[] for window "wp".
4836 * Return FAIL for failure, OK for success.
4837 */
4838 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004839win_alloc_lines(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840{
4841 wp->w_lines_valid = 0;
Bram Moolenaar9334c342006-11-21 19:57:30 +00004842 wp->w_lines = (wline_T *)alloc_clear((unsigned)(Rows * sizeof(wline_T)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 if (wp->w_lines == NULL)
4844 return FAIL;
4845 return OK;
4846}
4847
4848/*
4849 * free lsize arrays for a window
4850 */
4851 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004852win_free_lsize(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853{
Bram Moolenaar06e4a6d2014-06-12 11:49:46 +02004854 /* TODO: why would wp be NULL here? */
4855 if (wp != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01004856 VIM_CLEAR(wp->w_lines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004857}
4858
4859/*
4860 * Called from win_new_shellsize() after Rows changed.
Bram Moolenaarf740b292006-02-16 22:11:02 +00004861 * This only does the current tab page, others must be done when made active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 */
4863 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004864shell_new_rows(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004866 int h = (int)ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867
4868 if (firstwin == NULL) /* not initialized yet */
4869 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 if (h < frame_minheight(topframe, NULL))
4871 h = frame_minheight(topframe, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004872
4873 /* First try setting the heights of windows with 'winfixheight'. If
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 * that doesn't result in the right height, forget about that option. */
4875 frame_new_height(topframe, h, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004876 if (!frame_check_height(topframe, h))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 frame_new_height(topframe, h, FALSE, FALSE);
4878
4879 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004880 compute_cmdrow();
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00004881 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004882
Bram Moolenaar071d4272004-06-13 20:20:40 +00004883#if 0
4884 /* Disabled: don't want making the screen smaller make a window larger. */
4885 if (p_ea)
4886 win_equal(curwin, FALSE, 'v');
4887#endif
4888}
4889
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890/*
4891 * Called from win_new_shellsize() after Columns changed.
4892 */
4893 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004894shell_new_columns(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004895{
4896 if (firstwin == NULL) /* not initialized yet */
4897 return;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004898
4899 /* First try setting the widths of windows with 'winfixwidth'. If that
4900 * doesn't result in the right width, forget about that option. */
4901 frame_new_width(topframe, (int)Columns, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004902 if (!frame_check_width(topframe, Columns))
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004903 frame_new_width(topframe, (int)Columns, FALSE, FALSE);
4904
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
4906#if 0
4907 /* Disabled: don't want making the screen smaller make a window larger. */
4908 if (p_ea)
4909 win_equal(curwin, FALSE, 'h');
4910#endif
4911}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912
4913#if defined(FEAT_CMDWIN) || defined(PROTO)
4914/*
4915 * Save the size of all windows in "gap".
4916 */
4917 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004918win_size_save(garray_T *gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919
4920{
4921 win_T *wp;
4922
4923 ga_init2(gap, (int)sizeof(int), 1);
4924 if (ga_grow(gap, win_count() * 2) == OK)
Bram Moolenaar29323592016-07-24 22:04:11 +02004925 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926 {
4927 ((int *)gap->ga_data)[gap->ga_len++] =
4928 wp->w_width + wp->w_vsep_width;
4929 ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
4930 }
4931}
4932
4933/*
4934 * Restore window sizes, but only if the number of windows is still the same.
4935 * Does not free the growarray.
4936 */
4937 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004938win_size_restore(garray_T *gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939{
4940 win_T *wp;
Bram Moolenaarb643e772014-07-16 15:18:26 +02004941 int i, j;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942
4943 if (win_count() * 2 == gap->ga_len)
4944 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004945 /* The order matters, because frames contain other frames, but it's
4946 * difficult to get right. The easy way out is to do it twice. */
4947 for (j = 0; j < 2; ++j)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004948 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004949 i = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +02004950 FOR_ALL_WINDOWS(wp)
Bram Moolenaarb643e772014-07-16 15:18:26 +02004951 {
4952 frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
4953 win_setheight_win(((int *)gap->ga_data)[i++], wp);
4954 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 }
4956 /* recompute the window positions */
4957 (void)win_comp_pos();
4958 }
4959}
4960#endif /* FEAT_CMDWIN */
4961
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962/*
4963 * Update the position for all windows, using the width and height of the
4964 * frames.
4965 * Returns the row just after the last window.
4966 */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00004967 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004968win_comp_pos(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004969{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004970 int row = tabline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971 int col = 0;
4972
4973 frame_comp_pos(topframe, &row, &col);
4974 return row;
4975}
4976
4977/*
4978 * Update the position of the windows in frame "topfrp", using the width and
4979 * height of the frames.
4980 * "*row" and "*col" are the top-left position of the frame. They are updated
4981 * to the bottom-right position plus one.
4982 */
4983 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004984frame_comp_pos(frame_T *topfrp, int *row, int *col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004985{
4986 win_T *wp;
4987 frame_T *frp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988 int startcol;
4989 int startrow;
Bram Moolenaar415a6932017-12-05 20:31:07 +01004990 int h;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991
4992 wp = topfrp->fr_win;
4993 if (wp != NULL)
4994 {
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004995 if (wp->w_winrow != *row || wp->w_wincol != *col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996 {
4997 /* position changed, redraw */
4998 wp->w_winrow = *row;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 wp->w_wincol = *col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005000 redraw_win_later(wp, NOT_VALID);
5001 wp->w_redr_status = TRUE;
5002 }
Bram Moolenaar415a6932017-12-05 20:31:07 +01005003 /* WinBar will not show if the window height is zero */
5004 h = VISIBLE_HEIGHT(wp) + wp->w_status_height;
5005 *row += h > topfrp->fr_height ? topfrp->fr_height : h;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005006 *col += wp->w_width + wp->w_vsep_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 }
5008 else
5009 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 startrow = *row;
5011 startcol = *col;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01005012 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005014 if (topfrp->fr_layout == FR_ROW)
5015 *row = startrow; /* all frames are at the same row */
5016 else
5017 *col = startcol; /* all frames are at the same col */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005018 frame_comp_pos(frp, row, col);
5019 }
5020 }
5021}
5022
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023/*
5024 * Set current window height and take care of repositioning other windows to
5025 * fit around it.
5026 */
5027 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005028win_setheight(int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029{
5030 win_setheight_win(height, curwin);
5031}
5032
5033/*
5034 * Set the window height of window "win" and take care of repositioning other
5035 * windows to fit around it.
5036 */
5037 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005038win_setheight_win(int height, win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039{
5040 int row;
5041
5042 if (win == curwin)
5043 {
5044 /* Always keep current window at least one line high, even when
5045 * 'winminheight' is zero. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046 if (height < p_wmh)
5047 height = p_wmh;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048 if (height == 0)
5049 height = 1;
Bram Moolenaar415a6932017-12-05 20:31:07 +01005050 height += WINBAR_HEIGHT(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 }
5052
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 frame_setheight(win->w_frame, height + win->w_status_height);
5054
5055 /* recompute the window positions */
5056 row = win_comp_pos();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057
5058 /*
5059 * If there is extra space created between the last window and the command
5060 * line, clear it.
5061 */
5062 if (full_screen && msg_scrolled == 0 && row < cmdline_row)
5063 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5064 cmdline_row = row;
5065 msg_row = row;
5066 msg_col = 0;
5067
5068 redraw_all_later(NOT_VALID);
5069}
5070
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071/*
5072 * Set the height of a frame to "height" and take care that all frames and
5073 * windows inside it are resized. Also resize frames on the left and right if
5074 * the are in the same FR_ROW frame.
5075 *
5076 * Strategy:
5077 * If the frame is part of a FR_COL frame, try fitting the frame in that
5078 * frame. If that doesn't work (the FR_COL frame is too small), recursively
5079 * go to containing frames to resize them and make room.
5080 * If the frame is part of a FR_ROW frame, all frames must be resized as well.
5081 * Check for the minimal height of the FR_ROW frame.
5082 * At the top level we can also use change the command line height.
5083 */
5084 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005085frame_setheight(frame_T *curfrp, int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086{
5087 int room; /* total number of lines available */
5088 int take; /* number of lines taken from other windows */
5089 int room_cmdline; /* lines available from cmdline */
5090 int run;
5091 frame_T *frp;
5092 int h;
5093 int room_reserved;
5094
5095 /* If the height already is the desired value, nothing to do. */
5096 if (curfrp->fr_height == height)
5097 return;
5098
5099 if (curfrp->fr_parent == NULL)
5100 {
5101 /* topframe: can only change the command line */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005102 if (height > ROWS_AVAIL)
5103 height = ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 if (height > 0)
5105 frame_new_height(curfrp, height, FALSE, FALSE);
5106 }
5107 else if (curfrp->fr_parent->fr_layout == FR_ROW)
5108 {
5109 /* Row of frames: Also need to resize frames left and right of this
5110 * one. First check for the minimal height of these. */
5111 h = frame_minheight(curfrp->fr_parent, NULL);
5112 if (height < h)
5113 height = h;
5114 frame_setheight(curfrp->fr_parent, height);
5115 }
5116 else
5117 {
5118 /*
5119 * Column of frames: try to change only frames in this column.
5120 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 /*
5122 * Do this twice:
5123 * 1: compute room available, if it's not enough try resizing the
5124 * containing frame.
5125 * 2: compute the room available and adjust the height to it.
5126 * Try not to reduce the height of a window with 'winfixheight' set.
5127 */
5128 for (run = 1; run <= 2; ++run)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005129 {
5130 room = 0;
5131 room_reserved = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01005132 FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133 {
5134 if (frp != curfrp
5135 && frp->fr_win != NULL
5136 && frp->fr_win->w_p_wfh)
5137 room_reserved += frp->fr_height;
5138 room += frp->fr_height;
5139 if (frp != curfrp)
5140 room -= frame_minheight(frp, NULL);
5141 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142 if (curfrp->fr_width != Columns)
5143 room_cmdline = 0;
5144 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 {
5146 room_cmdline = Rows - p_ch - (lastwin->w_winrow
Bram Moolenaar415a6932017-12-05 20:31:07 +01005147 + VISIBLE_HEIGHT(lastwin)
5148 + lastwin->w_status_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 if (room_cmdline < 0)
5150 room_cmdline = 0;
5151 }
5152
5153 if (height <= room + room_cmdline)
5154 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155 if (run == 2 || curfrp->fr_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005156 {
5157 if (height > room + room_cmdline)
5158 height = room + room_cmdline;
5159 break;
5160 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161 frame_setheight(curfrp->fr_parent, height
5162 + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005163 }
5164
5165 /*
5166 * Compute the number of lines we will take from others frames (can be
5167 * negative!).
5168 */
5169 take = height - curfrp->fr_height;
5170
5171 /* If there is not enough room, also reduce the height of a window
5172 * with 'winfixheight' set. */
5173 if (height > room + room_cmdline - room_reserved)
5174 room_reserved = room + room_cmdline - height;
5175 /* If there is only a 'winfixheight' window and making the
5176 * window smaller, need to make the other window taller. */
5177 if (take < 0 && room - curfrp->fr_height < room_reserved)
5178 room_reserved = 0;
5179
5180 if (take > 0 && room_cmdline > 0)
5181 {
5182 /* use lines from cmdline first */
5183 if (take < room_cmdline)
5184 room_cmdline = take;
5185 take -= room_cmdline;
5186 topframe->fr_height += room_cmdline;
5187 }
5188
5189 /*
5190 * set the current frame to the new height
5191 */
5192 frame_new_height(curfrp, height, FALSE, FALSE);
5193
5194 /*
5195 * First take lines from the frames after the current frame. If
5196 * that is not enough, takes lines from frames above the current
5197 * frame.
5198 */
5199 for (run = 0; run < 2; ++run)
5200 {
5201 if (run == 0)
5202 frp = curfrp->fr_next; /* 1st run: start with next window */
5203 else
5204 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5205 while (frp != NULL && take != 0)
5206 {
5207 h = frame_minheight(frp, NULL);
5208 if (room_reserved > 0
5209 && frp->fr_win != NULL
5210 && frp->fr_win->w_p_wfh)
5211 {
5212 if (room_reserved >= frp->fr_height)
5213 room_reserved -= frp->fr_height;
5214 else
5215 {
5216 if (frp->fr_height - room_reserved > take)
5217 room_reserved = frp->fr_height - take;
5218 take -= frp->fr_height - room_reserved;
5219 frame_new_height(frp, room_reserved, FALSE, FALSE);
5220 room_reserved = 0;
5221 }
5222 }
5223 else
5224 {
5225 if (frp->fr_height - take < h)
5226 {
5227 take -= frp->fr_height - h;
5228 frame_new_height(frp, h, FALSE, FALSE);
5229 }
5230 else
5231 {
5232 frame_new_height(frp, frp->fr_height - take,
5233 FALSE, FALSE);
5234 take = 0;
5235 }
5236 }
5237 if (run == 0)
5238 frp = frp->fr_next;
5239 else
5240 frp = frp->fr_prev;
5241 }
5242 }
5243 }
5244}
5245
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246/*
5247 * Set current window width and take care of repositioning other windows to
5248 * fit around it.
5249 */
5250 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005251win_setwidth(int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252{
5253 win_setwidth_win(width, curwin);
5254}
5255
5256 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005257win_setwidth_win(int width, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258{
5259 /* Always keep current window at least one column wide, even when
5260 * 'winminwidth' is zero. */
5261 if (wp == curwin)
5262 {
5263 if (width < p_wmw)
5264 width = p_wmw;
5265 if (width == 0)
5266 width = 1;
5267 }
5268
5269 frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
5270
5271 /* recompute the window positions */
5272 (void)win_comp_pos();
5273
5274 redraw_all_later(NOT_VALID);
5275}
5276
5277/*
5278 * Set the width of a frame to "width" and take care that all frames and
5279 * windows inside it are resized. Also resize frames above and below if the
5280 * are in the same FR_ROW frame.
5281 *
5282 * Strategy is similar to frame_setheight().
5283 */
5284 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005285frame_setwidth(frame_T *curfrp, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005286{
5287 int room; /* total number of lines available */
5288 int take; /* number of lines taken from other windows */
5289 int run;
5290 frame_T *frp;
5291 int w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005292 int room_reserved;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293
5294 /* If the width already is the desired value, nothing to do. */
5295 if (curfrp->fr_width == width)
5296 return;
5297
5298 if (curfrp->fr_parent == NULL)
5299 /* topframe: can't change width */
5300 return;
5301
5302 if (curfrp->fr_parent->fr_layout == FR_COL)
5303 {
5304 /* Column of frames: Also need to resize frames above and below of
5305 * this one. First check for the minimal width of these. */
5306 w = frame_minwidth(curfrp->fr_parent, NULL);
5307 if (width < w)
5308 width = w;
5309 frame_setwidth(curfrp->fr_parent, width);
5310 }
5311 else
5312 {
5313 /*
5314 * Row of frames: try to change only frames in this row.
5315 *
5316 * Do this twice:
5317 * 1: compute room available, if it's not enough try resizing the
5318 * containing frame.
5319 * 2: compute the room available and adjust the width to it.
5320 */
5321 for (run = 1; run <= 2; ++run)
5322 {
5323 room = 0;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005324 room_reserved = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01005325 FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005327 if (frp != curfrp
5328 && frp->fr_win != NULL
5329 && frp->fr_win->w_p_wfw)
5330 room_reserved += frp->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005331 room += frp->fr_width;
5332 if (frp != curfrp)
5333 room -= frame_minwidth(frp, NULL);
5334 }
5335
5336 if (width <= room)
5337 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005338 if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005339 {
5340 if (width > room)
5341 width = room;
5342 break;
5343 }
5344 frame_setwidth(curfrp->fr_parent, width
5345 + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
5346 }
5347
Bram Moolenaar071d4272004-06-13 20:20:40 +00005348 /*
5349 * Compute the number of lines we will take from others frames (can be
5350 * negative!).
5351 */
5352 take = width - curfrp->fr_width;
5353
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005354 /* If there is not enough room, also reduce the width of a window
5355 * with 'winfixwidth' set. */
5356 if (width > room - room_reserved)
5357 room_reserved = room - width;
5358 /* If there is only a 'winfixwidth' window and making the
5359 * window smaller, need to make the other window narrower. */
5360 if (take < 0 && room - curfrp->fr_width < room_reserved)
5361 room_reserved = 0;
5362
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363 /*
5364 * set the current frame to the new width
5365 */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005366 frame_new_width(curfrp, width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005367
5368 /*
5369 * First take lines from the frames right of the current frame. If
5370 * that is not enough, takes lines from frames left of the current
5371 * frame.
5372 */
5373 for (run = 0; run < 2; ++run)
5374 {
5375 if (run == 0)
5376 frp = curfrp->fr_next; /* 1st run: start with next window */
5377 else
5378 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5379 while (frp != NULL && take != 0)
5380 {
5381 w = frame_minwidth(frp, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005382 if (room_reserved > 0
5383 && frp->fr_win != NULL
5384 && frp->fr_win->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005385 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005386 if (room_reserved >= frp->fr_width)
5387 room_reserved -= frp->fr_width;
5388 else
5389 {
5390 if (frp->fr_width - room_reserved > take)
5391 room_reserved = frp->fr_width - take;
5392 take -= frp->fr_width - room_reserved;
5393 frame_new_width(frp, room_reserved, FALSE, FALSE);
5394 room_reserved = 0;
5395 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005396 }
5397 else
5398 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005399 if (frp->fr_width - take < w)
5400 {
5401 take -= frp->fr_width - w;
5402 frame_new_width(frp, w, FALSE, FALSE);
5403 }
5404 else
5405 {
5406 frame_new_width(frp, frp->fr_width - take,
5407 FALSE, FALSE);
5408 take = 0;
5409 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005410 }
5411 if (run == 0)
5412 frp = frp->fr_next;
5413 else
5414 frp = frp->fr_prev;
5415 }
5416 }
5417 }
5418}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419
5420/*
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005421 * Check 'winminheight' for a valid value and reduce it if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005422 */
5423 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005424win_setminheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425{
5426 int room;
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005427 int needed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005428 int first = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005429
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005430 // loop until there is a 'winminheight' that is possible
Bram Moolenaar071d4272004-06-13 20:20:40 +00005431 while (p_wmh > 0)
5432 {
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005433 room = Rows - p_ch;
5434 needed = frame_minheight(topframe, NULL);
5435 if (room >= needed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005436 break;
5437 --p_wmh;
5438 if (first)
5439 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005440 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441 first = FALSE;
5442 }
5443 }
5444}
5445
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005446/*
5447 * Check 'winminwidth' for a valid value and reduce it if needed.
5448 */
5449 void
5450win_setminwidth(void)
5451{
5452 int room;
5453 int needed;
5454 int first = TRUE;
5455
5456 // loop until there is a 'winminheight' that is possible
5457 while (p_wmw > 0)
5458 {
5459 room = Columns;
5460 needed = frame_minwidth(topframe, NULL);
5461 if (room >= needed)
5462 break;
5463 --p_wmw;
5464 if (first)
5465 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005466 emsg(_(e_noroom));
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005467 first = FALSE;
5468 }
5469 }
5470}
5471
Bram Moolenaar6a2697f2015-11-19 13:14:30 +01005472#if defined(FEAT_MOUSE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473
5474/*
5475 * Status line of dragwin is dragged "offset" lines down (negative is up).
5476 */
5477 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005478win_drag_status_line(win_T *dragwin, int offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479{
5480 frame_T *curfr;
5481 frame_T *fr;
5482 int room;
5483 int row;
5484 int up; /* if TRUE, drag status line up, otherwise down */
5485 int n;
5486
5487 fr = dragwin->w_frame;
5488 curfr = fr;
5489 if (fr != topframe) /* more than one window */
5490 {
5491 fr = fr->fr_parent;
5492 /* When the parent frame is not a column of frames, its parent should
5493 * be. */
5494 if (fr->fr_layout != FR_COL)
5495 {
5496 curfr = fr;
5497 if (fr != topframe) /* only a row of windows, may drag statusline */
5498 fr = fr->fr_parent;
5499 }
5500 }
5501
5502 /* If this is the last frame in a column, may want to resize the parent
5503 * frame instead (go two up to skip a row of frames). */
5504 while (curfr != topframe && curfr->fr_next == NULL)
5505 {
5506 if (fr != topframe)
5507 fr = fr->fr_parent;
5508 curfr = fr;
5509 if (fr != topframe)
5510 fr = fr->fr_parent;
5511 }
5512
5513 if (offset < 0) /* drag up */
5514 {
5515 up = TRUE;
5516 offset = -offset;
5517 /* sum up the room of the current frame and above it */
5518 if (fr == curfr)
5519 {
5520 /* only one window */
5521 room = fr->fr_height - frame_minheight(fr, NULL);
5522 }
5523 else
5524 {
5525 room = 0;
5526 for (fr = fr->fr_child; ; fr = fr->fr_next)
5527 {
5528 room += fr->fr_height - frame_minheight(fr, NULL);
5529 if (fr == curfr)
5530 break;
5531 }
5532 }
5533 fr = curfr->fr_next; /* put fr at frame that grows */
5534 }
5535 else /* drag down */
5536 {
5537 up = FALSE;
5538 /*
5539 * Only dragging the last status line can reduce p_ch.
5540 */
5541 room = Rows - cmdline_row;
5542 if (curfr->fr_next == NULL)
5543 room -= 1;
5544 else
5545 room -= p_ch;
5546 if (room < 0)
5547 room = 0;
5548 /* sum up the room of frames below of the current one */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01005549 FOR_ALL_FRAMES(fr, curfr->fr_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005550 room += fr->fr_height - frame_minheight(fr, NULL);
5551 fr = curfr; /* put fr at window that grows */
5552 }
5553
5554 if (room < offset) /* Not enough room */
5555 offset = room; /* Move as far as we can */
5556 if (offset <= 0)
5557 return;
5558
5559 /*
5560 * Grow frame fr by "offset" lines.
5561 * Doesn't happen when dragging the last status line up.
5562 */
5563 if (fr != NULL)
5564 frame_new_height(fr, fr->fr_height + offset, up, FALSE);
5565
5566 if (up)
5567 fr = curfr; /* current frame gets smaller */
5568 else
5569 fr = curfr->fr_next; /* next frame gets smaller */
5570
5571 /*
5572 * Now make the other frames smaller.
5573 */
5574 while (fr != NULL && offset > 0)
5575 {
5576 n = frame_minheight(fr, NULL);
5577 if (fr->fr_height - offset <= n)
5578 {
5579 offset -= fr->fr_height - n;
5580 frame_new_height(fr, n, !up, FALSE);
5581 }
5582 else
5583 {
5584 frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
5585 break;
5586 }
5587 if (up)
5588 fr = fr->fr_prev;
5589 else
5590 fr = fr->fr_next;
5591 }
5592 row = win_comp_pos();
5593 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5594 cmdline_row = row;
5595 p_ch = Rows - cmdline_row;
5596 if (p_ch < 1)
5597 p_ch = 1;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005598 curtab->tp_ch_used = p_ch;
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005599 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005600 showmode();
5601}
5602
Bram Moolenaar071d4272004-06-13 20:20:40 +00005603/*
5604 * Separator line of dragwin is dragged "offset" lines right (negative is left).
5605 */
5606 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005607win_drag_vsep_line(win_T *dragwin, int offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608{
5609 frame_T *curfr;
5610 frame_T *fr;
5611 int room;
5612 int left; /* if TRUE, drag separator line left, otherwise right */
5613 int n;
5614
5615 fr = dragwin->w_frame;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005616 if (fr == topframe) /* only one window (cannot happen?) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005617 return;
5618 curfr = fr;
5619 fr = fr->fr_parent;
5620 /* When the parent frame is not a row of frames, its parent should be. */
5621 if (fr->fr_layout != FR_ROW)
5622 {
5623 if (fr == topframe) /* only a column of windows (cannot happen?) */
5624 return;
5625 curfr = fr;
5626 fr = fr->fr_parent;
5627 }
5628
5629 /* If this is the last frame in a row, may want to resize a parent
5630 * frame instead. */
5631 while (curfr->fr_next == NULL)
5632 {
5633 if (fr == topframe)
5634 break;
5635 curfr = fr;
5636 fr = fr->fr_parent;
5637 if (fr != topframe)
5638 {
5639 curfr = fr;
5640 fr = fr->fr_parent;
5641 }
5642 }
5643
5644 if (offset < 0) /* drag left */
5645 {
5646 left = TRUE;
5647 offset = -offset;
5648 /* sum up the room of the current frame and left of it */
5649 room = 0;
5650 for (fr = fr->fr_child; ; fr = fr->fr_next)
5651 {
5652 room += fr->fr_width - frame_minwidth(fr, NULL);
5653 if (fr == curfr)
5654 break;
5655 }
5656 fr = curfr->fr_next; /* put fr at frame that grows */
5657 }
5658 else /* drag right */
5659 {
5660 left = FALSE;
5661 /* sum up the room of frames right of the current one */
5662 room = 0;
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01005663 FOR_ALL_FRAMES(fr, curfr->fr_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005664 room += fr->fr_width - frame_minwidth(fr, NULL);
5665 fr = curfr; /* put fr at window that grows */
5666 }
5667
5668 if (room < offset) /* Not enough room */
5669 offset = room; /* Move as far as we can */
5670 if (offset <= 0) /* No room at all, quit. */
5671 return;
Bram Moolenaar294a7e52015-11-22 19:39:38 +01005672 if (fr == NULL)
5673 return; /* Safety check, should not happen. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005674
5675 /* grow frame fr by offset lines */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005676 frame_new_width(fr, fr->fr_width + offset, left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005677
5678 /* shrink other frames: current and at the left or at the right */
5679 if (left)
5680 fr = curfr; /* current frame gets smaller */
5681 else
5682 fr = curfr->fr_next; /* next frame gets smaller */
5683
5684 while (fr != NULL && offset > 0)
5685 {
5686 n = frame_minwidth(fr, NULL);
5687 if (fr->fr_width - offset <= n)
5688 {
5689 offset -= fr->fr_width - n;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005690 frame_new_width(fr, n, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 }
5692 else
5693 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005694 frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005695 break;
5696 }
5697 if (left)
5698 fr = fr->fr_prev;
5699 else
5700 fr = fr->fr_next;
5701 }
5702 (void)win_comp_pos();
5703 redraw_all_later(NOT_VALID);
5704}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005705#endif /* FEAT_MOUSE */
5706
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005707#define FRACTION_MULT 16384L
5708
5709/*
5710 * Set wp->w_fraction for the current w_wrow and w_height.
Bram Moolenaar3679c172017-11-22 22:22:11 +01005711 * Has no effect when the window is less than two lines.
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005712 */
Bram Moolenaar9dc2ce32015-12-05 19:47:04 +01005713 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005714set_fraction(win_T *wp)
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005715{
Bram Moolenaar3679c172017-11-22 22:22:11 +01005716 if (wp->w_height > 1)
5717 wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005718 + wp->w_height / 2) / (long)wp->w_height;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005719}
5720
Bram Moolenaar071d4272004-06-13 20:20:40 +00005721/*
5722 * Set the height of a window.
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005723 * "height" excludes any window toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005724 * This takes care of the things inside the window, not what happens to the
5725 * window position, the frame or to other windows.
5726 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005727 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005728win_new_height(win_T *wp, int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729{
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005730 int prev_height = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005731
5732 /* Don't want a negative height. Happens when splitting a tiny window.
5733 * Will equalize heights soon to fix it. */
5734 if (height < 0)
5735 height = 0;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00005736 if (wp->w_height == height)
5737 return; /* nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005738
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005739 if (wp->w_height > 0)
5740 {
5741 if (wp == curwin)
Bram Moolenaar0ae36a52014-06-13 20:08:45 +02005742 /* w_wrow needs to be valid. When setting 'laststatus' this may
5743 * call win_new_height() recursively. */
5744 validate_cursor();
5745 if (wp->w_height != prev_height)
5746 return; /* Recursive call already changed the size, bail out here
5747 to avoid the following to mess things up. */
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005748 if (wp->w_wrow != wp->w_prev_fraction_row)
5749 set_fraction(wp);
5750 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751
5752 wp->w_height = height;
5753 wp->w_skipcol = 0;
5754
Bram Moolenaar955f1982017-02-05 15:10:51 +01005755 /* There is no point in adjusting the scroll position when exiting. Some
5756 * values might be invalid. */
5757 if (!exiting)
5758 scroll_to_fraction(wp, prev_height);
Bram Moolenaar46328f92016-08-28 15:39:57 +02005759}
5760
5761 void
5762scroll_to_fraction(win_T *wp, int prev_height)
5763{
5764 linenr_T lnum;
5765 int sline, line_size;
5766 int height = wp->w_height;
5767
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 /* Don't change w_topline when height is zero. Don't set w_topline when
5769 * 'scrollbind' is set and this isn't the current window. */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01005770 if (height > 0 && (!wp->w_p_scb || wp == curwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771 {
Bram Moolenaar34114692005-01-02 11:28:13 +00005772 /*
5773 * Find a value for w_topline that shows the cursor at the same
5774 * relative position in the window as before (more or less).
5775 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776 lnum = wp->w_cursor.lnum;
5777 if (lnum < 1) /* can happen when starting up */
5778 lnum = 1;
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005779 wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L
5780 + FRACTION_MULT / 2) / FRACTION_MULT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
5782 sline = wp->w_wrow - line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005783
5784 if (sline >= 0)
5785 {
5786 /* Make sure the whole cursor line is visible, if possible. */
5787 int rows = plines_win(wp, lnum, FALSE);
5788
5789 if (sline > wp->w_height - rows)
5790 {
5791 sline = wp->w_height - rows;
5792 wp->w_wrow -= rows - line_size;
5793 }
5794 }
5795
Bram Moolenaar071d4272004-06-13 20:20:40 +00005796 if (sline < 0)
5797 {
5798 /*
5799 * Cursor line would go off top of screen if w_wrow was this high.
Bram Moolenaar26470632006-10-24 19:12:40 +00005800 * Make cursor line the first line in the window. If not enough
5801 * room use w_skipcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802 */
5803 wp->w_wrow = line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005804 if (wp->w_wrow >= wp->w_height
Bram Moolenaar02631462017-09-22 15:20:32 +02005805 && (wp->w_width - win_col_off(wp)) > 0)
Bram Moolenaar26470632006-10-24 19:12:40 +00005806 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005807 wp->w_skipcol += wp->w_width - win_col_off(wp);
Bram Moolenaar26470632006-10-24 19:12:40 +00005808 --wp->w_wrow;
5809 while (wp->w_wrow >= wp->w_height)
5810 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005811 wp->w_skipcol += wp->w_width - win_col_off(wp)
Bram Moolenaar26470632006-10-24 19:12:40 +00005812 + win_col_off2(wp);
5813 --wp->w_wrow;
5814 }
5815 }
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005816 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005817 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005818 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819 {
Bram Moolenaar26470632006-10-24 19:12:40 +00005820 while (sline > 0 && lnum > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005821 {
5822#ifdef FEAT_FOLDING
5823 hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
5824 if (lnum == 1)
5825 {
5826 /* first line in buffer is folded */
5827 line_size = 1;
5828 --sline;
5829 break;
5830 }
5831#endif
5832 --lnum;
5833#ifdef FEAT_DIFF
5834 if (lnum == wp->w_topline)
5835 line_size = plines_win_nofill(wp, lnum, TRUE)
5836 + wp->w_topfill;
5837 else
5838#endif
5839 line_size = plines_win(wp, lnum, TRUE);
5840 sline -= line_size;
5841 }
Bram Moolenaar34114692005-01-02 11:28:13 +00005842
Bram Moolenaar071d4272004-06-13 20:20:40 +00005843 if (sline < 0)
5844 {
5845 /*
5846 * Line we want at top would go off top of screen. Use next
5847 * line instead.
5848 */
5849#ifdef FEAT_FOLDING
5850 hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
5851#endif
5852 lnum++;
5853 wp->w_wrow -= line_size + sline;
5854 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005855 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 {
5857 /* First line of file reached, use that as topline. */
5858 lnum = 1;
5859 wp->w_wrow -= sline;
5860 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005861
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005862 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005863 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864 }
5865
5866 if (wp == curwin)
5867 {
Bram Moolenaar375e3392019-01-31 18:26:10 +01005868 if (get_scrolloff_value())
Bram Moolenaar071d4272004-06-13 20:20:40 +00005869 update_topline();
5870 curs_columns(FALSE); /* validate w_wrow */
5871 }
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005872 if (prev_height > 0)
5873 wp->w_prev_fraction_row = wp->w_wrow;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874
5875 win_comp_scroll(wp);
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005876 redraw_win_later(wp, SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005877 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878 invalidate_botline_win(wp);
5879}
5880
Bram Moolenaar071d4272004-06-13 20:20:40 +00005881/*
5882 * Set the width of a window.
5883 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005884 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005885win_new_width(win_T *wp, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886{
5887 wp->w_width = width;
5888 wp->w_lines_valid = 0;
5889 changed_line_abv_curs_win(wp);
5890 invalidate_botline_win(wp);
5891 if (wp == curwin)
5892 {
5893 update_topline();
5894 curs_columns(TRUE); /* validate w_wrow */
5895 }
5896 redraw_win_later(wp, NOT_VALID);
5897 wp->w_redr_status = TRUE;
5898}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005899
5900 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005901win_comp_scroll(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005902{
5903 wp->w_p_scr = ((unsigned)wp->w_height >> 1);
5904 if (wp->w_p_scr == 0)
5905 wp->w_p_scr = 1;
5906}
5907
5908/*
5909 * command_height: called whenever p_ch has been changed
5910 */
5911 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005912command_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005914 int h;
5915 frame_T *frp;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005916 int old_p_ch = curtab->tp_ch_used;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005917
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005918 /* Use the value of p_ch that we remembered. This is needed for when the
5919 * GUI starts up, we can't be sure in what order things happen. And when
5920 * p_ch was changed in another tab page. */
5921 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00005922
Bram Moolenaar071d4272004-06-13 20:20:40 +00005923 /* Find bottom frame with width of screen. */
5924 frp = lastwin->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005925 while (frp->fr_width != Columns && frp->fr_parent != NULL)
5926 frp = frp->fr_parent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005927
5928 /* Avoid changing the height of a window with 'winfixheight' set. */
5929 while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
5930 && frp->fr_win->w_p_wfh)
5931 frp = frp->fr_prev;
5932
5933 if (starting != NO_SCREEN)
5934 {
5935 cmdline_row = Rows - p_ch;
5936
5937 if (p_ch > old_p_ch) /* p_ch got bigger */
5938 {
5939 while (p_ch > old_p_ch)
5940 {
5941 if (frp == NULL)
5942 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005943 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944 p_ch = old_p_ch;
Bram Moolenaar719939c2007-09-25 12:51:28 +00005945 curtab->tp_ch_used = p_ch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946 cmdline_row = Rows - p_ch;
5947 break;
5948 }
5949 h = frp->fr_height - frame_minheight(frp, NULL);
5950 if (h > p_ch - old_p_ch)
5951 h = p_ch - old_p_ch;
5952 old_p_ch += h;
5953 frame_add_height(frp, -h);
5954 frp = frp->fr_prev;
5955 }
5956
5957 /* Recompute window positions. */
5958 (void)win_comp_pos();
5959
5960 /* clear the lines added to cmdline */
5961 if (full_screen)
5962 screen_fill((int)(cmdline_row), (int)Rows, 0,
5963 (int)Columns, ' ', ' ', 0);
5964 msg_row = cmdline_row;
5965 redraw_cmdline = TRUE;
5966 return;
5967 }
5968
5969 if (msg_row < cmdline_row)
5970 msg_row = cmdline_row;
5971 redraw_cmdline = TRUE;
5972 }
5973 frame_add_height(frp, (int)(old_p_ch - p_ch));
5974
5975 /* Recompute window positions. */
5976 if (frp != lastwin->w_frame)
5977 (void)win_comp_pos();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978}
5979
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980/*
5981 * Resize frame "frp" to be "n" lines higher (negative for less high).
5982 * Also resize the frames it is contained in.
5983 */
5984 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005985frame_add_height(frame_T *frp, int n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005986{
5987 frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
5988 for (;;)
5989 {
5990 frp = frp->fr_parent;
5991 if (frp == NULL)
5992 break;
5993 frp->fr_height += n;
5994 }
5995}
5996
5997/*
5998 * Add or remove a status line for the bottom window(s), according to the
5999 * value of 'laststatus'.
6000 */
6001 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006002last_status(
6003 int morewin) /* pretend there are two or more windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006004{
6005 /* Don't make a difference between horizontal or vertical split. */
6006 last_status_rec(topframe, (p_ls == 2
Bram Moolenaar459ca562016-11-10 18:16:33 +01006007 || (p_ls == 1 && (morewin || !ONE_WINDOW))));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006008}
6009
6010 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006011last_status_rec(frame_T *fr, int statusline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012{
6013 frame_T *fp;
6014 win_T *wp;
6015
6016 if (fr->fr_layout == FR_LEAF)
6017 {
6018 wp = fr->fr_win;
6019 if (wp->w_status_height != 0 && !statusline)
6020 {
6021 /* remove status line */
6022 win_new_height(wp, wp->w_height + 1);
6023 wp->w_status_height = 0;
6024 comp_col();
6025 }
6026 else if (wp->w_status_height == 0 && statusline)
6027 {
6028 /* Find a frame to take a line from. */
6029 fp = fr;
6030 while (fp->fr_height <= frame_minheight(fp, NULL))
6031 {
6032 if (fp == topframe)
6033 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006034 emsg(_(e_noroom));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035 return;
6036 }
6037 /* In a column of frames: go to frame above. If already at
6038 * the top or in a row of frames: go to parent. */
6039 if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
6040 fp = fp->fr_prev;
6041 else
6042 fp = fp->fr_parent;
6043 }
6044 wp->w_status_height = 1;
6045 if (fp != fr)
6046 {
6047 frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
6048 frame_fix_height(wp);
6049 (void)win_comp_pos();
6050 }
6051 else
6052 win_new_height(wp, wp->w_height - 1);
6053 comp_col();
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00006054 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006055 }
6056 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006057 else if (fr->fr_layout == FR_ROW)
6058 {
6059 /* vertically split windows, set status line for each one */
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006060 FOR_ALL_FRAMES(fp, fr->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 last_status_rec(fp, statusline);
6062 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063 else
6064 {
6065 /* horizontally split window, set status line for last one */
6066 for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
6067 ;
6068 last_status_rec(fp, statusline);
6069 }
6070}
6071
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006072/*
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006073 * Return the number of lines used by the tab page line.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006074 */
6075 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006076tabline_height(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006077{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006078#ifdef FEAT_GUI_TABLINE
6079 /* When the GUI has the tabline then this always returns zero. */
6080 if (gui_use_tabline())
6081 return 0;
6082#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00006083 switch (p_stal)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006084 {
6085 case 0: return 0;
6086 case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
6087 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006088 return 1;
6089}
6090
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091/*
6092 * Return the minimal number of rows that is needed on the screen to display
6093 * the current number of windows.
6094 */
6095 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006096min_rows(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006097{
6098 int total;
Bram Moolenaarf740b292006-02-16 22:11:02 +00006099 tabpage_T *tp;
6100 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101
6102 if (firstwin == NULL) /* not initialized yet */
6103 return MIN_LINES;
6104
Bram Moolenaarf740b292006-02-16 22:11:02 +00006105 total = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +02006106 FOR_ALL_TABPAGES(tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00006107 {
6108 n = frame_minheight(tp->tp_topframe, NULL);
6109 if (total < n)
6110 total = n;
6111 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006112 total += tabline_height();
Bram Moolenaarf740b292006-02-16 22:11:02 +00006113 total += 1; /* count the room for the command line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006114 return total;
6115}
6116
6117/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006118 * Return TRUE if there is only one window (in the current tab page), not
6119 * counting a help or preview window, unless it is the current window.
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006120 * Does not count "aucmd_win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121 */
6122 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006123only_one_window(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006124{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 int count = 0;
6126 win_T *wp;
6127
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006128 /* If there is another tab page there always is another window. */
6129 if (first_tabpage->tp_next != NULL)
6130 return FALSE;
6131
Bram Moolenaar29323592016-07-24 22:04:11 +02006132 FOR_ALL_WINDOWS(wp)
Bram Moolenaar802418d2013-01-17 14:00:11 +01006133 if (wp->w_buffer != NULL
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02006134 && (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006135# ifdef FEAT_QUICKFIX
6136 || wp->w_p_pvw
6137# endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006138 ) || wp == curwin) && wp != aucmd_win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139 ++count;
6140 return (count <= 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141}
6142
Bram Moolenaar071d4272004-06-13 20:20:40 +00006143/*
6144 * Correct the cursor line number in other windows. Used after changing the
6145 * current buffer, and before applying autocommands.
6146 * When "do_curwin" is TRUE, also check current window.
6147 */
6148 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006149check_lnums(int do_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006150{
6151 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00006152 tabpage_T *tp;
6153
6154 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006155 if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006156 {
6157 if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6158 wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6159 if (wp->w_topline > curbuf->b_ml.ml_line_count)
6160 wp->w_topline = curbuf->b_ml.ml_line_count;
6161 }
6162}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163
6164/*
6165 * A snapshot of the window sizes, to restore them after closing the help
6166 * window.
6167 * Only these fields are used:
6168 * fr_layout
6169 * fr_width
6170 * fr_height
6171 * fr_next
6172 * fr_child
6173 * fr_win (only valid for the old curwin, NULL otherwise)
6174 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006175
6176/*
6177 * Create a snapshot of the current frame sizes.
6178 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006179 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006180make_snapshot(int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006182 clear_snapshot(curtab, idx);
6183 make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184}
6185
6186 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006187make_snapshot_rec(frame_T *fr, frame_T **frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188{
6189 *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
6190 if (*frp == NULL)
6191 return;
6192 (*frp)->fr_layout = fr->fr_layout;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 (*frp)->fr_width = fr->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194 (*frp)->fr_height = fr->fr_height;
6195 if (fr->fr_next != NULL)
6196 make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
6197 if (fr->fr_child != NULL)
6198 make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
6199 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
6200 (*frp)->fr_win = curwin;
6201}
6202
6203/*
6204 * Remove any existing snapshot.
6205 */
6206 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006207clear_snapshot(tabpage_T *tp, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006209 clear_snapshot_rec(tp->tp_snapshot[idx]);
6210 tp->tp_snapshot[idx] = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211}
6212
6213 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006214clear_snapshot_rec(frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006215{
6216 if (fr != NULL)
6217 {
6218 clear_snapshot_rec(fr->fr_next);
6219 clear_snapshot_rec(fr->fr_child);
6220 vim_free(fr);
6221 }
6222}
6223
6224/*
6225 * Restore a previously created snapshot, if there is any.
6226 * This is only done if the screen size didn't change and the window layout is
6227 * still the same.
6228 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006229 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006230restore_snapshot(
6231 int idx,
6232 int close_curwin) /* closing current window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006233{
6234 win_T *wp;
6235
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006236 if (curtab->tp_snapshot[idx] != NULL
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006237 && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006238 && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
6239 && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006240 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006241 wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 win_comp_pos();
6243 if (wp != NULL && close_curwin)
6244 win_goto(wp);
Bram Moolenaarbf3250a2019-01-06 17:25:29 +01006245 redraw_all_later(NOT_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006247 clear_snapshot(curtab, idx);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248}
6249
6250/*
6251 * Check if frames "sn" and "fr" have the same layout, same following frames
Bram Moolenaar343b8c02017-02-17 12:04:56 +01006252 * and same children. And the window pointer is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253 */
6254 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006255check_snapshot_rec(frame_T *sn, frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256{
6257 if (sn->fr_layout != fr->fr_layout
6258 || (sn->fr_next == NULL) != (fr->fr_next == NULL)
6259 || (sn->fr_child == NULL) != (fr->fr_child == NULL)
6260 || (sn->fr_next != NULL
6261 && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
6262 || (sn->fr_child != NULL
Bram Moolenaar343b8c02017-02-17 12:04:56 +01006263 && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
Bram Moolenaar2c90d512017-03-18 22:35:30 +01006264 || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006265 return FAIL;
6266 return OK;
6267}
6268
6269/*
6270 * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all
6271 * following frames and children.
6272 * Returns a pointer to the old current window, or NULL.
6273 */
6274 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006275restore_snapshot_rec(frame_T *sn, frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006276{
6277 win_T *wp = NULL;
6278 win_T *wp2;
6279
6280 fr->fr_height = sn->fr_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006281 fr->fr_width = sn->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006282 if (fr->fr_layout == FR_LEAF)
6283 {
6284 frame_new_height(fr, fr->fr_height, FALSE, FALSE);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00006285 frame_new_width(fr, fr->fr_width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006286 wp = sn->fr_win;
6287 }
6288 if (sn->fr_next != NULL)
6289 {
6290 wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
6291 if (wp2 != NULL)
6292 wp = wp2;
6293 }
6294 if (sn->fr_child != NULL)
6295 {
6296 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
6297 if (wp2 != NULL)
6298 wp = wp2;
6299 }
6300 return wp;
6301}
6302
Bram Moolenaar95064ec2013-07-17 17:15:25 +02006303#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
6304 || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006305/*
6306 * Set "win" to be the curwin and "tp" to be the current tab page.
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02006307 * restore_win() MUST be called to undo, also when FAIL is returned.
6308 * No autocommands will be executed until restore_win() is called.
Bram Moolenaard6949742013-06-16 14:18:28 +02006309 * When "no_display" is TRUE the display won't be affected, no redraw is
6310 * triggered, another tabpage access is limited.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006311 * Returns FAIL if switching to "win" failed.
6312 */
6313 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006314switch_win(
Bram Moolenaar816968d2017-09-29 21:29:18 +02006315 win_T **save_curwin,
6316 tabpage_T **save_curtab,
6317 win_T *win,
6318 tabpage_T *tp,
6319 int no_display)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006320{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006321 block_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006322 *save_curwin = curwin;
6323 if (tp != NULL)
6324 {
6325 *save_curtab = curtab;
Bram Moolenaard6949742013-06-16 14:18:28 +02006326 if (no_display)
6327 {
6328 curtab->tp_firstwin = firstwin;
6329 curtab->tp_lastwin = lastwin;
6330 curtab = tp;
6331 firstwin = curtab->tp_firstwin;
6332 lastwin = curtab->tp_lastwin;
6333 }
6334 else
6335 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar105bc352013-05-17 16:03:57 +02006336 }
6337 if (!win_valid(win))
Bram Moolenaar105bc352013-05-17 16:03:57 +02006338 return FAIL;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006339 curwin = win;
6340 curbuf = curwin->w_buffer;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006341 return OK;
6342}
6343
6344/*
6345 * Restore current tabpage and window saved by switch_win(), if still valid.
Bram Moolenaard6949742013-06-16 14:18:28 +02006346 * When "no_display" is TRUE the display won't be affected, no redraw is
6347 * triggered.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006348 */
6349 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006350restore_win(
6351 win_T *save_curwin UNUSED,
6352 tabpage_T *save_curtab UNUSED,
6353 int no_display UNUSED)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006354{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006355 if (save_curtab != NULL && valid_tabpage(save_curtab))
Bram Moolenaard6949742013-06-16 14:18:28 +02006356 {
6357 if (no_display)
6358 {
6359 curtab->tp_firstwin = firstwin;
6360 curtab->tp_lastwin = lastwin;
6361 curtab = save_curtab;
6362 firstwin = curtab->tp_firstwin;
6363 lastwin = curtab->tp_lastwin;
6364 }
6365 else
6366 goto_tabpage_tp(save_curtab, FALSE, FALSE);
6367 }
Bram Moolenaar105bc352013-05-17 16:03:57 +02006368 if (win_valid(save_curwin))
6369 {
6370 curwin = save_curwin;
6371 curbuf = curwin->w_buffer;
6372 }
Bram Moolenaar105bc352013-05-17 16:03:57 +02006373 unblock_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006374}
6375
6376/*
6377 * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
6378 * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
6379 */
6380 void
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006381switch_buffer(bufref_T *save_curbuf, buf_T *buf)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006382{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006383 block_autocmds();
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006384 set_bufref(save_curbuf, curbuf);
Bram Moolenaar105bc352013-05-17 16:03:57 +02006385 --curbuf->b_nwindows;
6386 curbuf = buf;
6387 curwin->w_buffer = buf;
6388 ++curbuf->b_nwindows;
6389}
6390
6391/*
6392 * Restore the current buffer after using switch_buffer().
6393 */
6394 void
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006395restore_buffer(bufref_T *save_curbuf)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006396{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006397 unblock_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006398 /* Check for valid buffer, just in case. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006399 if (bufref_valid(save_curbuf))
Bram Moolenaar105bc352013-05-17 16:03:57 +02006400 {
6401 --curbuf->b_nwindows;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006402 curwin->w_buffer = save_curbuf->br_buf;
6403 curbuf = save_curbuf->br_buf;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006404 ++curbuf->b_nwindows;
6405 }
6406}
6407#endif
6408
Bram Moolenaar4033c552017-09-16 20:54:51 +02006409#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006410/*
6411 * Return TRUE if there is any vertically split window.
6412 */
6413 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006414win_hasvertsplit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006415{
6416 frame_T *fr;
6417
6418 if (topframe->fr_layout == FR_ROW)
6419 return TRUE;
6420
6421 if (topframe->fr_layout == FR_COL)
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006422 FOR_ALL_FRAMES(fr, topframe->fr_child)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423 if (fr->fr_layout == FR_ROW)
6424 return TRUE;
6425
6426 return FALSE;
6427}
6428#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006429
6430#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
6431/*
6432 * Add match to the match list of window 'wp'. The pattern 'pat' will be
Bram Moolenaare37d50a2008-08-06 17:06:04 +00006433 * highlighted with the group 'grp' with priority 'prio'.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006434 * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
6435 * If no particular ID is desired, -1 must be specified for 'id'.
6436 * Return ID of added match, -1 on failure.
6437 */
6438 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006439match_add(
6440 win_T *wp,
6441 char_u *grp,
6442 char_u *pat,
6443 int prio,
6444 int id,
6445 list_T *pos_list,
6446 char_u *conceal_char UNUSED) /* pointer to conceal replacement char */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006447{
Bram Moolenaarb3414592014-06-17 17:48:32 +02006448 matchitem_T *cur;
6449 matchitem_T *prev;
6450 matchitem_T *m;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006451 int hlg_id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006452 regprog_T *regprog = NULL;
6453 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006454
Bram Moolenaarb3414592014-06-17 17:48:32 +02006455 if (*grp == NUL || (pat != NULL && *pat == NUL))
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006456 return -1;
6457 if (id < -1 || id == 0)
6458 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01006459 semsg(_("E799: Invalid ID: %d (must be greater than or equal to 1)"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006460 return -1;
6461 }
6462 if (id != -1)
6463 {
6464 cur = wp->w_match_head;
6465 while (cur != NULL)
6466 {
6467 if (cur->id == id)
6468 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01006469 semsg(_("E801: ID already taken: %d"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006470 return -1;
6471 }
6472 cur = cur->next;
6473 }
6474 }
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00006475 if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006476 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006477 semsg(_(e_nogroup), grp);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006478 return -1;
6479 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006480 if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006481 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006482 semsg(_(e_invarg2), pat);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006483 return -1;
6484 }
6485
6486 /* Find available match ID. */
6487 while (id == -1)
6488 {
6489 cur = wp->w_match_head;
6490 while (cur != NULL && cur->id != wp->w_next_match_id)
6491 cur = cur->next;
6492 if (cur == NULL)
6493 id = wp->w_next_match_id;
6494 wp->w_next_match_id++;
6495 }
6496
6497 /* Build new match. */
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006498 m = (matchitem_T *)alloc_clear(sizeof(matchitem_T));
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006499 m->id = id;
6500 m->priority = prio;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006501 m->pattern = pat == NULL ? NULL : vim_strsave(pat);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006502 m->hlg_id = hlg_id;
Bram Moolenaar0963cd92007-08-05 16:49:43 +00006503 m->match.regprog = regprog;
6504 m->match.rmm_ic = FALSE;
6505 m->match.rmm_maxcol = 0;
Bram Moolenaar264b74f2019-01-24 17:18:42 +01006506# if defined(FEAT_CONCEAL)
Bram Moolenaar6561d522015-07-21 15:48:27 +02006507 m->conceal_char = 0;
6508 if (conceal_char != NULL)
6509 m->conceal_char = (*mb_ptr2char)(conceal_char);
Bram Moolenaar42356152016-03-31 22:27:40 +02006510# endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006511
Bram Moolenaarb3414592014-06-17 17:48:32 +02006512 /* Set up position matches */
6513 if (pos_list != NULL)
6514 {
6515 linenr_T toplnum = 0;
6516 linenr_T botlnum = 0;
6517 listitem_T *li;
6518 int i;
6519
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006520 for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006521 i++, li = li->li_next)
6522 {
6523 linenr_T lnum = 0;
6524 colnr_T col = 0;
6525 int len = 1;
6526 list_T *subl;
6527 listitem_T *subli;
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006528 int error = FALSE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006529
Bram Moolenaarb3414592014-06-17 17:48:32 +02006530 if (li->li_tv.v_type == VAR_LIST)
6531 {
6532 subl = li->li_tv.vval.v_list;
6533 if (subl == NULL)
6534 goto fail;
6535 subli = subl->lv_first;
6536 if (subli == NULL)
6537 goto fail;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006538 lnum = tv_get_number_chk(&subli->li_tv, &error);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006539 if (error == TRUE)
6540 goto fail;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006541 if (lnum == 0)
6542 {
6543 --i;
6544 continue;
6545 }
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006546 m->pos.pos[i].lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006547 subli = subli->li_next;
6548 if (subli != NULL)
6549 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006550 col = tv_get_number_chk(&subli->li_tv, &error);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006551 if (error == TRUE)
6552 goto fail;
6553 subli = subli->li_next;
6554 if (subli != NULL)
6555 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006556 len = tv_get_number_chk(&subli->li_tv, &error);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006557 if (error == TRUE)
6558 goto fail;
6559 }
6560 }
6561 m->pos.pos[i].col = col;
6562 m->pos.pos[i].len = len;
6563 }
6564 else if (li->li_tv.v_type == VAR_NUMBER)
6565 {
6566 if (li->li_tv.vval.v_number == 0)
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006567 {
6568 --i;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006569 continue;
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006570 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006571 m->pos.pos[i].lnum = li->li_tv.vval.v_number;
6572 m->pos.pos[i].col = 0;
6573 m->pos.pos[i].len = 0;
6574 }
6575 else
6576 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006577 emsg(_("List or number required"));
Bram Moolenaarb3414592014-06-17 17:48:32 +02006578 goto fail;
6579 }
6580 if (toplnum == 0 || lnum < toplnum)
6581 toplnum = lnum;
Bram Moolenaar41d75232014-06-25 17:58:11 +02006582 if (botlnum == 0 || lnum >= botlnum)
6583 botlnum = lnum + 1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006584 }
6585
6586 /* Calculate top and bottom lines for redrawing area */
6587 if (toplnum != 0)
6588 {
6589 if (wp->w_buffer->b_mod_set)
6590 {
6591 if (wp->w_buffer->b_mod_top > toplnum)
6592 wp->w_buffer->b_mod_top = toplnum;
6593 if (wp->w_buffer->b_mod_bot < botlnum)
6594 wp->w_buffer->b_mod_bot = botlnum;
6595 }
6596 else
6597 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02006598 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006599 wp->w_buffer->b_mod_top = toplnum;
6600 wp->w_buffer->b_mod_bot = botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02006601 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006602 }
6603 m->pos.toplnum = toplnum;
6604 m->pos.botlnum = botlnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006605 rtype = VALID;
6606 }
6607 }
6608
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006609 /* Insert new match. The match list is in ascending order with regard to
6610 * the match priorities. */
6611 cur = wp->w_match_head;
6612 prev = cur;
6613 while (cur != NULL && prio >= cur->priority)
6614 {
6615 prev = cur;
6616 cur = cur->next;
6617 }
6618 if (cur == prev)
6619 wp->w_match_head = m;
6620 else
6621 prev->next = m;
6622 m->next = cur;
6623
Bram Moolenaarb3414592014-06-17 17:48:32 +02006624 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006625 return id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006626
6627fail:
6628 vim_free(m);
6629 return -1;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006630}
6631
6632/*
6633 * Delete match with ID 'id' in the match list of window 'wp'.
6634 * Print error messages if 'perr' is TRUE.
6635 */
6636 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006637match_delete(win_T *wp, int id, int perr)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006638{
Bram Moolenaarb3414592014-06-17 17:48:32 +02006639 matchitem_T *cur = wp->w_match_head;
6640 matchitem_T *prev = cur;
6641 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006642
6643 if (id < 1)
6644 {
6645 if (perr == TRUE)
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01006646 semsg(_("E802: Invalid ID: %d (must be greater than or equal to 1)"),
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006647 id);
6648 return -1;
6649 }
6650 while (cur != NULL && cur->id != id)
6651 {
6652 prev = cur;
6653 cur = cur->next;
6654 }
6655 if (cur == NULL)
6656 {
6657 if (perr == TRUE)
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01006658 semsg(_("E803: ID not found: %d"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006659 return -1;
6660 }
6661 if (cur == prev)
6662 wp->w_match_head = cur->next;
6663 else
6664 prev->next = cur->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02006665 vim_regfree(cur->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006666 vim_free(cur->pattern);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006667 if (cur->pos.toplnum != 0)
6668 {
6669 if (wp->w_buffer->b_mod_set)
6670 {
6671 if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
6672 wp->w_buffer->b_mod_top = cur->pos.toplnum;
6673 if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
6674 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
6675 }
6676 else
6677 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02006678 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006679 wp->w_buffer->b_mod_top = cur->pos.toplnum;
6680 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02006681 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006682 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006683 rtype = VALID;
6684 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006685 vim_free(cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006686 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006687 return 0;
6688}
6689
6690/*
6691 * Delete all matches in the match list of window 'wp'.
6692 */
6693 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006694clear_matches(win_T *wp)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006695{
6696 matchitem_T *m;
6697
6698 while (wp->w_match_head != NULL)
6699 {
6700 m = wp->w_match_head->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02006701 vim_regfree(wp->w_match_head->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006702 vim_free(wp->w_match_head->pattern);
6703 vim_free(wp->w_match_head);
6704 wp->w_match_head = m;
6705 }
6706 redraw_later(SOME_VALID);
6707}
6708
6709/*
6710 * Get match from ID 'id' in window 'wp'.
6711 * Return NULL if match not found.
6712 */
6713 matchitem_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006714get_match(win_T *wp, int id)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006715{
6716 matchitem_T *cur = wp->w_match_head;
6717
6718 while (cur != NULL && cur->id != id)
6719 cur = cur->next;
6720 return cur;
6721}
6722#endif
Bram Moolenaar6d216452013-05-12 19:00:41 +02006723
6724#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
6725 int
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02006726get_win_number(win_T *wp, win_T *first_win)
Bram Moolenaar6d216452013-05-12 19:00:41 +02006727{
6728 int i = 1;
6729 win_T *w;
6730
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02006731 for (w = first_win; w != NULL && w != wp; w = W_NEXT(w))
Bram Moolenaar6d216452013-05-12 19:00:41 +02006732 ++i;
6733
6734 if (w == NULL)
6735 return 0;
6736 else
6737 return i;
6738}
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02006739
6740 int
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02006741get_tab_number(tabpage_T *tp UNUSED)
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02006742{
6743 int i = 1;
6744 tabpage_T *t;
6745
6746 for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next)
6747 ++i;
6748
6749 if (t == NULL)
6750 return 0;
6751 else
6752 return i;
6753}
Bram Moolenaar6d216452013-05-12 19:00:41 +02006754#endif
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006755
6756/*
6757 * Return TRUE if "topfrp" and its children are at the right height.
6758 */
6759 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006760frame_check_height(frame_T *topfrp, int height)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006761{
6762 frame_T *frp;
6763
6764 if (topfrp->fr_height != height)
6765 return FALSE;
6766
6767 if (topfrp->fr_layout == FR_ROW)
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006768 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006769 if (frp->fr_height != height)
6770 return FALSE;
6771
6772 return TRUE;
6773}
6774
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006775/*
6776 * Return TRUE if "topfrp" and its children are at the right width.
6777 */
6778 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006779frame_check_width(frame_T *topfrp, int width)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006780{
6781 frame_T *frp;
6782
6783 if (topfrp->fr_width != width)
6784 return FALSE;
6785
6786 if (topfrp->fr_layout == FR_COL)
Bram Moolenaar3d1491e2018-12-22 17:07:50 +01006787 FOR_ALL_FRAMES(frp, topfrp->fr_child)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006788 if (frp->fr_width != width)
6789 return FALSE;
6790
6791 return TRUE;
6792}
Bram Moolenaarb893ac22013-06-26 14:04:47 +02006793
Bram Moolenaar86edef62016-03-13 18:07:30 +01006794#if defined(FEAT_EVAL) || defined(PROTO)
6795 int
6796win_getid(typval_T *argvars)
6797{
6798 int winnr;
6799 win_T *wp;
6800
6801 if (argvars[0].v_type == VAR_UNKNOWN)
6802 return curwin->w_id;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006803 winnr = tv_get_number(&argvars[0]);
Bram Moolenaar86edef62016-03-13 18:07:30 +01006804 if (winnr > 0)
6805 {
6806 if (argvars[1].v_type == VAR_UNKNOWN)
6807 wp = firstwin;
6808 else
6809 {
6810 tabpage_T *tp;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 int tabnr = tv_get_number(&argvars[1]);
Bram Moolenaar86edef62016-03-13 18:07:30 +01006812
Bram Moolenaar29323592016-07-24 22:04:11 +02006813 FOR_ALL_TABPAGES(tp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01006814 if (--tabnr == 0)
6815 break;
6816 if (tp == NULL)
6817 return -1;
Bram Moolenaar8e639052016-11-13 14:31:40 +01006818 if (tp == curtab)
6819 wp = firstwin;
6820 else
6821 wp = tp->tp_firstwin;
Bram Moolenaar86edef62016-03-13 18:07:30 +01006822 }
6823 for ( ; wp != NULL; wp = wp->w_next)
6824 if (--winnr == 0)
6825 return wp->w_id;
6826 }
6827 return 0;
6828}
6829
6830 int
6831win_gotoid(typval_T *argvars)
6832{
6833 win_T *wp;
6834 tabpage_T *tp;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006835 int id = tv_get_number(&argvars[0]);
Bram Moolenaar86edef62016-03-13 18:07:30 +01006836
Bram Moolenaar29323592016-07-24 22:04:11 +02006837 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01006838 if (wp->w_id == id)
6839 {
6840 goto_tabpage_win(tp, wp);
6841 return 1;
6842 }
6843 return 0;
6844}
6845
6846 void
6847win_id2tabwin(typval_T *argvars, list_T *list)
6848{
6849 win_T *wp;
6850 tabpage_T *tp;
6851 int winnr = 1;
6852 int tabnr = 1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006853 int id = tv_get_number(&argvars[0]);
Bram Moolenaar86edef62016-03-13 18:07:30 +01006854
Bram Moolenaar29323592016-07-24 22:04:11 +02006855 FOR_ALL_TABPAGES(tp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01006856 {
Bram Moolenaar29323592016-07-24 22:04:11 +02006857 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01006858 {
6859 if (wp->w_id == id)
6860 {
6861 list_append_number(list, tabnr);
6862 list_append_number(list, winnr);
6863 return;
6864 }
6865 ++winnr;
6866 }
6867 ++tabnr;
6868 winnr = 1;
6869 }
6870 list_append_number(list, 0);
6871 list_append_number(list, 0);
6872}
6873
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006874 win_T *
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01006875win_id2wp(int id)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006876{
6877 win_T *wp;
6878 tabpage_T *tp;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006879
6880 FOR_ALL_TAB_WINDOWS(tp, wp)
6881 if (wp->w_id == id)
6882 return wp;
6883
6884 return NULL;
6885}
6886
Bram Moolenaar86edef62016-03-13 18:07:30 +01006887 int
6888win_id2win(typval_T *argvars)
6889{
6890 win_T *wp;
6891 int nr = 1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006892 int id = tv_get_number(&argvars[0]);
Bram Moolenaar86edef62016-03-13 18:07:30 +01006893
Bram Moolenaar29323592016-07-24 22:04:11 +02006894 FOR_ALL_WINDOWS(wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01006895 {
6896 if (wp->w_id == id)
6897 return nr;
6898 ++nr;
6899 }
6900 return 0;
6901}
Bram Moolenaar9cdf86b2016-03-13 19:04:51 +01006902
6903 void
6904win_findbuf(typval_T *argvars, list_T *list)
6905{
6906 win_T *wp;
6907 tabpage_T *tp;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006908 int bufnr = tv_get_number(&argvars[0]);
Bram Moolenaar9cdf86b2016-03-13 19:04:51 +01006909
Bram Moolenaar29323592016-07-24 22:04:11 +02006910 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar9cdf86b2016-03-13 19:04:51 +01006911 if (wp->w_buffer->b_fnum == bufnr)
6912 list_append_number(list, wp->w_id);
6913}
6914
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02006915/*
6916 * Get the layout of the given tab page for winlayout().
6917 */
6918 void
6919get_framelayout(frame_T *fr, list_T *l, int outer)
6920{
6921 frame_T *child;
6922 list_T *fr_list;
6923 list_T *win_list;
6924
6925 if (fr == NULL)
6926 return;
6927
6928 if (outer)
6929 // outermost call from f_winlayout()
6930 fr_list = l;
6931 else
6932 {
6933 fr_list = list_alloc();
6934 if (fr_list == NULL)
6935 return;
6936 list_append_list(l, fr_list);
6937 }
6938
6939 if (fr->fr_layout == FR_LEAF)
6940 {
6941 if (fr->fr_win != NULL)
6942 {
6943 list_append_string(fr_list, (char_u *)"leaf", -1);
6944 list_append_number(fr_list, fr->fr_win->w_id);
6945 }
6946 }
6947 else
6948 {
6949 list_append_string(fr_list,
6950 fr->fr_layout == FR_ROW ? (char_u *)"row" : (char_u *)"col", -1);
6951
6952 win_list = list_alloc();
6953 if (win_list == NULL)
6954 return;
6955 list_append_list(fr_list, win_list);
6956 child = fr->fr_child;
6957 while (child != NULL)
6958 {
6959 get_framelayout(child, win_list, FALSE);
6960 child = child->fr_next;
6961 }
6962 }
6963}
Bram Moolenaar86edef62016-03-13 18:07:30 +01006964#endif