blob: 5a2d8a42b5d17810c92c56f175cba485ac5943f8 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
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 Moolenaar071d4272004-06-13 20:20:40 +000012static int path_is_url __ARGS((char_u *p));
13#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar884ae642009-02-22 01:37:59 +000014static void win_init __ARGS((win_T *newp, win_T *oldp, int flags));
Bram Moolenaar746ebd32009-06-16 14:01:43 +000015static void win_init_some __ARGS((win_T *newp, win_T *oldp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000016static void frame_comp_pos __ARGS((frame_T *topfrp, int *row, int *col));
17static void frame_setheight __ARGS((frame_T *curfrp, int height));
18#ifdef FEAT_VERTSPLIT
19static void frame_setwidth __ARGS((frame_T *curfrp, int width));
20#endif
21static void win_exchange __ARGS((long));
22static void win_rotate __ARGS((int, int));
23static void win_totop __ARGS((int size, int flags));
24static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height));
Bram Moolenaar49d7bf12006-02-17 21:45:41 +000025static int last_window __ARGS((void));
Bram Moolenaarbef1c362012-05-25 12:39:00 +020026static int close_last_window_tabpage __ARGS((win_T *win, int free_buf, tabpage_T *prev_curtab));
Bram Moolenaarf740b292006-02-16 22:11:02 +000027static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
Bram Moolenaarf740b292006-02-16 22:11:02 +000028static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000029static tabpage_T *alt_tabpage __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +000030static win_T *frame2win __ARGS((frame_T *frp));
31static int frame_has_win __ARGS((frame_T *frp, win_T *wp));
32static void frame_new_height __ARGS((frame_T *topfrp, int height, int topfirst, int wfh));
33static int frame_fixed_height __ARGS((frame_T *frp));
34#ifdef FEAT_VERTSPLIT
Bram Moolenaarbe4d5062006-03-18 21:30:13 +000035static int frame_fixed_width __ARGS((frame_T *frp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000036static void frame_add_statusline __ARGS((frame_T *frp));
Bram Moolenaarbe4d5062006-03-18 21:30:13 +000037static void frame_new_width __ARGS((frame_T *topfrp, int width, int leftfirst, int wfw));
Bram Moolenaar071d4272004-06-13 20:20:40 +000038static void frame_add_vsep __ARGS((frame_T *frp));
39static int frame_minwidth __ARGS((frame_T *topfrp, win_T *next_curwin));
40static void frame_fix_width __ARGS((win_T *wp));
41#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000042#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +000043static int win_alloc_firstwin __ARGS((win_T *oldwin));
Bram Moolenaar746ebd32009-06-16 14:01:43 +000044static void new_frame __ARGS((win_T *wp));
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000045#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +000046static tabpage_T *alloc_tabpage __ARGS((void));
Bram Moolenaar49e649f2013-05-06 04:50:35 +020047static int leave_tabpage __ARGS((buf_T *new_curbuf, int trigger_leave_autocmds));
48static void enter_tabpage __ARGS((tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds));
Bram Moolenaar071d4272004-06-13 20:20:40 +000049static void frame_fix_height __ARGS((win_T *wp));
50static int frame_minheight __ARGS((frame_T *topfrp, win_T *next_curwin));
Bram Moolenaar49e649f2013-05-06 04:50:35 +020051static void win_enter_ext __ARGS((win_T *wp, int undo_sync, int no_curwin, int trigger_enter_autocmds, int trigger_leave_autocmds));
Bram Moolenaarf740b292006-02-16 22:11:02 +000052static void win_free __ARGS((win_T *wp, tabpage_T *tp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000053static void frame_append __ARGS((frame_T *after, frame_T *frp));
54static void frame_insert __ARGS((frame_T *before, frame_T *frp));
55static void frame_remove __ARGS((frame_T *frp));
Bram Moolenaarf0327f62013-06-28 20:16:55 +020056# ifdef FEAT_VERTSPLIT
Bram Moolenaar071d4272004-06-13 20:20:40 +000057static void win_goto_ver __ARGS((int up, long count));
58static void win_goto_hor __ARGS((int left, long count));
Bram Moolenaarf0327f62013-06-28 20:16:55 +020059# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000060static void frame_add_height __ARGS((frame_T *frp, int n));
61static void last_status_rec __ARGS((frame_T *fr, int statusline));
62
Bram Moolenaar071d4272004-06-13 20:20:40 +000063static void make_snapshot_rec __ARGS((frame_T *fr, frame_T **frp));
Bram Moolenaar746ebd32009-06-16 14:01:43 +000064static void clear_snapshot __ARGS((tabpage_T *tp, int idx));
Bram Moolenaar071d4272004-06-13 20:20:40 +000065static void clear_snapshot_rec __ARGS((frame_T *fr));
Bram Moolenaar071d4272004-06-13 20:20:40 +000066static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
67static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
68
Bram Moolenaarb893ac22013-06-26 14:04:47 +020069static int frame_check_height __ARGS((frame_T *topfrp, int height));
70#ifdef FEAT_VERTSPLIT
71static int frame_check_width __ARGS((frame_T *topfrp, int width));
72#endif
73
Bram Moolenaar071d4272004-06-13 20:20:40 +000074#endif /* FEAT_WINDOWS */
Bram Moolenaar6ee10162007-07-26 20:58:42 +000075
Bram Moolenaar746ebd32009-06-16 14:01:43 +000076static win_T *win_alloc __ARGS((win_T *after, int hidden));
Bram Moolenaar0215e8e2010-12-17 17:35:10 +010077static void set_fraction __ARGS((win_T *wp));
Bram Moolenaar071d4272004-06-13 20:20:40 +000078
79#define URL_SLASH 1 /* path_is_url() has found "://" */
80#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
81
Bram Moolenaarb6799ac2007-05-10 16:44:05 +000082#define NOWIN (win_T *)-1 /* non-existing window */
Bram Moolenaar071d4272004-06-13 20:20:40 +000083
Bram Moolenaar05159a02005-02-26 23:04:13 +000084#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +000085# define ROWS_AVAIL (Rows - p_ch - tabline_height())
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000086#else
87# define ROWS_AVAIL (Rows - p_ch)
Bram Moolenaar05159a02005-02-26 23:04:13 +000088#endif
89
Bram Moolenaar071d4272004-06-13 20:20:40 +000090#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000091
92static char *m_onlyone = N_("Already only one window");
93
Bram Moolenaar071d4272004-06-13 20:20:40 +000094/*
95 * all CTRL-W window commands are handled here, called from normal_cmd().
96 */
97 void
98do_window(nchar, Prenum, xchar)
99 int nchar;
100 long Prenum;
101 int xchar; /* extra char from ":wincmd gx" or NUL */
102{
103 long Prenum1;
104 win_T *wp;
105#if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
106 char_u *ptr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000107 linenr_T lnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108#endif
109#ifdef FEAT_FIND_ID
110 int type = FIND_DEFINE;
111 int len;
112#endif
113 char_u cbuf[40];
114
115 if (Prenum == 0)
116 Prenum1 = 1;
117 else
118 Prenum1 = Prenum;
119
120#ifdef FEAT_CMDWIN
121# define CHECK_CMDWIN if (cmdwin_type != 0) { EMSG(_(e_cmdwin)); break; }
122#else
123# define CHECK_CMDWIN
124#endif
125
126 switch (nchar)
127 {
128/* split current window in two parts, horizontally */
129 case 'S':
130 case Ctrl_S:
131 case 's':
132 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000133 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000134#ifdef FEAT_QUICKFIX
135 /* When splitting the quickfix window open a new buffer in it,
136 * don't replicate the quickfix buffer. */
137 if (bt_quickfix(curbuf))
138 goto newwindow;
139#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140#ifdef FEAT_GUI
141 need_mouse_correct = TRUE;
142#endif
143 win_split((int)Prenum, 0);
144 break;
145
146#ifdef FEAT_VERTSPLIT
147/* split current window in two parts, vertically */
148 case Ctrl_V:
149 case 'v':
150 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000152# ifdef FEAT_QUICKFIX
153 /* When splitting the quickfix window open a new buffer in it,
154 * don't replicate the quickfix buffer. */
155 if (bt_quickfix(curbuf))
156 goto newwindow;
157# endif
158# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 need_mouse_correct = TRUE;
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000160# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 win_split((int)Prenum, WSP_VERT);
162 break;
163#endif
164
165/* split current window and edit alternate file */
166 case Ctrl_HAT:
167 case '^':
168 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170 STRCPY(cbuf, "split #");
171 if (Prenum)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000172 vim_snprintf((char *)cbuf + 7, sizeof(cbuf) - 7,
173 "%ld", Prenum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 do_cmdline_cmd(cbuf);
175 break;
176
177/* open new window */
178 case Ctrl_N:
179 case 'n':
180 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000182#ifdef FEAT_QUICKFIX
183newwindow:
184#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185 if (Prenum)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000186 /* window height */
187 vim_snprintf((char *)cbuf, sizeof(cbuf) - 5, "%ld", Prenum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188 else
189 cbuf[0] = NUL;
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000190#if defined(FEAT_VERTSPLIT) && defined(FEAT_QUICKFIX)
191 if (nchar == 'v' || nchar == Ctrl_V)
192 STRCAT(cbuf, "v");
193#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194 STRCAT(cbuf, "new");
195 do_cmdline_cmd(cbuf);
196 break;
197
198/* quit current window */
199 case Ctrl_Q:
200 case 'q':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202 do_cmdline_cmd((char_u *)"quit");
203 break;
204
205/* close current window */
206 case Ctrl_C:
207 case 'c':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 do_cmdline_cmd((char_u *)"close");
210 break;
211
212#if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
213/* close preview window */
214 case Ctrl_Z:
215 case 'z':
216 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218 do_cmdline_cmd((char_u *)"pclose");
219 break;
220
221/* cursor to preview window */
222 case 'P':
223 for (wp = firstwin; wp != NULL; wp = wp->w_next)
224 if (wp->w_p_pvw)
225 break;
226 if (wp == NULL)
227 EMSG(_("E441: There is no preview window"));
228 else
229 win_goto(wp);
230 break;
231#endif
232
233/* close all but current window */
234 case Ctrl_O:
235 case 'o':
236 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238 do_cmdline_cmd((char_u *)"only");
239 break;
240
241/* cursor to next window with wrap around */
242 case Ctrl_W:
243 case 'w':
244/* cursor to previous window with wrap around */
245 case 'W':
246 CHECK_CMDWIN
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000247 if (firstwin == lastwin && Prenum != 1) /* just one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000248 beep_flush();
249 else
250 {
251 if (Prenum) /* go to specified window */
252 {
253 for (wp = firstwin; --Prenum > 0; )
254 {
255 if (wp->w_next == NULL)
256 break;
257 else
258 wp = wp->w_next;
259 }
260 }
261 else
262 {
263 if (nchar == 'W') /* go to previous window */
264 {
265 wp = curwin->w_prev;
266 if (wp == NULL)
267 wp = lastwin; /* wrap around */
268 }
269 else /* go to next window */
270 {
271 wp = curwin->w_next;
272 if (wp == NULL)
273 wp = firstwin; /* wrap around */
274 }
275 }
276 win_goto(wp);
277 }
278 break;
279
280/* cursor to window below */
281 case 'j':
282 case K_DOWN:
283 case Ctrl_J:
284 CHECK_CMDWIN
285#ifdef FEAT_VERTSPLIT
286 win_goto_ver(FALSE, Prenum1);
287#else
288 for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
289 wp = wp->w_next)
290 ;
291 win_goto(wp);
292#endif
293 break;
294
295/* cursor to window above */
296 case 'k':
297 case K_UP:
298 case Ctrl_K:
299 CHECK_CMDWIN
300#ifdef FEAT_VERTSPLIT
301 win_goto_ver(TRUE, Prenum1);
302#else
303 for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
304 wp = wp->w_prev)
305 ;
306 win_goto(wp);
307#endif
308 break;
309
310#ifdef FEAT_VERTSPLIT
311/* cursor to left window */
312 case 'h':
313 case K_LEFT:
314 case Ctrl_H:
315 case K_BS:
316 CHECK_CMDWIN
317 win_goto_hor(TRUE, Prenum1);
318 break;
319
320/* cursor to right window */
321 case 'l':
322 case K_RIGHT:
323 case Ctrl_L:
324 CHECK_CMDWIN
325 win_goto_hor(FALSE, Prenum1);
326 break;
327#endif
328
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000329/* move window to new tab page */
330 case 'T':
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000331 if (one_window())
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000332 MSG(_(m_onlyone));
333 else
334 {
335 tabpage_T *oldtab = curtab;
336 tabpage_T *newtab;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000337
338 /* First create a new tab with the window, then go back to
339 * the old tab and close the window there. */
Bram Moolenaar89d40322006-08-29 15:30:07 +0000340 wp = curwin;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000341 if (win_new_tabpage((int)Prenum) == OK
342 && valid_tabpage(oldtab))
343 {
344 newtab = curtab;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200345 goto_tabpage_tp(oldtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000346 if (curwin == wp)
347 win_close(curwin, FALSE);
348 if (valid_tabpage(newtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200349 goto_tabpage_tp(newtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000350 }
351 }
352 break;
353
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354/* cursor to top-left window */
355 case 't':
356 case Ctrl_T:
357 win_goto(firstwin);
358 break;
359
360/* cursor to bottom-right window */
361 case 'b':
362 case Ctrl_B:
363 win_goto(lastwin);
364 break;
365
366/* cursor to last accessed (previous) window */
367 case 'p':
368 case Ctrl_P:
369 if (prevwin == NULL)
370 beep_flush();
371 else
372 win_goto(prevwin);
373 break;
374
375/* exchange current and next window */
376 case 'x':
377 case Ctrl_X:
378 CHECK_CMDWIN
379 win_exchange(Prenum);
380 break;
381
382/* rotate windows downwards */
383 case Ctrl_R:
384 case 'r':
385 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 win_rotate(FALSE, (int)Prenum1); /* downwards */
388 break;
389
390/* rotate windows upwards */
391 case 'R':
392 CHECK_CMDWIN
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394 win_rotate(TRUE, (int)Prenum1); /* upwards */
395 break;
396
397/* move window to the very top/bottom/left/right */
398 case 'K':
399 case 'J':
400#ifdef FEAT_VERTSPLIT
401 case 'H':
402 case 'L':
403#endif
404 CHECK_CMDWIN
405 win_totop((int)Prenum,
406 ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
407 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
408 break;
409
410/* make all windows the same height */
411 case '=':
412#ifdef FEAT_GUI
413 need_mouse_correct = TRUE;
414#endif
415 win_equal(NULL, FALSE, 'b');
416 break;
417
418/* increase current window height */
419 case '+':
420#ifdef FEAT_GUI
421 need_mouse_correct = TRUE;
422#endif
423 win_setheight(curwin->w_height + (int)Prenum1);
424 break;
425
426/* decrease current window height */
427 case '-':
428#ifdef FEAT_GUI
429 need_mouse_correct = TRUE;
430#endif
431 win_setheight(curwin->w_height - (int)Prenum1);
432 break;
433
434/* set current window height */
435 case Ctrl__:
436 case '_':
437#ifdef FEAT_GUI
438 need_mouse_correct = TRUE;
439#endif
440 win_setheight(Prenum ? (int)Prenum : 9999);
441 break;
442
443#ifdef FEAT_VERTSPLIT
444/* increase current window width */
445 case '>':
446#ifdef FEAT_GUI
447 need_mouse_correct = TRUE;
448#endif
449 win_setwidth(curwin->w_width + (int)Prenum1);
450 break;
451
452/* decrease current window width */
453 case '<':
454#ifdef FEAT_GUI
455 need_mouse_correct = TRUE;
456#endif
457 win_setwidth(curwin->w_width - (int)Prenum1);
458 break;
459
460/* set current window width */
461 case '|':
462#ifdef FEAT_GUI
463 need_mouse_correct = TRUE;
464#endif
465 win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
466 break;
467#endif
468
469/* jump to tag and split window if tag exists (in preview window) */
470#if defined(FEAT_QUICKFIX)
471 case '}':
472 CHECK_CMDWIN
473 if (Prenum)
474 g_do_tagpreview = Prenum;
475 else
476 g_do_tagpreview = p_pvh;
477 /*FALLTHROUGH*/
478#endif
479 case ']':
480 case Ctrl_RSB:
481 CHECK_CMDWIN
Bram Moolenaard355c502014-09-23 13:48:43 +0200482 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000483 if (Prenum)
484 postponed_split = Prenum;
485 else
486 postponed_split = -1;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200487#ifdef FEAT_QUICKFIX
Bram Moolenaard355c502014-09-23 13:48:43 +0200488 g_do_tagpreview = 0;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200489#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490
Bram Moolenaard355c502014-09-23 13:48:43 +0200491 /* Execute the command right here, required when "wincmd ]"
492 * was used in a function. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000493 do_nv_ident(Ctrl_RSB, NUL);
494 break;
495
496#ifdef FEAT_SEARCHPATH
497/* edit file name under cursor in a new window */
498 case 'f':
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000499 case 'F':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 case Ctrl_F:
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000501wingotofile:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 CHECK_CMDWIN
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000503
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000504 ptr = grab_file_name(Prenum1, &lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 if (ptr != NULL)
506 {
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000507# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 need_mouse_correct = TRUE;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000509# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 setpcmark();
511 if (win_split(0, 0) == OK)
512 {
Bram Moolenaar3368ea22010-09-21 16:56:35 +0200513 RESET_BINDING(curwin);
Bram Moolenaar701f7af2008-11-15 13:12:07 +0000514 (void)do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
515 ECMD_HIDE, NULL);
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000516 if (nchar == 'F' && lnum >= 0)
517 {
518 curwin->w_cursor.lnum = lnum;
519 check_cursor_lnum();
520 beginline(BL_SOL | BL_FIX);
521 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 }
523 vim_free(ptr);
524 }
525 break;
526#endif
527
528#ifdef FEAT_FIND_ID
Bram Moolenaarb6799ac2007-05-10 16:44:05 +0000529/* Go to the first occurrence of the identifier under cursor along path in a
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 * new window -- webb
531 */
532 case 'i': /* Go to any match */
533 case Ctrl_I:
534 type = FIND_ANY;
535 /* FALLTHROUGH */
536 case 'd': /* Go to definition, using 'define' */
537 case Ctrl_D:
538 CHECK_CMDWIN
539 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
540 break;
541 find_pattern_in_path(ptr, 0, len, TRUE,
542 Prenum == 0 ? TRUE : FALSE, type,
543 Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
544 curwin->w_set_curswant = TRUE;
545 break;
546#endif
547
Bram Moolenaar05159a02005-02-26 23:04:13 +0000548 case K_KENTER:
549 case CAR:
550#if defined(FEAT_QUICKFIX)
551 /*
552 * In a quickfix window a <CR> jumps to the error under the
553 * cursor in a new window.
554 */
555 if (bt_quickfix(curbuf))
556 {
Bram Moolenaar28c258f2006-01-25 22:02:51 +0000557 sprintf((char *)cbuf, "split +%ld%s",
558 (long)curwin->w_cursor.lnum,
559 (curwin->w_llist_ref == NULL) ? "cc" : "ll");
Bram Moolenaar05159a02005-02-26 23:04:13 +0000560 do_cmdline_cmd(cbuf);
561 }
562#endif
563 break;
564
565
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566/* CTRL-W g extended commands */
567 case 'g':
568 case Ctrl_G:
569 CHECK_CMDWIN
570#ifdef USE_ON_FLY_SCROLL
571 dont_scroll = TRUE; /* disallow scrolling here */
572#endif
573 ++no_mapping;
574 ++allow_keys; /* no mapping for xchar, but allow key codes */
575 if (xchar == NUL)
Bram Moolenaar61abfd12007-09-13 16:26:47 +0000576 xchar = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 LANGMAP_ADJUST(xchar, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 --no_mapping;
579 --allow_keys;
580#ifdef FEAT_CMDL_INFO
581 (void)add_to_showcmd(xchar);
582#endif
583 switch (xchar)
584 {
585#if defined(FEAT_QUICKFIX)
586 case '}':
587 xchar = Ctrl_RSB;
588 if (Prenum)
589 g_do_tagpreview = Prenum;
590 else
591 g_do_tagpreview = p_pvh;
592 /*FALLTHROUGH*/
593#endif
594 case ']':
595 case Ctrl_RSB:
Bram Moolenaard355c502014-09-23 13:48:43 +0200596 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 if (Prenum)
598 postponed_split = Prenum;
599 else
600 postponed_split = -1;
601
602 /* Execute the command right here, required when
603 * "wincmd g}" was used in a function. */
604 do_nv_ident('g', xchar);
605 break;
606
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000607#ifdef FEAT_SEARCHPATH
608 case 'f': /* CTRL-W gf: "gf" in a new tab page */
Bram Moolenaar57657d82006-04-21 22:12:41 +0000609 case 'F': /* CTRL-W gF: "gF" in a new tab page */
Bram Moolenaar6d1dcff2010-01-27 20:26:46 +0100610 cmdmod.tab = tabpage_index(curtab) + 1;
Bram Moolenaar57657d82006-04-21 22:12:41 +0000611 nchar = xchar;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000612 goto wingotofile;
613#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614 default:
615 beep_flush();
616 break;
617 }
618 break;
619
620 default: beep_flush();
621 break;
622 }
623}
624
625/*
626 * split the current window, implements CTRL-W s and :split
627 *
628 * "size" is the height or width for the new window, 0 to use half of current
629 * height or width.
630 *
631 * "flags":
632 * WSP_ROOM: require enough room for new window
633 * WSP_VERT: vertical split.
634 * WSP_TOP: open window at the top-left of the shell (help window).
635 * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
636 * WSP_HELP: creating the help window, keep layout snapshot
637 *
638 * return FAIL for failure, OK otherwise
639 */
640 int
641win_split(size, flags)
642 int size;
643 int flags;
644{
Bram Moolenaar80a94a52006-02-23 21:26:58 +0000645 /* When the ":tab" modifier was used open a new tab page instead. */
646 if (may_open_tabpage() == OK)
647 return OK;
648
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649 /* Add flags from ":vertical", ":topleft" and ":botright". */
650 flags |= cmdmod.split;
651 if ((flags & WSP_TOP) && (flags & WSP_BOT))
652 {
653 EMSG(_("E442: Can't split topleft and botright at the same time"));
654 return FAIL;
655 }
656
657 /* When creating the help window make a snapshot of the window layout.
658 * Otherwise clear the snapshot, it's now invalid. */
659 if (flags & WSP_HELP)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000660 make_snapshot(SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000662 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663
664 return win_split_ins(size, flags, NULL, 0);
665}
666
667/*
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100668 * When "new_wp" is NULL: split the current window in two.
669 * When "new_wp" is not NULL: insert this window at the far
Bram Moolenaar071d4272004-06-13 20:20:40 +0000670 * top/left/right/bottom.
671 * return FAIL for failure, OK otherwise
672 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000673 int
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100674win_split_ins(size, flags, new_wp, dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 int size;
676 int flags;
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100677 win_T *new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678 int dir;
679{
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100680 win_T *wp = new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 win_T *oldwin;
682 int new_size = size;
683 int i;
684 int need_status = 0;
685 int do_equal = FALSE;
686 int needed;
687 int available;
688 int oldwin_height = 0;
689 int layout;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200690 frame_T *frp, *curfrp, *frp2, *prevfrp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000691 int before;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200692 int minheight;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200693 int wmh1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000694
695 if (flags & WSP_TOP)
696 oldwin = firstwin;
697 else if (flags & WSP_BOT)
698 oldwin = lastwin;
699 else
700 oldwin = curwin;
701
702 /* add a status line when p_ls == 1 and splitting the first window */
703 if (lastwin == firstwin && p_ls == 1 && oldwin->w_status_height == 0)
704 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100705 if (oldwin->w_height <= p_wmh && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 {
707 EMSG(_(e_noroom));
708 return FAIL;
709 }
710 need_status = STATUS_HEIGHT;
711 }
712
Bram Moolenaaree79cbc2007-05-02 19:50:14 +0000713#ifdef FEAT_GUI
714 /* May be needed for the scrollbars that are going to change. */
715 if (gui.in_use)
716 out_flush();
717#endif
718
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719#ifdef FEAT_VERTSPLIT
720 if (flags & WSP_VERT)
721 {
Bram Moolenaara0485492014-07-16 23:39:54 +0200722 int wmw1;
723 int minwidth;
724
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 layout = FR_ROW;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726
727 /*
728 * Check if we are able to split the current window and compute its
729 * width.
730 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200731 /* Current window requires at least 1 space. */
732 wmw1 = (p_wmw == 0 ? 1 : p_wmw);
733 needed = wmw1 + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200735 needed += p_wiw - wmw1;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200736 if (flags & (WSP_BOT | WSP_TOP))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200738 minwidth = frame_minwidth(topframe, NOWIN);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 available = topframe->fr_width;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200740 needed += minwidth;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200742 else if (p_ea)
743 {
744 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
745 prevfrp = oldwin->w_frame;
746 for (frp = oldwin->w_frame->fr_parent; frp != NULL;
747 frp = frp->fr_parent)
748 {
749 if (frp->fr_layout == FR_ROW)
750 for (frp2 = frp->fr_child; frp2 != NULL;
751 frp2 = frp2->fr_next)
752 if (frp2 != prevfrp)
753 minwidth += frame_minwidth(frp2, NOWIN);
754 prevfrp = frp;
755 }
756 available = topframe->fr_width;
757 needed += minwidth;
758 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 else
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200760 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200761 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
762 available = oldwin->w_frame->fr_width;
763 needed += minwidth;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200764 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100765 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 {
767 EMSG(_(e_noroom));
768 return FAIL;
769 }
770 if (new_size == 0)
771 new_size = oldwin->w_width / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200772 if (new_size > available - minwidth - 1)
773 new_size = available - minwidth - 1;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200774 if (new_size < wmw1)
775 new_size = wmw1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776
777 /* if it doesn't fit in the current window, need win_equal() */
778 if (oldwin->w_width - new_size - 1 < p_wmw)
779 do_equal = TRUE;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +0000780
781 /* We don't like to take lines for the new window from a
782 * 'winfixwidth' window. Take them from a window to the left or right
783 * instead, if possible. */
784 if (oldwin->w_p_wfw)
785 win_setwidth_win(oldwin->w_width + new_size, oldwin);
Bram Moolenaar67f71312007-08-12 14:55:56 +0000786
787 /* Only make all windows the same width if one of them (except oldwin)
788 * is wider than one of the split windows. */
789 if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
790 && oldwin->w_frame->fr_parent != NULL)
791 {
792 frp = oldwin->w_frame->fr_parent->fr_child;
793 while (frp != NULL)
794 {
795 if (frp->fr_win != oldwin && frp->fr_win != NULL
796 && (frp->fr_win->w_width > new_size
797 || frp->fr_win->w_width > oldwin->w_width
798 - new_size - STATUS_HEIGHT))
799 {
800 do_equal = TRUE;
801 break;
802 }
803 frp = frp->fr_next;
804 }
805 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 }
807 else
808#endif
809 {
810 layout = FR_COL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811
812 /*
813 * Check if we are able to split the current window and compute its
814 * height.
815 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200816 /* Current window requires at least 1 space. */
817 wmh1 = (p_wmh == 0 ? 1 : p_wmh);
818 needed = wmh1 + STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200820 needed += p_wh - wmh1;
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 minheight = frame_minheight(topframe, NOWIN) + need_status;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 available = topframe->fr_height;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200825 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200827 else if (p_ea)
828 {
829 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
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_COL)
835 for (frp2 = frp->fr_child; frp2 != NULL;
836 frp2 = frp2->fr_next)
837 if (frp2 != prevfrp)
838 minheight += frame_minheight(frp2, NOWIN);
839 prevfrp = frp;
840 }
841 available = topframe->fr_height;
842 needed += minheight;
843 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 else
845 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200846 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
847 available = oldwin->w_frame->fr_height;
848 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100850 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 {
852 EMSG(_(e_noroom));
853 return FAIL;
854 }
855 oldwin_height = oldwin->w_height;
856 if (need_status)
857 {
858 oldwin->w_status_height = STATUS_HEIGHT;
859 oldwin_height -= STATUS_HEIGHT;
860 }
861 if (new_size == 0)
862 new_size = oldwin_height / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200863 if (new_size > available - minheight - STATUS_HEIGHT)
864 new_size = available - minheight - STATUS_HEIGHT;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200865 if (new_size < wmh1)
866 new_size = wmh1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867
868 /* if it doesn't fit in the current window, need win_equal() */
869 if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
870 do_equal = TRUE;
871
872 /* We don't like to take lines for the new window from a
873 * 'winfixheight' window. Take them from a window above or below
874 * instead, if possible. */
875 if (oldwin->w_p_wfh)
876 {
877 win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
878 oldwin);
879 oldwin_height = oldwin->w_height;
880 if (need_status)
881 oldwin_height -= STATUS_HEIGHT;
882 }
Bram Moolenaar67f71312007-08-12 14:55:56 +0000883
884 /* Only make all windows the same height if one of them (except oldwin)
885 * is higher than one of the split windows. */
886 if (!do_equal && p_ea && size == 0
887#ifdef FEAT_VERTSPLIT
888 && *p_ead != 'h'
889#endif
890 && oldwin->w_frame->fr_parent != NULL)
891 {
892 frp = oldwin->w_frame->fr_parent->fr_child;
893 while (frp != NULL)
894 {
895 if (frp->fr_win != oldwin && frp->fr_win != NULL
896 && (frp->fr_win->w_height > new_size
897 || frp->fr_win->w_height > oldwin_height - new_size
898 - STATUS_HEIGHT))
899 {
900 do_equal = TRUE;
901 break;
902 }
903 frp = frp->fr_next;
904 }
905 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 }
907
908 /*
909 * allocate new window structure and link it in the window list
910 */
911 if ((flags & WSP_TOP) == 0
912 && ((flags & WSP_BOT)
913 || (flags & WSP_BELOW)
914 || (!(flags & WSP_ABOVE)
915 && (
916#ifdef FEAT_VERTSPLIT
917 (flags & WSP_VERT) ? p_spr :
918#endif
919 p_sb))))
920 {
921 /* new window below/right of current one */
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100922 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000923 wp = win_alloc(oldwin, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 else
925 win_append(oldwin, wp);
926 }
927 else
928 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100929 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000930 wp = win_alloc(oldwin->w_prev, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 else
932 win_append(oldwin->w_prev, wp);
933 }
934
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100935 if (new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 {
937 if (wp == NULL)
938 return FAIL;
939
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000940 new_frame(wp);
941 if (wp->w_frame == NULL)
942 {
943 win_free(wp, NULL);
944 return FAIL;
945 }
946
Bram Moolenaar2a0449d2006-02-20 21:27:21 +0000947 /* make the contents of the new window the same as the current one */
Bram Moolenaar884ae642009-02-22 01:37:59 +0000948 win_init(wp, curwin, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949 }
950
951 /*
952 * Reorganise the tree of frames to insert the new window.
953 */
954 if (flags & (WSP_TOP | WSP_BOT))
955 {
956#ifdef FEAT_VERTSPLIT
957 if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
958 || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
959#else
960 if (topframe->fr_layout == FR_COL)
961#endif
962 {
963 curfrp = topframe->fr_child;
964 if (flags & WSP_BOT)
965 while (curfrp->fr_next != NULL)
966 curfrp = curfrp->fr_next;
967 }
968 else
969 curfrp = topframe;
970 before = (flags & WSP_TOP);
971 }
972 else
973 {
974 curfrp = oldwin->w_frame;
975 if (flags & WSP_BELOW)
976 before = FALSE;
977 else if (flags & WSP_ABOVE)
978 before = TRUE;
979 else
980#ifdef FEAT_VERTSPLIT
981 if (flags & WSP_VERT)
982 before = !p_spr;
983 else
984#endif
985 before = !p_sb;
986 }
987 if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
988 {
989 /* Need to create a new frame in the tree to make a branch. */
990 frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
991 *frp = *curfrp;
992 curfrp->fr_layout = layout;
993 frp->fr_parent = curfrp;
994 frp->fr_next = NULL;
995 frp->fr_prev = NULL;
996 curfrp->fr_child = frp;
997 curfrp->fr_win = NULL;
998 curfrp = frp;
999 if (frp->fr_win != NULL)
1000 oldwin->w_frame = frp;
1001 else
1002 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
1003 frp->fr_parent = curfrp;
1004 }
1005
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001006 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001007 frp = wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 else
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001009 frp = new_wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010 frp->fr_parent = curfrp->fr_parent;
1011
1012 /* Insert the new frame at the right place in the frame list. */
1013 if (before)
1014 frame_insert(curfrp, frp);
1015 else
1016 frame_append(curfrp, frp);
1017
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001018 /* Set w_fraction now so that the cursor keeps the same relative
1019 * vertical position. */
Bram Moolenaar13d831f2011-01-08 14:46:03 +01001020 if (oldwin->w_height > 0)
1021 set_fraction(oldwin);
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001022 wp->w_fraction = oldwin->w_fraction;
1023
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024#ifdef FEAT_VERTSPLIT
1025 if (flags & WSP_VERT)
1026 {
1027 wp->w_p_scr = curwin->w_p_scr;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001028
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 if (need_status)
1030 {
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001031 win_new_height(oldwin, oldwin->w_height - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032 oldwin->w_status_height = need_status;
1033 }
1034 if (flags & (WSP_TOP | WSP_BOT))
1035 {
1036 /* set height and row of new window to full height */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001037 wp->w_winrow = tabline_height();
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001038 win_new_height(wp, curfrp->fr_height - (p_ls > 0));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 wp->w_status_height = (p_ls > 0);
1040 }
1041 else
1042 {
1043 /* height and row of new window is same as current window */
1044 wp->w_winrow = oldwin->w_winrow;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001045 win_new_height(wp, oldwin->w_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 wp->w_status_height = oldwin->w_status_height;
1047 }
1048 frp->fr_height = curfrp->fr_height;
1049
1050 /* "new_size" of the current window goes to the new window, use
1051 * one column for the vertical separator */
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001052 win_new_width(wp, new_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 if (before)
1054 wp->w_vsep_width = 1;
1055 else
1056 {
1057 wp->w_vsep_width = oldwin->w_vsep_width;
1058 oldwin->w_vsep_width = 1;
1059 }
1060 if (flags & (WSP_TOP | WSP_BOT))
1061 {
1062 if (flags & WSP_BOT)
1063 frame_add_vsep(curfrp);
1064 /* Set width of neighbor frame */
1065 frame_new_width(curfrp, curfrp->fr_width
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001066 - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
1067 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 }
1069 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001070 win_new_width(oldwin, oldwin->w_width - (new_size + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 if (before) /* new window left of current one */
1072 {
1073 wp->w_wincol = oldwin->w_wincol;
1074 oldwin->w_wincol += new_size + 1;
1075 }
1076 else /* new window right of current one */
1077 wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
1078 frame_fix_width(oldwin);
1079 frame_fix_width(wp);
1080 }
1081 else
1082#endif
1083 {
1084 /* width and column of new window is same as current window */
1085#ifdef FEAT_VERTSPLIT
1086 if (flags & (WSP_TOP | WSP_BOT))
1087 {
1088 wp->w_wincol = 0;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001089 win_new_width(wp, Columns);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090 wp->w_vsep_width = 0;
1091 }
1092 else
1093 {
1094 wp->w_wincol = oldwin->w_wincol;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001095 win_new_width(wp, oldwin->w_width);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 wp->w_vsep_width = oldwin->w_vsep_width;
1097 }
1098 frp->fr_width = curfrp->fr_width;
1099#endif
1100
1101 /* "new_size" of the current window goes to the new window, use
1102 * one row for the status line */
1103 win_new_height(wp, new_size);
1104 if (flags & (WSP_TOP | WSP_BOT))
1105 frame_new_height(curfrp, curfrp->fr_height
1106 - (new_size + STATUS_HEIGHT), flags & WSP_TOP, FALSE);
1107 else
1108 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1109 if (before) /* new window above current one */
1110 {
1111 wp->w_winrow = oldwin->w_winrow;
1112 wp->w_status_height = STATUS_HEIGHT;
1113 oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
1114 }
1115 else /* new window below current one */
1116 {
1117 wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
1118 wp->w_status_height = oldwin->w_status_height;
1119 oldwin->w_status_height = STATUS_HEIGHT;
1120 }
1121#ifdef FEAT_VERTSPLIT
1122 if (flags & WSP_BOT)
1123 frame_add_statusline(curfrp);
1124#endif
1125 frame_fix_height(wp);
1126 frame_fix_height(oldwin);
1127 }
1128
1129 if (flags & (WSP_TOP | WSP_BOT))
1130 (void)win_comp_pos();
1131
1132 /*
1133 * Both windows need redrawing
1134 */
1135 redraw_win_later(wp, NOT_VALID);
1136 wp->w_redr_status = TRUE;
1137 redraw_win_later(oldwin, NOT_VALID);
1138 oldwin->w_redr_status = TRUE;
1139
1140 if (need_status)
1141 {
1142 msg_row = Rows - 1;
1143 msg_col = sc_col;
1144 msg_clr_eos_force(); /* Old command/ruler may still be there */
1145 comp_col();
1146 msg_row = Rows - 1;
1147 msg_col = 0; /* put position back at start of line */
1148 }
1149
1150 /*
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001151 * equalize the window sizes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 */
1153 if (do_equal || dir != 0)
1154 win_equal(wp, TRUE,
1155#ifdef FEAT_VERTSPLIT
1156 (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
1157 : dir == 'h' ? 'b' :
1158#endif
1159 'v');
1160
1161 /* Don't change the window height/width to 'winheight' / 'winwidth' if a
1162 * size was given. */
1163#ifdef FEAT_VERTSPLIT
1164 if (flags & WSP_VERT)
1165 {
1166 i = p_wiw;
1167 if (size != 0)
1168 p_wiw = size;
1169
1170# ifdef FEAT_GUI
1171 /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
1172 if (gui.in_use)
1173 gui_init_which_components(NULL);
1174# endif
1175 }
1176 else
1177#endif
1178 {
1179 i = p_wh;
1180 if (size != 0)
1181 p_wh = size;
1182 }
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001183
Bram Moolenaar23fb7a92014-07-30 14:05:00 +02001184#ifdef FEAT_JUMPLIST
1185 /* Keep same changelist position in new window. */
1186 wp->w_changelistidx = oldwin->w_changelistidx;
1187#endif
1188
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001189 /*
1190 * make the new window the current window
1191 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 win_enter(wp, FALSE);
1193#ifdef FEAT_VERTSPLIT
1194 if (flags & WSP_VERT)
1195 p_wiw = i;
1196 else
1197#endif
1198 p_wh = i;
1199
1200 return OK;
1201}
1202
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001203
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001204/*
1205 * Initialize window "newp" from window "oldp".
1206 * Used when splitting a window and when creating a new tab page.
1207 * The windows will both edit the same buffer.
Bram Moolenaar884ae642009-02-22 01:37:59 +00001208 * WSP_NEWLOC may be specified in flags to prevent the location list from
1209 * being copied.
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001210 */
1211 static void
Bram Moolenaar884ae642009-02-22 01:37:59 +00001212win_init(newp, oldp, flags)
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001213 win_T *newp;
1214 win_T *oldp;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001215 int flags UNUSED;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001216{
1217 int i;
1218
1219 newp->w_buffer = oldp->w_buffer;
Bram Moolenaar860cae12010-06-05 23:22:07 +02001220#ifdef FEAT_SYN_HL
Bram Moolenaarfd29f462010-06-06 16:11:09 +02001221 newp->w_s = &(oldp->w_buffer->b_s);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001222#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001223 oldp->w_buffer->b_nwindows++;
1224 newp->w_cursor = oldp->w_cursor;
1225 newp->w_valid = 0;
1226 newp->w_curswant = oldp->w_curswant;
1227 newp->w_set_curswant = oldp->w_set_curswant;
1228 newp->w_topline = oldp->w_topline;
1229#ifdef FEAT_DIFF
1230 newp->w_topfill = oldp->w_topfill;
1231#endif
1232 newp->w_leftcol = oldp->w_leftcol;
1233 newp->w_pcmark = oldp->w_pcmark;
1234 newp->w_prev_pcmark = oldp->w_prev_pcmark;
1235 newp->w_alt_fnum = oldp->w_alt_fnum;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00001236 newp->w_wrow = oldp->w_wrow;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001237 newp->w_fraction = oldp->w_fraction;
1238 newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
1239#ifdef FEAT_JUMPLIST
1240 copy_jumplist(oldp, newp);
1241#endif
1242#ifdef FEAT_QUICKFIX
Bram Moolenaar884ae642009-02-22 01:37:59 +00001243 if (flags & WSP_NEWLOC)
1244 {
1245 /* Don't copy the location list. */
1246 newp->w_llist = NULL;
1247 newp->w_llist_ref = NULL;
1248 }
1249 else
1250 copy_loclist(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001251#endif
Bram Moolenaarbd2dc342014-01-10 15:53:13 +01001252 newp->w_localdir = (oldp->w_localdir == NULL)
1253 ? NULL : vim_strsave(oldp->w_localdir);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001254
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001255 /* copy tagstack and folds */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001256 for (i = 0; i < oldp->w_tagstacklen; i++)
1257 {
1258 newp->w_tagstack[i] = oldp->w_tagstack[i];
1259 if (newp->w_tagstack[i].tagname != NULL)
1260 newp->w_tagstack[i].tagname =
1261 vim_strsave(newp->w_tagstack[i].tagname);
1262 }
1263 newp->w_tagstackidx = oldp->w_tagstackidx;
1264 newp->w_tagstacklen = oldp->w_tagstacklen;
Bram Moolenaara971b822011-09-14 14:43:25 +02001265#ifdef FEAT_FOLDING
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001266 copyFoldingState(oldp, newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001267#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001268
1269 win_init_some(newp, oldp);
Bram Moolenaar1a384422010-07-14 19:53:30 +02001270
Bram Moolenaara971b822011-09-14 14:43:25 +02001271#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02001272 check_colorcolumn(newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001273#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001274}
1275
1276/*
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02001277 * Initialize window "newp" from window "old".
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001278 * Only the essential things are copied.
1279 */
1280 static void
1281win_init_some(newp, oldp)
1282 win_T *newp;
1283 win_T *oldp;
1284{
1285 /* Use the same argument list. */
1286 newp->w_alist = oldp->w_alist;
1287 ++newp->w_alist->al_refcount;
1288 newp->w_arg_idx = oldp->w_arg_idx;
1289
1290 /* copy options from existing window */
1291 win_copy_options(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001292}
1293
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294#endif /* FEAT_WINDOWS */
1295
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296#if defined(FEAT_WINDOWS) || defined(PROTO)
1297/*
1298 * Check if "win" is a pointer to an existing window.
1299 */
1300 int
1301win_valid(win)
1302 win_T *win;
1303{
1304 win_T *wp;
1305
1306 if (win == NULL)
1307 return FALSE;
1308 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1309 if (wp == win)
1310 return TRUE;
1311 return FALSE;
1312}
1313
1314/*
1315 * Return the number of windows.
1316 */
1317 int
1318win_count()
1319{
1320 win_T *wp;
1321 int count = 0;
1322
1323 for (wp = firstwin; wp != NULL; wp = wp->w_next)
1324 ++count;
1325 return count;
1326}
1327
1328/*
1329 * Make "count" windows on the screen.
1330 * Return actual number of windows on the screen.
1331 * Must be called when there is just one window, filling the whole screen
1332 * (excluding the command line).
1333 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334 int
1335make_windows(count, vertical)
1336 int count;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00001337 int vertical UNUSED; /* split windows vertically if TRUE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001338{
1339 int maxcount;
1340 int todo;
1341
1342#ifdef FEAT_VERTSPLIT
1343 if (vertical)
1344 {
1345 /* Each windows needs at least 'winminwidth' lines and a separator
1346 * column. */
1347 maxcount = (curwin->w_width + curwin->w_vsep_width
1348 - (p_wiw - p_wmw)) / (p_wmw + 1);
1349 }
1350 else
1351#endif
1352 {
1353 /* Each window needs at least 'winminheight' lines and a status line. */
1354 maxcount = (curwin->w_height + curwin->w_status_height
1355 - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
1356 }
1357
1358 if (maxcount < 2)
1359 maxcount = 2;
1360 if (count > maxcount)
1361 count = maxcount;
1362
1363 /*
1364 * add status line now, otherwise first window will be too big
1365 */
1366 if (count > 1)
1367 last_status(TRUE);
1368
1369#ifdef FEAT_AUTOCMD
1370 /*
1371 * Don't execute autocommands while creating the windows. Must do that
1372 * when putting the buffers in the windows.
1373 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001374 block_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375#endif
1376
1377 /* todo is number of windows left to create */
1378 for (todo = count - 1; todo > 0; --todo)
1379#ifdef FEAT_VERTSPLIT
1380 if (vertical)
1381 {
1382 if (win_split(curwin->w_width - (curwin->w_width - todo)
1383 / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
1384 break;
1385 }
1386 else
1387#endif
1388 {
1389 if (win_split(curwin->w_height - (curwin->w_height - todo
1390 * STATUS_HEIGHT) / (todo + 1)
1391 - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
1392 break;
1393 }
1394
1395#ifdef FEAT_AUTOCMD
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001396 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397#endif
1398
1399 /* return actual number of windows */
1400 return (count - todo);
1401}
1402
1403/*
1404 * Exchange current and next window
1405 */
1406 static void
1407win_exchange(Prenum)
1408 long Prenum;
1409{
1410 frame_T *frp;
1411 frame_T *frp2;
1412 win_T *wp;
1413 win_T *wp2;
1414 int temp;
1415
1416 if (lastwin == firstwin) /* just one window */
1417 {
1418 beep_flush();
1419 return;
1420 }
1421
1422#ifdef FEAT_GUI
1423 need_mouse_correct = TRUE;
1424#endif
1425
1426 /*
1427 * find window to exchange with
1428 */
1429 if (Prenum)
1430 {
1431 frp = curwin->w_frame->fr_parent->fr_child;
1432 while (frp != NULL && --Prenum > 0)
1433 frp = frp->fr_next;
1434 }
1435 else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
1436 frp = curwin->w_frame->fr_next;
1437 else /* Swap last window in row/col with previous */
1438 frp = curwin->w_frame->fr_prev;
1439
1440 /* We can only exchange a window with another window, not with a frame
1441 * containing windows. */
1442 if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
1443 return;
1444 wp = frp->fr_win;
1445
1446/*
1447 * 1. remove curwin from the list. Remember after which window it was in wp2
1448 * 2. insert curwin before wp in the list
1449 * if wp != wp2
1450 * 3. remove wp from the list
1451 * 4. insert wp after wp2
1452 * 5. exchange the status line height and vsep width.
1453 */
1454 wp2 = curwin->w_prev;
1455 frp2 = curwin->w_frame->fr_prev;
1456 if (wp->w_prev != curwin)
1457 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001458 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001459 frame_remove(curwin->w_frame);
1460 win_append(wp->w_prev, curwin);
1461 frame_insert(frp, curwin->w_frame);
1462 }
1463 if (wp != wp2)
1464 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001465 win_remove(wp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466 frame_remove(wp->w_frame);
1467 win_append(wp2, wp);
1468 if (frp2 == NULL)
1469 frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
1470 else
1471 frame_append(frp2, wp->w_frame);
1472 }
1473 temp = curwin->w_status_height;
1474 curwin->w_status_height = wp->w_status_height;
1475 wp->w_status_height = temp;
1476#ifdef FEAT_VERTSPLIT
1477 temp = curwin->w_vsep_width;
1478 curwin->w_vsep_width = wp->w_vsep_width;
1479 wp->w_vsep_width = temp;
1480
1481 /* If the windows are not in the same frame, exchange the sizes to avoid
1482 * messing up the window layout. Otherwise fix the frame sizes. */
1483 if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
1484 {
1485 temp = curwin->w_height;
1486 curwin->w_height = wp->w_height;
1487 wp->w_height = temp;
1488 temp = curwin->w_width;
1489 curwin->w_width = wp->w_width;
1490 wp->w_width = temp;
1491 }
1492 else
1493 {
1494 frame_fix_height(curwin);
1495 frame_fix_height(wp);
1496 frame_fix_width(curwin);
1497 frame_fix_width(wp);
1498 }
1499#endif
1500
1501 (void)win_comp_pos(); /* recompute window positions */
1502
1503 win_enter(wp, TRUE);
1504 redraw_later(CLEAR);
1505}
1506
1507/*
1508 * rotate windows: if upwards TRUE the second window becomes the first one
1509 * if upwards FALSE the first window becomes the second one
1510 */
1511 static void
1512win_rotate(upwards, count)
1513 int upwards;
1514 int count;
1515{
1516 win_T *wp1;
1517 win_T *wp2;
1518 frame_T *frp;
1519 int n;
1520
1521 if (firstwin == lastwin) /* nothing to do */
1522 {
1523 beep_flush();
1524 return;
1525 }
1526
1527#ifdef FEAT_GUI
1528 need_mouse_correct = TRUE;
1529#endif
1530
1531#ifdef FEAT_VERTSPLIT
1532 /* Check if all frames in this row/col have one window. */
1533 for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
1534 frp = frp->fr_next)
1535 if (frp->fr_win == NULL)
1536 {
1537 EMSG(_("E443: Cannot rotate when another window is split"));
1538 return;
1539 }
1540#endif
1541
1542 while (count--)
1543 {
1544 if (upwards) /* first window becomes last window */
1545 {
1546 /* remove first window/frame from the list */
1547 frp = curwin->w_frame->fr_parent->fr_child;
1548 wp1 = frp->fr_win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001549 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 frame_remove(frp);
1551
1552 /* find last frame and append removed window/frame after it */
1553 for ( ; frp->fr_next != NULL; frp = frp->fr_next)
1554 ;
1555 win_append(frp->fr_win, wp1);
1556 frame_append(frp, wp1->w_frame);
1557
1558 wp2 = frp->fr_win; /* previously last window */
1559 }
1560 else /* last window becomes first window */
1561 {
1562 /* find last window/frame in the list and remove it */
1563 for (frp = curwin->w_frame; frp->fr_next != NULL;
1564 frp = frp->fr_next)
1565 ;
1566 wp1 = frp->fr_win;
1567 wp2 = wp1->w_prev; /* will become last window */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001568 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569 frame_remove(frp);
1570
1571 /* append the removed window/frame before the first in the list */
1572 win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
1573 frame_insert(frp->fr_parent->fr_child, frp);
1574 }
1575
1576 /* exchange status height and vsep width of old and new last window */
1577 n = wp2->w_status_height;
1578 wp2->w_status_height = wp1->w_status_height;
1579 wp1->w_status_height = n;
1580 frame_fix_height(wp1);
1581 frame_fix_height(wp2);
1582#ifdef FEAT_VERTSPLIT
1583 n = wp2->w_vsep_width;
1584 wp2->w_vsep_width = wp1->w_vsep_width;
1585 wp1->w_vsep_width = n;
1586 frame_fix_width(wp1);
1587 frame_fix_width(wp2);
1588#endif
1589
1590 /* recompute w_winrow and w_wincol for all windows */
1591 (void)win_comp_pos();
1592 }
1593
1594 redraw_later(CLEAR);
1595}
1596
1597/*
1598 * Move the current window to the very top/bottom/left/right of the screen.
1599 */
1600 static void
1601win_totop(size, flags)
1602 int size;
1603 int flags;
1604{
1605 int dir;
1606 int height = curwin->w_height;
1607
1608 if (lastwin == firstwin)
1609 {
1610 beep_flush();
1611 return;
1612 }
1613
1614 /* Remove the window and frame from the tree of frames. */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001615 (void)winframe_remove(curwin, &dir, NULL);
1616 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617 last_status(FALSE); /* may need to remove last status line */
1618 (void)win_comp_pos(); /* recompute window positions */
1619
1620 /* Split a window on the desired side and put the window there. */
1621 (void)win_split_ins(size, flags, curwin, dir);
1622 if (!(flags & WSP_VERT))
1623 {
1624 win_setheight(height);
1625 if (p_ea)
1626 win_equal(curwin, TRUE, 'v');
1627 }
1628
1629#if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
1630 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
1631 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001632 gui_may_update_scrollbars();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634}
1635
1636/*
1637 * Move window "win1" to below/right of "win2" and make "win1" the current
1638 * window. Only works within the same frame!
1639 */
1640 void
1641win_move_after(win1, win2)
1642 win_T *win1, *win2;
1643{
1644 int height;
1645
1646 /* check if the arguments are reasonable */
1647 if (win1 == win2)
1648 return;
1649
1650 /* check if there is something to do */
1651 if (win2->w_next != win1)
1652 {
1653 /* may need move the status line/vertical separator of the last window
1654 * */
1655 if (win1 == lastwin)
1656 {
1657 height = win1->w_prev->w_status_height;
1658 win1->w_prev->w_status_height = win1->w_status_height;
1659 win1->w_status_height = height;
1660#ifdef FEAT_VERTSPLIT
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001661 if (win1->w_prev->w_vsep_width == 1)
1662 {
1663 /* Remove the vertical separator from the last-but-one window,
1664 * add it to the last window. Adjust the frame widths. */
1665 win1->w_prev->w_vsep_width = 0;
1666 win1->w_prev->w_frame->fr_width -= 1;
1667 win1->w_vsep_width = 1;
1668 win1->w_frame->fr_width += 1;
1669 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670#endif
1671 }
1672 else if (win2 == lastwin)
1673 {
1674 height = win1->w_status_height;
1675 win1->w_status_height = win2->w_status_height;
1676 win2->w_status_height = height;
1677#ifdef FEAT_VERTSPLIT
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001678 if (win1->w_vsep_width == 1)
1679 {
1680 /* Remove the vertical separator from win1, add it to the last
1681 * window, win2. Adjust the frame widths. */
1682 win2->w_vsep_width = 1;
1683 win2->w_frame->fr_width += 1;
1684 win1->w_vsep_width = 0;
1685 win1->w_frame->fr_width -= 1;
1686 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001687#endif
1688 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00001689 win_remove(win1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690 frame_remove(win1->w_frame);
1691 win_append(win2, win1);
1692 frame_append(win2->w_frame, win1->w_frame);
1693
1694 (void)win_comp_pos(); /* recompute w_winrow for all windows */
1695 redraw_later(NOT_VALID);
1696 }
1697 win_enter(win1, FALSE);
1698}
1699
1700/*
1701 * Make all windows the same height.
1702 * 'next_curwin' will soon be the current window, make sure it has enough
1703 * rows.
1704 */
1705 void
1706win_equal(next_curwin, current, dir)
1707 win_T *next_curwin; /* pointer to current window to be or NULL */
1708 int current; /* do only frame with current window */
1709 int dir; /* 'v' for vertically, 'h' for horizontally,
1710 'b' for both, 0 for using p_ead */
1711{
1712 if (dir == 0)
1713#ifdef FEAT_VERTSPLIT
1714 dir = *p_ead;
1715#else
1716 dir = 'b';
1717#endif
1718 win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001719 topframe, dir, 0, tabline_height(),
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001720 (int)Columns, topframe->fr_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721}
1722
1723/*
1724 * Set a frame to a new position and height, spreading the available room
1725 * equally over contained frames.
1726 * The window "next_curwin" (if not NULL) should at least get the size from
1727 * 'winheight' and 'winwidth' if possible.
1728 */
1729 static void
1730win_equal_rec(next_curwin, current, topfr, dir, col, row, width, height)
1731 win_T *next_curwin; /* pointer to current window to be or NULL */
1732 int current; /* do only frame with current window */
1733 frame_T *topfr; /* frame to set size off */
1734 int dir; /* 'v', 'h' or 'b', see win_equal() */
1735 int col; /* horizontal position for frame */
1736 int row; /* vertical position for frame */
1737 int width; /* new width of frame */
1738 int height; /* new height of frame */
1739{
1740 int n, m;
1741 int extra_sep = 0;
1742 int wincount, totwincount = 0;
1743 frame_T *fr;
1744 int next_curwin_size = 0;
1745 int room = 0;
1746 int new_size;
1747 int has_next_curwin = 0;
1748 int hnc;
1749
1750 if (topfr->fr_layout == FR_LEAF)
1751 {
1752 /* Set the width/height of this frame.
1753 * Redraw when size or position changes */
1754 if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
1755#ifdef FEAT_VERTSPLIT
1756 || topfr->fr_width != width || topfr->fr_win->w_wincol != col
1757#endif
1758 )
1759 {
1760 topfr->fr_win->w_winrow = row;
1761 frame_new_height(topfr, height, FALSE, FALSE);
1762#ifdef FEAT_VERTSPLIT
1763 topfr->fr_win->w_wincol = col;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001764 frame_new_width(topfr, width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765#endif
1766 redraw_all_later(CLEAR);
1767 }
1768 }
1769#ifdef FEAT_VERTSPLIT
1770 else if (topfr->fr_layout == FR_ROW)
1771 {
1772 topfr->fr_width = width;
1773 topfr->fr_height = height;
1774
1775 if (dir != 'v') /* equalize frame widths */
1776 {
1777 /* Compute the maximum number of windows horizontally in this
1778 * frame. */
1779 n = frame_minwidth(topfr, NOWIN);
1780 /* add one for the rightmost window, it doesn't have a separator */
1781 if (col + width == Columns)
1782 extra_sep = 1;
1783 else
1784 extra_sep = 0;
1785 totwincount = (n + extra_sep) / (p_wmw + 1);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001786 has_next_curwin = frame_has_win(topfr, next_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001788 /*
1789 * Compute width for "next_curwin" window and room available for
1790 * other windows.
1791 * "m" is the minimal width when counting p_wiw for "next_curwin".
1792 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 m = frame_minwidth(topfr, next_curwin);
1794 room = width - m;
1795 if (room < 0)
1796 {
1797 next_curwin_size = p_wiw + room;
1798 room = 0;
1799 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800 else
1801 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001802 next_curwin_size = -1;
1803 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1804 {
1805 /* If 'winfixwidth' set keep the window width if
1806 * possible.
1807 * Watch out for this window being the next_curwin. */
1808 if (frame_fixed_width(fr))
1809 {
1810 n = frame_minwidth(fr, NOWIN);
1811 new_size = fr->fr_width;
1812 if (frame_has_win(fr, next_curwin))
1813 {
1814 room += p_wiw - p_wmw;
1815 next_curwin_size = 0;
1816 if (new_size < p_wiw)
1817 new_size = p_wiw;
1818 }
1819 else
1820 /* These windows don't use up room. */
1821 totwincount -= (n + (fr->fr_next == NULL
1822 ? extra_sep : 0)) / (p_wmw + 1);
1823 room -= new_size - n;
1824 if (room < 0)
1825 {
1826 new_size += room;
1827 room = 0;
1828 }
1829 fr->fr_newwidth = new_size;
1830 }
1831 }
1832 if (next_curwin_size == -1)
1833 {
1834 if (!has_next_curwin)
1835 next_curwin_size = 0;
1836 else if (totwincount > 1
1837 && (room + (totwincount - 2))
1838 / (totwincount - 1) > p_wiw)
1839 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001840 /* Can make all windows wider than 'winwidth', spread
1841 * the room equally. */
1842 next_curwin_size = (room + p_wiw
1843 + (totwincount - 1) * p_wmw
1844 + (totwincount - 1)) / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001845 room -= next_curwin_size - p_wiw;
1846 }
1847 else
1848 next_curwin_size = p_wiw;
1849 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001851
1852 if (has_next_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853 --totwincount; /* don't count curwin */
1854 }
1855
1856 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1857 {
1858 n = m = 0;
1859 wincount = 1;
1860 if (fr->fr_next == NULL)
1861 /* last frame gets all that remains (avoid roundoff error) */
1862 new_size = width;
1863 else if (dir == 'v')
1864 new_size = fr->fr_width;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001865 else if (frame_fixed_width(fr))
1866 {
1867 new_size = fr->fr_newwidth;
1868 wincount = 0; /* doesn't count as a sizeable window */
1869 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001870 else
1871 {
1872 /* Compute the maximum number of windows horiz. in "fr". */
1873 n = frame_minwidth(fr, NOWIN);
1874 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
1875 / (p_wmw + 1);
1876 m = frame_minwidth(fr, next_curwin);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001877 if (has_next_curwin)
1878 hnc = frame_has_win(fr, next_curwin);
1879 else
1880 hnc = FALSE;
1881 if (hnc) /* don't count next_curwin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882 --wincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001883 if (totwincount == 0)
1884 new_size = room;
1885 else
1886 new_size = (wincount * room + ((unsigned)totwincount >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001888 if (hnc) /* add next_curwin size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001889 {
1890 next_curwin_size -= p_wiw - (m - n);
1891 new_size += next_curwin_size;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001892 room -= new_size - next_curwin_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001894 else
1895 room -= new_size;
1896 new_size += n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 }
1898
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001899 /* Skip frame that is full width when splitting or closing a
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 * window, unless equalizing all frames. */
1901 if (!current || dir != 'v' || topfr->fr_parent != NULL
1902 || (new_size != fr->fr_width)
1903 || frame_has_win(fr, next_curwin))
1904 win_equal_rec(next_curwin, current, fr, dir, col, row,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001905 new_size, height);
1906 col += new_size;
1907 width -= new_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 totwincount -= wincount;
1909 }
1910 }
1911#endif
1912 else /* topfr->fr_layout == FR_COL */
1913 {
1914#ifdef FEAT_VERTSPLIT
1915 topfr->fr_width = width;
1916#endif
1917 topfr->fr_height = height;
1918
1919 if (dir != 'h') /* equalize frame heights */
1920 {
1921 /* Compute maximum number of windows vertically in this frame. */
1922 n = frame_minheight(topfr, NOWIN);
1923 /* add one for the bottom window if it doesn't have a statusline */
1924 if (row + height == cmdline_row && p_ls == 0)
1925 extra_sep = 1;
1926 else
1927 extra_sep = 0;
1928 totwincount = (n + extra_sep) / (p_wmh + 1);
1929 has_next_curwin = frame_has_win(topfr, next_curwin);
1930
1931 /*
1932 * Compute height for "next_curwin" window and room available for
1933 * other windows.
1934 * "m" is the minimal height when counting p_wh for "next_curwin".
1935 */
1936 m = frame_minheight(topfr, next_curwin);
1937 room = height - m;
1938 if (room < 0)
1939 {
1940 /* The room is less then 'winheight', use all space for the
1941 * current window. */
1942 next_curwin_size = p_wh + room;
1943 room = 0;
1944 }
1945 else
1946 {
1947 next_curwin_size = -1;
1948 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1949 {
1950 /* If 'winfixheight' set keep the window height if
1951 * possible.
1952 * Watch out for this window being the next_curwin. */
1953 if (frame_fixed_height(fr))
1954 {
1955 n = frame_minheight(fr, NOWIN);
1956 new_size = fr->fr_height;
1957 if (frame_has_win(fr, next_curwin))
1958 {
1959 room += p_wh - p_wmh;
1960 next_curwin_size = 0;
1961 if (new_size < p_wh)
1962 new_size = p_wh;
1963 }
1964 else
1965 /* These windows don't use up room. */
1966 totwincount -= (n + (fr->fr_next == NULL
1967 ? extra_sep : 0)) / (p_wmh + 1);
1968 room -= new_size - n;
1969 if (room < 0)
1970 {
1971 new_size += room;
1972 room = 0;
1973 }
1974 fr->fr_newheight = new_size;
1975 }
1976 }
1977 if (next_curwin_size == -1)
1978 {
1979 if (!has_next_curwin)
1980 next_curwin_size = 0;
1981 else if (totwincount > 1
1982 && (room + (totwincount - 2))
1983 / (totwincount - 1) > p_wh)
1984 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001985 /* can make all windows higher than 'winheight',
1986 * spread the room equally. */
1987 next_curwin_size = (room + p_wh
1988 + (totwincount - 1) * p_wmh
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989 + (totwincount - 1)) / totwincount;
1990 room -= next_curwin_size - p_wh;
1991 }
1992 else
1993 next_curwin_size = p_wh;
1994 }
1995 }
1996
1997 if (has_next_curwin)
1998 --totwincount; /* don't count curwin */
1999 }
2000
2001 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
2002 {
2003 n = m = 0;
2004 wincount = 1;
2005 if (fr->fr_next == NULL)
2006 /* last frame gets all that remains (avoid roundoff error) */
2007 new_size = height;
2008 else if (dir == 'h')
2009 new_size = fr->fr_height;
2010 else if (frame_fixed_height(fr))
2011 {
2012 new_size = fr->fr_newheight;
2013 wincount = 0; /* doesn't count as a sizeable window */
2014 }
2015 else
2016 {
2017 /* Compute the maximum number of windows vert. in "fr". */
2018 n = frame_minheight(fr, NOWIN);
2019 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
2020 / (p_wmh + 1);
2021 m = frame_minheight(fr, next_curwin);
2022 if (has_next_curwin)
2023 hnc = frame_has_win(fr, next_curwin);
2024 else
2025 hnc = FALSE;
2026 if (hnc) /* don't count next_curwin */
2027 --wincount;
2028 if (totwincount == 0)
2029 new_size = room;
2030 else
2031 new_size = (wincount * room + ((unsigned)totwincount >> 1))
2032 / totwincount;
2033 if (hnc) /* add next_curwin size */
2034 {
2035 next_curwin_size -= p_wh - (m - n);
2036 new_size += next_curwin_size;
2037 room -= new_size - next_curwin_size;
2038 }
2039 else
2040 room -= new_size;
2041 new_size += n;
2042 }
2043 /* Skip frame that is full width when splitting or closing a
2044 * window, unless equalizing all frames. */
2045 if (!current || dir != 'h' || topfr->fr_parent != NULL
2046 || (new_size != fr->fr_height)
2047 || frame_has_win(fr, next_curwin))
2048 win_equal_rec(next_curwin, current, fr, dir, col, row,
2049 width, new_size);
2050 row += new_size;
2051 height -= new_size;
2052 totwincount -= wincount;
2053 }
2054 }
2055}
2056
2057/*
2058 * close all windows for buffer 'buf'
2059 */
2060 void
Bram Moolenaarf740b292006-02-16 22:11:02 +00002061close_windows(buf, keep_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 buf_T *buf;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002063 int keep_curwin; /* don't close "curwin" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064{
Bram Moolenaarf740b292006-02-16 22:11:02 +00002065 win_T *wp;
2066 tabpage_T *tp, *nexttp;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002067 int h = tabline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068
2069 ++RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002070
2071 for (wp = firstwin; wp != NULL && lastwin != firstwin; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072 {
Bram Moolenaar362ce482012-06-06 19:02:45 +02002073 if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
2074#ifdef FEAT_AUTOCMD
2075 && !(wp->w_closing || wp->w_buffer->b_closing)
2076#endif
2077 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00002079 win_close(wp, FALSE);
2080
2081 /* Start all over, autocommands may change the window layout. */
2082 wp = firstwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 }
2084 else
Bram Moolenaarf740b292006-02-16 22:11:02 +00002085 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00002087
2088 /* Also check windows in other tab pages. */
2089 for (tp = first_tabpage; tp != NULL; tp = nexttp)
2090 {
2091 nexttp = tp->tp_next;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002092 if (tp != curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002093 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002094 if (wp->w_buffer == buf
2095#ifdef FEAT_AUTOCMD
2096 && !(wp->w_closing || wp->w_buffer->b_closing)
2097#endif
2098 )
Bram Moolenaarf740b292006-02-16 22:11:02 +00002099 {
2100 win_close_othertab(wp, FALSE, tp);
2101
2102 /* Start all over, the tab page may be closed and
2103 * autocommands may change the window layout. */
2104 nexttp = first_tabpage;
2105 break;
2106 }
2107 }
2108
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 --RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002110
Bram Moolenaar4c7e9db2013-04-15 15:55:19 +02002111 redraw_tabline = TRUE;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002112 if (h != tabline_height())
Bram Moolenaarf740b292006-02-16 22:11:02 +00002113 shell_new_rows();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114}
2115
2116/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002117 * Return TRUE if the current window is the only window that exists (ignoring
2118 * "aucmd_win").
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002119 * Returns FALSE if there is a window, possibly in another tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002120 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002121 static int
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002122last_window()
2123{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002124 return (one_window() && first_tabpage->tp_next == NULL);
2125}
2126
2127/*
2128 * Return TRUE if there is only one window other than "aucmd_win" in the
2129 * current tab page.
2130 */
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002131 int
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002132one_window()
2133{
2134#ifdef FEAT_AUTOCMD
2135 win_T *wp;
2136 int seen_one = FALSE;
2137
2138 FOR_ALL_WINDOWS(wp)
2139 {
2140 if (wp != aucmd_win)
2141 {
2142 if (seen_one)
2143 return FALSE;
2144 seen_one = TRUE;
2145 }
2146 }
2147 return TRUE;
2148#else
2149 return firstwin == lastwin;
2150#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002151}
2152
2153/*
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002154 * Close the possibly last window in a tab page.
2155 * Returns TRUE when the window was closed already.
2156 */
2157 static int
2158close_last_window_tabpage(win, free_buf, prev_curtab)
2159 win_T *win;
2160 int free_buf;
2161 tabpage_T *prev_curtab;
2162{
2163 if (firstwin == lastwin)
2164 {
Bram Moolenaar07729b22013-05-15 23:13:10 +02002165#ifdef FEAT_AUTOCMD
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002166 buf_T *old_curbuf = curbuf;
Bram Moolenaar07729b22013-05-15 23:13:10 +02002167#endif
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002168
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002169 /*
2170 * Closing the last window in a tab page. First go to another tab
2171 * page and then close the window and the tab page. This avoids that
2172 * curwin and curtab are invalid while we are freeing memory, they may
2173 * be used in GUI events.
Bram Moolenaara8596c42012-06-13 14:28:20 +02002174 * Don't trigger autocommands yet, they may use wrong values, so do
2175 * that below.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002176 */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002177 goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002178 redraw_tabline = TRUE;
2179
2180 /* Safety check: Autocommands may have closed the window when jumping
2181 * to the other tab page. */
2182 if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win)
2183 {
2184 int h = tabline_height();
2185
2186 win_close_othertab(win, free_buf, prev_curtab);
2187 if (h != tabline_height())
2188 shell_new_rows();
2189 }
Bram Moolenaara8596c42012-06-13 14:28:20 +02002190 /* Since goto_tabpage_tp above did not trigger *Enter autocommands, do
2191 * that now. */
2192#ifdef FEAT_AUTOCMD
Bram Moolenaara8596c42012-06-13 14:28:20 +02002193 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002194 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
2195 if (old_curbuf != curbuf)
2196 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaara8596c42012-06-13 14:28:20 +02002197#endif
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002198 return TRUE;
2199 }
2200 return FALSE;
2201}
2202
2203/*
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002204 * Close window "win". Only works for the current tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 * If "free_buf" is TRUE related buffer may be unloaded.
2206 *
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002207 * Called by :quit, :close, :xit, :wq and findtag().
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002208 * Returns FAIL when the window was not closed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209 */
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002210 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211win_close(win, free_buf)
2212 win_T *win;
2213 int free_buf;
2214{
2215 win_T *wp;
2216#ifdef FEAT_AUTOCMD
2217 int other_buffer = FALSE;
2218#endif
2219 int close_curwin = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220 int dir;
2221 int help_window = FALSE;
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002222 tabpage_T *prev_curtab = curtab;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002224 if (last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 {
2226 EMSG(_("E444: Cannot close last window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002227 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228 }
2229
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002230#ifdef FEAT_AUTOCMD
Bram Moolenaar756287d2012-07-06 16:39:47 +02002231 if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002232 return FAIL; /* window is already being closed */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002233 if (win == aucmd_win)
2234 {
2235 EMSG(_("E813: Cannot close autocmd window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002236 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002237 }
2238 if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
2239 {
2240 EMSG(_("E814: Cannot close window, only autocmd window would remain"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002241 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002242 }
2243#endif
2244
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002245 /* When closing the last window in a tab page first go to another tab page
2246 * and then close the window and the tab page to avoid that curwin and
2247 * curtab are invalid while we are freeing memory. */
2248 if (close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002249 return FAIL;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002250
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251 /* When closing the help window, try restoring a snapshot after closing
2252 * the window. Otherwise clear the snapshot, it's now invalid. */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002253 if (win->w_buffer != NULL && win->w_buffer->b_help)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 help_window = TRUE;
2255 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002256 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002257
2258#ifdef FEAT_AUTOCMD
2259 if (win == curwin)
2260 {
2261 /*
2262 * Guess which window is going to be the new current window.
2263 * This may change because of the autocommands (sigh).
2264 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002265 wp = frame2win(win_altframe(win, NULL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266
2267 /*
Bram Moolenaar362ce482012-06-06 19:02:45 +02002268 * Be careful: If autocommands delete the window or cause this window
2269 * to be the last one left, return now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 */
2271 if (wp->w_buffer != curbuf)
2272 {
2273 other_buffer = TRUE;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002274 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002276 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002277 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002278 win->w_closing = FALSE;
2279 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002280 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002281 }
Bram Moolenaar362ce482012-06-06 19:02:45 +02002282 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002284 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002285 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002286 win->w_closing = FALSE;
2287 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002288 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289# ifdef FEAT_EVAL
2290 /* autocmds may abort script processing */
2291 if (aborting())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002292 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293# endif
2294 }
2295#endif
2296
Bram Moolenaar053b9fa2007-04-26 14:09:42 +00002297#ifdef FEAT_GUI
2298 /* Avoid trouble with scrollbars that are going to be deleted in
2299 * win_free(). */
2300 if (gui.in_use)
2301 out_flush();
2302#endif
2303
Bram Moolenaara971b822011-09-14 14:43:25 +02002304#ifdef FEAT_SYN_HL
2305 /* Free independent synblock before the buffer is freed. */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002306 if (win->w_buffer != NULL)
2307 reset_synblock(win);
Bram Moolenaara971b822011-09-14 14:43:25 +02002308#endif
2309
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 /*
2311 * Close the link to the buffer.
2312 */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002313 if (win->w_buffer != NULL)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002314 {
2315#ifdef FEAT_AUTOCMD
2316 win->w_closing = TRUE;
2317#endif
Bram Moolenaar8f913992012-08-29 15:50:26 +02002318 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002319#ifdef FEAT_AUTOCMD
2320 if (win_valid(win))
2321 win->w_closing = FALSE;
2322#endif
2323 }
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002324
Bram Moolenaar802418d2013-01-17 14:00:11 +01002325 if (only_one_window() && win_valid(win) && win->w_buffer == NULL
2326 && (last_window() || curtab != prev_curtab
2327 || close_last_window_tabpage(win, free_buf, prev_curtab)))
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002328 {
2329 /* Autocommands have close all windows, quit now. Restore
2330 * curwin->w_buffer, otherwise writing viminfo may fail. */
2331 if (curwin->w_buffer == NULL)
2332 curwin->w_buffer = curbuf;
Bram Moolenaar802418d2013-01-17 14:00:11 +01002333 getout(0);
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002334 }
Bram Moolenaar802418d2013-01-17 14:00:11 +01002335
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 /* Autocommands may have closed the window already, or closed the only
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002337 * other window or moved to another tab page. */
Bram Moolenaar802418d2013-01-17 14:00:11 +01002338 else if (!win_valid(win) || last_window() || curtab != prev_curtab
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002339 || close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002340 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341
Bram Moolenaara971b822011-09-14 14:43:25 +02002342 /* Free the memory used for the window and get the window that received
2343 * the screen space. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002344 wp = win_free_mem(win, &dir, NULL);
2345
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 /* Make sure curwin isn't invalid. It can cause severe trouble when
2347 * printing an error message. For win_equal() curbuf needs to be valid
2348 * too. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002349 if (win == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 {
2351 curwin = wp;
2352#ifdef FEAT_QUICKFIX
2353 if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
2354 {
2355 /*
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002356 * If the cursor goes to the preview or the quickfix window, try
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357 * finding another window to go to.
2358 */
2359 for (;;)
2360 {
2361 if (wp->w_next == NULL)
2362 wp = firstwin;
2363 else
2364 wp = wp->w_next;
2365 if (wp == curwin)
2366 break;
2367 if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
2368 {
2369 curwin = wp;
2370 break;
2371 }
2372 }
2373 }
2374#endif
2375 curbuf = curwin->w_buffer;
2376 close_curwin = TRUE;
2377 }
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00002378 if (p_ea
2379#ifdef FEAT_VERTSPLIT
2380 && (*p_ead == 'b' || *p_ead == dir)
2381#endif
2382 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 win_equal(curwin, TRUE,
2384#ifdef FEAT_VERTSPLIT
2385 dir
2386#else
2387 0
2388#endif
2389 );
2390 else
2391 win_comp_pos();
2392 if (close_curwin)
2393 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002394 win_enter_ext(wp, FALSE, TRUE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395#ifdef FEAT_AUTOCMD
2396 if (other_buffer)
2397 /* careful: after this wp and win may be invalid! */
2398 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
2399#endif
2400 }
2401
2402 /*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002403 * If last window has a status line now and we don't want one,
2404 * remove the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 */
2406 last_status(FALSE);
2407
2408 /* After closing the help window, try restoring the window layout from
2409 * before it was opened. */
2410 if (help_window)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002411 restore_snapshot(SNAP_HELP_IDX, close_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412
2413#if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
2414 /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
2415 if (gui.in_use && !win_hasvertsplit())
2416 gui_init_which_components(NULL);
2417#endif
2418
2419 redraw_all_later(NOT_VALID);
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002420 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421}
2422
2423/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002424 * Close window "win" in tab page "tp", which is not the current tab page.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002425 * This may be the last window in that tab page and result in closing the tab,
Bram Moolenaarf740b292006-02-16 22:11:02 +00002426 * thus "tp" may become invalid!
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002427 * Caller must check if buffer is hidden and whether the tabline needs to be
2428 * updated.
Bram Moolenaarf740b292006-02-16 22:11:02 +00002429 */
2430 void
2431win_close_othertab(win, free_buf, tp)
2432 win_T *win;
2433 int free_buf;
2434 tabpage_T *tp;
2435{
2436 win_T *wp;
2437 int dir;
2438 tabpage_T *ptp = NULL;
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002439 int free_tp = FALSE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002440
Bram Moolenaar362ce482012-06-06 19:02:45 +02002441#ifdef FEAT_AUTOCMD
2442 if (win->w_closing || win->w_buffer->b_closing)
2443 return; /* window is already being closed */
2444#endif
2445
Bram Moolenaarf740b292006-02-16 22:11:02 +00002446 /* Close the link to the buffer. */
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002447 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002448
2449 /* Careful: Autocommands may have closed the tab page or made it the
2450 * current tab page. */
2451 for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
2452 ;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002453 if (ptp == NULL || tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002454 return;
2455
2456 /* Autocommands may have closed the window already. */
2457 for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
2458 ;
2459 if (wp == NULL)
2460 return;
2461
Bram Moolenaarf740b292006-02-16 22:11:02 +00002462 /* When closing the last window in a tab page remove the tab page. */
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002463 if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002464 {
2465 if (tp == first_tabpage)
2466 first_tabpage = tp->tp_next;
2467 else
2468 {
2469 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
2470 ptp = ptp->tp_next)
2471 ;
2472 if (ptp == NULL)
2473 {
2474 EMSG2(_(e_intern2), "win_close_othertab()");
2475 return;
2476 }
2477 ptp->tp_next = tp->tp_next;
2478 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002479 free_tp = TRUE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002480 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002481
2482 /* Free the memory used for the window. */
2483 win_free_mem(win, &dir, tp);
2484
2485 if (free_tp)
2486 free_tabpage(tp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002487}
2488
2489/*
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002490 * Free the memory used for a window.
2491 * Returns a pointer to the window that got the freed up space.
2492 */
2493 static win_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002494win_free_mem(win, dirp, tp)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002495 win_T *win;
2496 int *dirp; /* set to 'v' or 'h' for direction if 'ea' */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002497 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002498{
2499 frame_T *frp;
2500 win_T *wp;
2501
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002502 /* Remove the window and its frame from the tree of frames. */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002503 frp = win->w_frame;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002504 wp = winframe_remove(win, dirp, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002505 vim_free(frp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002506 win_free(win, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002507
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002508 /* When deleting the current window of another tab page select a new
2509 * current window. */
2510 if (tp != NULL && win == tp->tp_curwin)
2511 tp->tp_curwin = wp;
2512
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002513 return wp;
2514}
2515
2516#if defined(EXITFREE) || defined(PROTO)
2517 void
2518win_free_all()
2519{
2520 int dummy;
2521
Bram Moolenaarf740b292006-02-16 22:11:02 +00002522# ifdef FEAT_WINDOWS
2523 while (first_tabpage->tp_next != NULL)
2524 tabpage_close(TRUE);
2525# endif
2526
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002527# ifdef FEAT_AUTOCMD
2528 if (aucmd_win != NULL)
2529 {
2530 (void)win_free_mem(aucmd_win, &dummy, NULL);
2531 aucmd_win = NULL;
2532 }
2533# endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00002534
2535 while (firstwin != NULL)
2536 (void)win_free_mem(firstwin, &dummy, NULL);
Bram Moolenaar4e036c92014-07-16 16:30:28 +02002537
2538 /* No window should be used after this. Set curwin to NULL to crash
2539 * instead of using freed memory. */
2540 curwin = NULL;
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002541}
2542#endif
2543
2544/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 * Remove a window and its frame from the tree of frames.
2546 * Returns a pointer to the window that got the freed up space.
2547 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002548 win_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002549winframe_remove(win, dirp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 win_T *win;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00002551 int *dirp UNUSED; /* set to 'v' or 'h' for direction if 'ea' */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002552 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553{
2554 frame_T *frp, *frp2, *frp3;
2555 frame_T *frp_close = win->w_frame;
2556 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557
2558 /*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002559 * If there is only one window there is nothing to remove.
2560 */
2561 if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
2562 return NULL;
2563
2564 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565 * Remove the window from its frame.
2566 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002567 frp2 = win_altframe(win, tp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 wp = frame2win(frp2);
2569
2570 /* Remove this frame from the list of frames. */
2571 frame_remove(frp_close);
2572
2573#ifdef FEAT_VERTSPLIT
2574 if (frp_close->fr_parent->fr_layout == FR_COL)
2575 {
2576#endif
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002577 /* When 'winfixheight' is set, try to find another frame in the column
2578 * (as close to the closed frame as possible) to distribute the height
2579 * to. */
2580 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
2581 {
2582 frp = frp_close->fr_prev;
2583 frp3 = frp_close->fr_next;
2584 while (frp != NULL || frp3 != NULL)
2585 {
2586 if (frp != NULL)
2587 {
2588 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh)
2589 {
2590 frp2 = frp;
2591 wp = frp->fr_win;
2592 break;
2593 }
2594 frp = frp->fr_prev;
2595 }
2596 if (frp3 != NULL)
2597 {
2598 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
2599 {
2600 frp2 = frp3;
2601 wp = frp3->fr_win;
2602 break;
2603 }
2604 frp3 = frp3->fr_next;
2605 }
2606 }
2607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
2609 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610#ifdef FEAT_VERTSPLIT
2611 *dirp = 'v';
2612 }
2613 else
2614 {
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002615 /* When 'winfixwidth' is set, try to find another frame in the column
2616 * (as close to the closed frame as possible) to distribute the width
2617 * to. */
2618 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
2619 {
2620 frp = frp_close->fr_prev;
2621 frp3 = frp_close->fr_next;
2622 while (frp != NULL || frp3 != NULL)
2623 {
2624 if (frp != NULL)
2625 {
2626 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw)
2627 {
2628 frp2 = frp;
2629 wp = frp->fr_win;
2630 break;
2631 }
2632 frp = frp->fr_prev;
2633 }
2634 if (frp3 != NULL)
2635 {
2636 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
2637 {
2638 frp2 = frp3;
2639 wp = frp3->fr_win;
2640 break;
2641 }
2642 frp3 = frp3->fr_next;
2643 }
2644 }
2645 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002647 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648 *dirp = 'h';
2649 }
2650#endif
2651
2652 /* If rows/columns go to a window below/right its positions need to be
2653 * updated. Can only be done after the sizes have been updated. */
2654 if (frp2 == frp_close->fr_next)
2655 {
2656 int row = win->w_winrow;
2657 int col = W_WINCOL(win);
2658
2659 frame_comp_pos(frp2, &row, &col);
2660 }
2661
2662 if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
2663 {
2664 /* There is no other frame in this list, move its info to the parent
2665 * and remove it. */
2666 frp2->fr_parent->fr_layout = frp2->fr_layout;
2667 frp2->fr_parent->fr_child = frp2->fr_child;
2668 for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
2669 frp->fr_parent = frp2->fr_parent;
2670 frp2->fr_parent->fr_win = frp2->fr_win;
2671 if (frp2->fr_win != NULL)
2672 frp2->fr_win->w_frame = frp2->fr_parent;
2673 frp = frp2->fr_parent;
2674 vim_free(frp2);
2675
2676 frp2 = frp->fr_parent;
2677 if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
2678 {
2679 /* The frame above the parent has the same layout, have to merge
2680 * the frames into this list. */
2681 if (frp2->fr_child == frp)
2682 frp2->fr_child = frp->fr_child;
2683 frp->fr_child->fr_prev = frp->fr_prev;
2684 if (frp->fr_prev != NULL)
2685 frp->fr_prev->fr_next = frp->fr_child;
2686 for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
2687 {
2688 frp3->fr_parent = frp2;
2689 if (frp3->fr_next == NULL)
2690 {
2691 frp3->fr_next = frp->fr_next;
2692 if (frp->fr_next != NULL)
2693 frp->fr_next->fr_prev = frp3;
2694 break;
2695 }
2696 }
2697 vim_free(frp);
2698 }
2699 }
2700
2701 return wp;
2702}
2703
2704/*
2705 * Find out which frame is going to get the freed up space when "win" is
2706 * closed.
2707 * if 'splitbelow'/'splitleft' the space goes to the window above/left.
2708 * if 'nosplitbelow'/'nosplitleft' the space goes to the window below/right.
2709 * This makes opening a window and closing it immediately keep the same window
2710 * layout.
2711 */
2712 static frame_T *
Bram Moolenaarf740b292006-02-16 22:11:02 +00002713win_altframe(win, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002714 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002715 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716{
2717 frame_T *frp;
2718 int b;
2719
Bram Moolenaarf740b292006-02-16 22:11:02 +00002720 if (tp == NULL ? firstwin == lastwin : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002721 /* Last window in this tab page, will go to next tab page. */
2722 return alt_tabpage()->tp_curwin->w_frame;
2723
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 frp = win->w_frame;
2725#ifdef FEAT_VERTSPLIT
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002726 if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 b = p_spr;
2728 else
2729#endif
2730 b = p_sb;
2731 if ((!b && frp->fr_next != NULL) || frp->fr_prev == NULL)
2732 return frp->fr_next;
2733 return frp->fr_prev;
2734}
2735
2736/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002737 * Return the tabpage that will be used if the current one is closed.
2738 */
2739 static tabpage_T *
2740alt_tabpage()
2741{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002742 tabpage_T *tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002743
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002744 /* Use the next tab page if possible. */
2745 if (curtab->tp_next != NULL)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002746 return curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002747
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002748 /* Find the last but one tab page. */
2749 for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
2750 ;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002751 return tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002752}
2753
2754/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 * Find the left-upper window in frame "frp".
2756 */
2757 static win_T *
2758frame2win(frp)
2759 frame_T *frp;
2760{
2761 while (frp->fr_win == NULL)
2762 frp = frp->fr_child;
2763 return frp->fr_win;
2764}
2765
2766/*
2767 * Return TRUE if frame "frp" contains window "wp".
2768 */
2769 static int
2770frame_has_win(frp, wp)
2771 frame_T *frp;
2772 win_T *wp;
2773{
2774 frame_T *p;
2775
2776 if (frp->fr_layout == FR_LEAF)
2777 return frp->fr_win == wp;
2778
2779 for (p = frp->fr_child; p != NULL; p = p->fr_next)
2780 if (frame_has_win(p, wp))
2781 return TRUE;
2782 return FALSE;
2783}
2784
2785/*
2786 * Set a new height for a frame. Recursively sets the height for contained
2787 * frames and windows. Caller must take care of positions.
2788 */
2789 static void
2790frame_new_height(topfrp, height, topfirst, wfh)
2791 frame_T *topfrp;
2792 int height;
2793 int topfirst; /* resize topmost contained frame first */
2794 int wfh; /* obey 'winfixheight' when there is a choice;
2795 may cause the height not to be set */
2796{
2797 frame_T *frp;
2798 int extra_lines;
2799 int h;
2800
2801 if (topfrp->fr_win != NULL)
2802 {
2803 /* Simple case: just one window. */
2804 win_new_height(topfrp->fr_win,
2805 height - topfrp->fr_win->w_status_height);
2806 }
2807#ifdef FEAT_VERTSPLIT
2808 else if (topfrp->fr_layout == FR_ROW)
2809 {
2810 do
2811 {
2812 /* All frames in this row get the same new height. */
2813 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2814 {
2815 frame_new_height(frp, height, topfirst, wfh);
2816 if (frp->fr_height > height)
2817 {
2818 /* Could not fit the windows, make the whole row higher. */
2819 height = frp->fr_height;
2820 break;
2821 }
2822 }
2823 }
2824 while (frp != NULL);
2825 }
2826#endif
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002827 else /* fr_layout == FR_COL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 {
2829 /* Complicated case: Resize a column of frames. Resize the bottom
2830 * frame first, frames above that when needed. */
2831
2832 frp = topfrp->fr_child;
2833 if (wfh)
2834 /* Advance past frames with one window with 'wfh' set. */
2835 while (frame_fixed_height(frp))
2836 {
2837 frp = frp->fr_next;
2838 if (frp == NULL)
2839 return; /* no frame without 'wfh', give up */
2840 }
2841 if (!topfirst)
2842 {
2843 /* Find the bottom frame of this column */
2844 while (frp->fr_next != NULL)
2845 frp = frp->fr_next;
2846 if (wfh)
2847 /* Advance back for frames with one window with 'wfh' set. */
2848 while (frame_fixed_height(frp))
2849 frp = frp->fr_prev;
2850 }
2851
2852 extra_lines = height - topfrp->fr_height;
2853 if (extra_lines < 0)
2854 {
2855 /* reduce height of contained frames, bottom or top frame first */
2856 while (frp != NULL)
2857 {
2858 h = frame_minheight(frp, NULL);
2859 if (frp->fr_height + extra_lines < h)
2860 {
2861 extra_lines += frp->fr_height - h;
2862 frame_new_height(frp, h, topfirst, wfh);
2863 }
2864 else
2865 {
2866 frame_new_height(frp, frp->fr_height + extra_lines,
2867 topfirst, wfh);
2868 break;
2869 }
2870 if (topfirst)
2871 {
2872 do
2873 frp = frp->fr_next;
2874 while (wfh && frp != NULL && frame_fixed_height(frp));
2875 }
2876 else
2877 {
2878 do
2879 frp = frp->fr_prev;
2880 while (wfh && frp != NULL && frame_fixed_height(frp));
2881 }
2882 /* Increase "height" if we could not reduce enough frames. */
2883 if (frp == NULL)
2884 height -= extra_lines;
2885 }
2886 }
2887 else if (extra_lines > 0)
2888 {
2889 /* increase height of bottom or top frame */
2890 frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
2891 }
2892 }
2893 topfrp->fr_height = height;
2894}
2895
2896/*
2897 * Return TRUE if height of frame "frp" should not be changed because of
2898 * the 'winfixheight' option.
2899 */
2900 static int
2901frame_fixed_height(frp)
2902 frame_T *frp;
2903{
2904 /* frame with one window: fixed height if 'winfixheight' set. */
2905 if (frp->fr_win != NULL)
2906 return frp->fr_win->w_p_wfh;
2907
2908 if (frp->fr_layout == FR_ROW)
2909 {
2910 /* The frame is fixed height if one of the frames in the row is fixed
2911 * height. */
2912 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2913 if (frame_fixed_height(frp))
2914 return TRUE;
2915 return FALSE;
2916 }
2917
2918 /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
2919 * frames in the row are fixed height. */
2920 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2921 if (!frame_fixed_height(frp))
2922 return FALSE;
2923 return TRUE;
2924}
2925
2926#ifdef FEAT_VERTSPLIT
2927/*
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002928 * Return TRUE if width of frame "frp" should not be changed because of
2929 * the 'winfixwidth' option.
2930 */
2931 static int
2932frame_fixed_width(frp)
2933 frame_T *frp;
2934{
2935 /* frame with one window: fixed width if 'winfixwidth' set. */
2936 if (frp->fr_win != NULL)
2937 return frp->fr_win->w_p_wfw;
2938
2939 if (frp->fr_layout == FR_COL)
2940 {
2941 /* The frame is fixed width if one of the frames in the row is fixed
2942 * width. */
2943 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2944 if (frame_fixed_width(frp))
2945 return TRUE;
2946 return FALSE;
2947 }
2948
2949 /* frp->fr_layout == FR_ROW: The frame is fixed width if all of the
2950 * frames in the row are fixed width. */
2951 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2952 if (!frame_fixed_width(frp))
2953 return FALSE;
2954 return TRUE;
2955}
2956
2957/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002958 * Add a status line to windows at the bottom of "frp".
2959 * Note: Does not check if there is room!
2960 */
2961 static void
2962frame_add_statusline(frp)
2963 frame_T *frp;
2964{
2965 win_T *wp;
2966
2967 if (frp->fr_layout == FR_LEAF)
2968 {
2969 wp = frp->fr_win;
2970 if (wp->w_status_height == 0)
2971 {
2972 if (wp->w_height > 0) /* don't make it negative */
2973 --wp->w_height;
2974 wp->w_status_height = STATUS_HEIGHT;
2975 }
2976 }
2977 else if (frp->fr_layout == FR_ROW)
2978 {
2979 /* Handle all the frames in the row. */
2980 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
2981 frame_add_statusline(frp);
2982 }
2983 else /* frp->fr_layout == FR_COL */
2984 {
2985 /* Only need to handle the last frame in the column. */
2986 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
2987 ;
2988 frame_add_statusline(frp);
2989 }
2990}
2991
2992/*
2993 * Set width of a frame. Handles recursively going through contained frames.
2994 * May remove separator line for windows at the right side (for win_close()).
2995 */
2996 static void
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002997frame_new_width(topfrp, width, leftfirst, wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 frame_T *topfrp;
2999 int width;
3000 int leftfirst; /* resize leftmost contained frame first */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003001 int wfw; /* obey 'winfixwidth' when there is a choice;
3002 may cause the width not to be set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003{
3004 frame_T *frp;
3005 int extra_cols;
3006 int w;
3007 win_T *wp;
3008
3009 if (topfrp->fr_layout == FR_LEAF)
3010 {
3011 /* Simple case: just one window. */
3012 wp = topfrp->fr_win;
3013 /* Find out if there are any windows right of this one. */
3014 for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
3015 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
3016 break;
3017 if (frp->fr_parent == NULL)
3018 wp->w_vsep_width = 0;
3019 win_new_width(wp, width - wp->w_vsep_width);
3020 }
3021 else if (topfrp->fr_layout == FR_COL)
3022 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003023 do
3024 {
3025 /* All frames in this column get the same new width. */
3026 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3027 {
3028 frame_new_width(frp, width, leftfirst, wfw);
3029 if (frp->fr_width > width)
3030 {
3031 /* Could not fit the windows, make whole column wider. */
3032 width = frp->fr_width;
3033 break;
3034 }
3035 }
3036 } while (frp != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037 }
3038 else /* fr_layout == FR_ROW */
3039 {
3040 /* Complicated case: Resize a row of frames. Resize the rightmost
3041 * frame first, frames left of it when needed. */
3042
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043 frp = topfrp->fr_child;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003044 if (wfw)
3045 /* Advance past frames with one window with 'wfw' set. */
3046 while (frame_fixed_width(frp))
3047 {
3048 frp = frp->fr_next;
3049 if (frp == NULL)
3050 return; /* no frame without 'wfw', give up */
3051 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052 if (!leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003053 {
3054 /* Find the rightmost frame of this row */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 while (frp->fr_next != NULL)
3056 frp = frp->fr_next;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003057 if (wfw)
3058 /* Advance back for frames with one window with 'wfw' set. */
3059 while (frame_fixed_width(frp))
3060 frp = frp->fr_prev;
3061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062
3063 extra_cols = width - topfrp->fr_width;
3064 if (extra_cols < 0)
3065 {
3066 /* reduce frame width, rightmost frame first */
3067 while (frp != NULL)
3068 {
3069 w = frame_minwidth(frp, NULL);
3070 if (frp->fr_width + extra_cols < w)
3071 {
3072 extra_cols += frp->fr_width - w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003073 frame_new_width(frp, w, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 }
3075 else
3076 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003077 frame_new_width(frp, frp->fr_width + extra_cols,
3078 leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079 break;
3080 }
3081 if (leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003082 {
3083 do
3084 frp = frp->fr_next;
3085 while (wfw && frp != NULL && frame_fixed_width(frp));
3086 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003088 {
3089 do
3090 frp = frp->fr_prev;
3091 while (wfw && frp != NULL && frame_fixed_width(frp));
3092 }
3093 /* Increase "width" if we could not reduce enough frames. */
3094 if (frp == NULL)
3095 width -= extra_cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096 }
3097 }
3098 else if (extra_cols > 0)
3099 {
3100 /* increase width of rightmost frame */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003101 frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 }
3103 }
3104 topfrp->fr_width = width;
3105}
3106
3107/*
3108 * Add the vertical separator to windows at the right side of "frp".
3109 * Note: Does not check if there is room!
3110 */
3111 static void
3112frame_add_vsep(frp)
3113 frame_T *frp;
3114{
3115 win_T *wp;
3116
3117 if (frp->fr_layout == FR_LEAF)
3118 {
3119 wp = frp->fr_win;
3120 if (wp->w_vsep_width == 0)
3121 {
3122 if (wp->w_width > 0) /* don't make it negative */
3123 --wp->w_width;
3124 wp->w_vsep_width = 1;
3125 }
3126 }
3127 else if (frp->fr_layout == FR_COL)
3128 {
3129 /* Handle all the frames in the column. */
3130 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3131 frame_add_vsep(frp);
3132 }
3133 else /* frp->fr_layout == FR_ROW */
3134 {
3135 /* Only need to handle the last frame in the row. */
3136 frp = frp->fr_child;
3137 while (frp->fr_next != NULL)
3138 frp = frp->fr_next;
3139 frame_add_vsep(frp);
3140 }
3141}
3142
3143/*
3144 * Set frame width from the window it contains.
3145 */
3146 static void
3147frame_fix_width(wp)
3148 win_T *wp;
3149{
3150 wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
3151}
3152#endif
3153
3154/*
3155 * Set frame height from the window it contains.
3156 */
3157 static void
3158frame_fix_height(wp)
3159 win_T *wp;
3160{
3161 wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
3162}
3163
3164/*
3165 * Compute the minimal height for frame "topfrp".
3166 * Uses the 'winminheight' option.
3167 * When "next_curwin" isn't NULL, use p_wh for this window.
3168 * When "next_curwin" is NOWIN, don't use at least one line for the current
3169 * window.
3170 */
3171 static int
3172frame_minheight(topfrp, next_curwin)
3173 frame_T *topfrp;
3174 win_T *next_curwin;
3175{
3176 frame_T *frp;
3177 int m;
3178#ifdef FEAT_VERTSPLIT
3179 int n;
3180#endif
3181
3182 if (topfrp->fr_win != NULL)
3183 {
3184 if (topfrp->fr_win == next_curwin)
3185 m = p_wh + topfrp->fr_win->w_status_height;
3186 else
3187 {
3188 /* window: minimal height of the window plus status line */
3189 m = p_wmh + topfrp->fr_win->w_status_height;
3190 /* Current window is minimal one line high */
3191 if (p_wmh == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
3192 ++m;
3193 }
3194 }
3195#ifdef FEAT_VERTSPLIT
3196 else if (topfrp->fr_layout == FR_ROW)
3197 {
3198 /* get the minimal height from each frame in this row */
3199 m = 0;
3200 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3201 {
3202 n = frame_minheight(frp, next_curwin);
3203 if (n > m)
3204 m = n;
3205 }
3206 }
3207#endif
3208 else
3209 {
3210 /* Add up the minimal heights for all frames in this column. */
3211 m = 0;
3212 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3213 m += frame_minheight(frp, next_curwin);
3214 }
3215
3216 return m;
3217}
3218
3219#ifdef FEAT_VERTSPLIT
3220/*
3221 * Compute the minimal width for frame "topfrp".
3222 * When "next_curwin" isn't NULL, use p_wiw for this window.
3223 * When "next_curwin" is NOWIN, don't use at least one column for the current
3224 * window.
3225 */
3226 static int
3227frame_minwidth(topfrp, next_curwin)
3228 frame_T *topfrp;
3229 win_T *next_curwin; /* use p_wh and p_wiw for next_curwin */
3230{
3231 frame_T *frp;
3232 int m, n;
3233
3234 if (topfrp->fr_win != NULL)
3235 {
3236 if (topfrp->fr_win == next_curwin)
3237 m = p_wiw + topfrp->fr_win->w_vsep_width;
3238 else
3239 {
3240 /* window: minimal width of the window plus separator column */
3241 m = p_wmw + topfrp->fr_win->w_vsep_width;
3242 /* Current window is minimal one column wide */
3243 if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
3244 ++m;
3245 }
3246 }
3247 else if (topfrp->fr_layout == FR_COL)
3248 {
3249 /* get the minimal width from each frame in this column */
3250 m = 0;
3251 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3252 {
3253 n = frame_minwidth(frp, next_curwin);
3254 if (n > m)
3255 m = n;
3256 }
3257 }
3258 else
3259 {
3260 /* Add up the minimal widths for all frames in this row. */
3261 m = 0;
3262 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3263 m += frame_minwidth(frp, next_curwin);
3264 }
3265
3266 return m;
3267}
3268#endif
3269
3270
3271/*
3272 * Try to close all windows except current one.
3273 * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
3274 * used and the buffer was modified.
3275 *
3276 * Used by ":bdel" and ":only".
3277 */
3278 void
3279close_others(message, forceit)
3280 int message;
3281 int forceit; /* always hide all other windows */
3282{
3283 win_T *wp;
3284 win_T *nextwp;
3285 int r;
3286
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003287 if (one_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 {
3289 if (message
3290#ifdef FEAT_AUTOCMD
3291 && !autocmd_busy
3292#endif
3293 )
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00003294 MSG(_(m_onlyone));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 return;
3296 }
3297
3298 /* Be very careful here: autocommands may change the window layout. */
3299 for (wp = firstwin; win_valid(wp); wp = nextwp)
3300 {
3301 nextwp = wp->w_next;
3302 if (wp != curwin) /* don't close current window */
3303 {
3304
3305 /* Check if it's allowed to abandon this window */
3306 r = can_abandon(wp->w_buffer, forceit);
3307#ifdef FEAT_AUTOCMD
3308 if (!win_valid(wp)) /* autocommands messed wp up */
3309 {
3310 nextwp = firstwin;
3311 continue;
3312 }
3313#endif
3314 if (!r)
3315 {
3316#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3317 if (message && (p_confirm || cmdmod.confirm) && p_write)
3318 {
3319 dialog_changed(wp->w_buffer, FALSE);
3320# ifdef FEAT_AUTOCMD
3321 if (!win_valid(wp)) /* autocommands messed wp up */
3322 {
3323 nextwp = firstwin;
3324 continue;
3325 }
3326# endif
3327 }
3328 if (bufIsChanged(wp->w_buffer))
3329#endif
3330 continue;
3331 }
3332 win_close(wp, !P_HID(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
3333 }
3334 }
3335
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003336 if (message && lastwin != firstwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 EMSG(_("E445: Other window contains changes"));
3338}
3339
3340#endif /* FEAT_WINDOWS */
3341
3342/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003343 * Init the current window "curwin".
3344 * Called when a new file is being edited.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 */
3346 void
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003347curwin_init()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348{
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003349 win_init_empty(curwin);
3350}
3351
3352 void
3353win_init_empty(wp)
3354 win_T *wp;
3355{
3356 redraw_win_later(wp, NOT_VALID);
3357 wp->w_lines_valid = 0;
3358 wp->w_cursor.lnum = 1;
3359 wp->w_curswant = wp->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360#ifdef FEAT_VIRTUALEDIT
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003361 wp->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003362#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003363 wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
3364 wp->w_pcmark.col = 0;
3365 wp->w_prev_pcmark.lnum = 0;
3366 wp->w_prev_pcmark.col = 0;
3367 wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368#ifdef FEAT_DIFF
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003369 wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003371 wp->w_botline = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372#ifdef FEAT_FKMAP
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003373 if (wp->w_p_rl)
3374 wp->w_farsi = W_CONV + W_R_L;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 else
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003376 wp->w_farsi = W_CONV;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377#endif
Bram Moolenaara971b822011-09-14 14:43:25 +02003378#ifdef FEAT_SYN_HL
3379 wp->w_s = &wp->w_buffer->b_s;
3380#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381}
3382
3383/*
3384 * Allocate the first window and put an empty buffer in it.
3385 * Called from main().
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003386 * Return FAIL when something goes wrong (out of memory).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003388 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389win_alloc_first()
3390{
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003391 if (win_alloc_firstwin(NULL) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003392 return FAIL;
3393
3394#ifdef FEAT_WINDOWS
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003395 first_tabpage = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003396 if (first_tabpage == NULL)
3397 return FAIL;
3398 first_tabpage->tp_topframe = topframe;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003399 curtab = first_tabpage;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003400#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003401
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003402 return OK;
3403}
3404
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003405#if defined(FEAT_AUTOCMD) || defined(PROTO)
3406/*
3407 * Init "aucmd_win". This can only be done after the first
3408 * window is fully initialized, thus it can't be in win_alloc_first().
3409 */
3410 void
3411win_alloc_aucmd_win()
3412{
3413 aucmd_win = win_alloc(NULL, TRUE);
3414 if (aucmd_win != NULL)
3415 {
3416 win_init_some(aucmd_win, curwin);
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003417 RESET_BINDING(aucmd_win);
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003418 new_frame(aucmd_win);
3419 }
3420}
3421#endif
3422
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003423/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003424 * Allocate the first window or the first window in a new tab page.
3425 * When "oldwin" is NULL create an empty buffer for it.
3426 * When "oldwin" is not NULL copy info from it to the new window (only with
3427 * FEAT_WINDOWS).
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003428 * Return FAIL when something goes wrong (out of memory).
3429 */
3430 static int
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003431win_alloc_firstwin(oldwin)
3432 win_T *oldwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003433{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003434 curwin = win_alloc(NULL, FALSE);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003435 if (oldwin == NULL)
3436 {
3437 /* Very first window, need to create an empty buffer for it and
3438 * initialize from scratch. */
3439 curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
3440 if (curwin == NULL || curbuf == NULL)
3441 return FAIL;
3442 curwin->w_buffer = curbuf;
Bram Moolenaar860cae12010-06-05 23:22:07 +02003443#ifdef FEAT_SYN_HL
3444 curwin->w_s = &(curbuf->b_s);
3445#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003446 curbuf->b_nwindows = 1; /* there is one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447#ifdef FEAT_WINDOWS
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003448 curwin->w_alist = &global_alist;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003450 curwin_init(); /* init current window */
3451 }
3452#ifdef FEAT_WINDOWS
3453 else
3454 {
3455 /* First window in new tab page, initialize it from "oldwin". */
Bram Moolenaar884ae642009-02-22 01:37:59 +00003456 win_init(curwin, oldwin, 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003457
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003458 /* We don't want cursor- and scroll-binding in the first window. */
3459 RESET_BINDING(curwin);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003460 }
3461#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003462
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003463 new_frame(curwin);
3464 if (curwin->w_frame == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003465 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003466 topframe = curwin->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467#ifdef FEAT_VERTSPLIT
3468 topframe->fr_width = Columns;
3469#endif
3470 topframe->fr_height = Rows - p_ch;
3471 topframe->fr_win = curwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003472
3473 return OK;
3474}
3475
3476/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003477 * Create a frame for window "wp".
3478 */
3479 static void
3480new_frame(win_T *wp)
3481{
3482 frame_T *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
3483
3484 wp->w_frame = frp;
3485 if (frp != NULL)
3486 {
3487 frp->fr_layout = FR_LEAF;
3488 frp->fr_win = wp;
3489 }
3490}
3491
3492/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003493 * Initialize the window and frame size to the maximum.
3494 */
3495 void
3496win_init_size()
3497{
3498 firstwin->w_height = ROWS_AVAIL;
3499 topframe->fr_height = ROWS_AVAIL;
3500#ifdef FEAT_VERTSPLIT
3501 firstwin->w_width = Columns;
3502 topframe->fr_width = Columns;
3503#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504}
3505
3506#if defined(FEAT_WINDOWS) || defined(PROTO)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003507
3508/*
3509 * Allocate a new tabpage_T and init the values.
3510 * Returns NULL when out of memory.
3511 */
3512 static tabpage_T *
3513alloc_tabpage()
3514{
3515 tabpage_T *tp;
Bram Moolenaar429fa852013-04-15 12:27:36 +02003516# ifdef FEAT_GUI
3517 int i;
3518# endif
3519
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003520
3521 tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02003522 if (tp == NULL)
3523 return NULL;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003524
Bram Moolenaar429fa852013-04-15 12:27:36 +02003525# ifdef FEAT_EVAL
3526 /* init t: variables */
3527 tp->tp_vars = dict_alloc();
3528 if (tp->tp_vars == NULL)
3529 {
3530 vim_free(tp);
3531 return NULL;
3532 }
3533 init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
3534# endif
3535
3536# ifdef FEAT_GUI
3537 for (i = 0; i < 3; i++)
3538 tp->tp_prev_which_scrollbars[i] = -1;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003539# endif
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003540# ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02003541 tp->tp_diff_invalid = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003542# endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02003543 tp->tp_ch_used = p_ch;
3544
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003545 return tp;
3546}
3547
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00003548 void
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003549free_tabpage(tp)
3550 tabpage_T *tp;
3551{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003552 int idx;
3553
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003554# ifdef FEAT_DIFF
3555 diff_clear(tp);
3556# endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003557 for (idx = 0; idx < SNAP_COUNT; ++idx)
3558 clear_snapshot(tp, idx);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003559#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02003560 vars_clear(&tp->tp_vars->dv_hashtab); /* free all t: variables */
3561 hash_init(&tp->tp_vars->dv_hashtab);
3562 unref_var_dict(tp->tp_vars);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003563#endif
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02003564
3565#ifdef FEAT_PYTHON
3566 python_tabpage_free(tp);
3567#endif
3568
3569#ifdef FEAT_PYTHON3
3570 python3_tabpage_free(tp);
3571#endif
3572
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003573 vim_free(tp);
3574}
3575
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003576/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003577 * Create a new Tab page with one window.
3578 * It will edit the current buffer, like after ":split".
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003579 * When "after" is 0 put it just after the current Tab page.
3580 * Otherwise put it just before tab page "after".
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003581 * Return FAIL or OK.
3582 */
3583 int
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003584win_new_tabpage(after)
3585 int after;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003586{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003587 tabpage_T *tp = curtab;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003588 tabpage_T *newtp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003589 int n;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003590
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003591 newtp = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003592 if (newtp == NULL)
3593 return FAIL;
3594
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003595 /* Remember the current windows in this Tab page. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003596 if (leave_tabpage(curbuf, TRUE) == FAIL)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003597 {
3598 vim_free(newtp);
3599 return FAIL;
3600 }
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003601 curtab = newtp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003602
3603 /* Create a new empty window. */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003604 if (win_alloc_firstwin(tp->tp_curwin) == OK)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003605 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003606 /* Make the new Tab page the new topframe. */
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003607 if (after == 1)
3608 {
3609 /* New tab page becomes the first one. */
3610 newtp->tp_next = first_tabpage;
3611 first_tabpage = newtp;
3612 }
3613 else
3614 {
3615 if (after > 0)
3616 {
3617 /* Put new tab page before tab page "after". */
3618 n = 2;
3619 for (tp = first_tabpage; tp->tp_next != NULL
3620 && n < after; tp = tp->tp_next)
3621 ++n;
3622 }
3623 newtp->tp_next = tp->tp_next;
3624 tp->tp_next = newtp;
3625 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003626 win_init_size();
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003627 firstwin->w_winrow = tabline_height();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003628 win_comp_scroll(curwin);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003629
3630 newtp->tp_topframe = topframe;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003631 last_status(FALSE);
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003632
3633#if defined(FEAT_GUI)
3634 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3635 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003636 gui_may_update_scrollbars();
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003637#endif
3638
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003639 redraw_all_later(CLEAR);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003640#ifdef FEAT_AUTOCMD
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003641 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003642 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003643#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003644 return OK;
3645 }
3646
3647 /* Failed, get back the previous Tab page */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003648 enter_tabpage(curtab, curbuf, TRUE, TRUE);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003649 return FAIL;
3650}
3651
3652/*
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003653 * Open a new tab page if ":tab cmd" was used. It will edit the same buffer,
3654 * like with ":split".
3655 * Returns OK if a new tab page was created, FAIL otherwise.
3656 */
3657 int
3658may_open_tabpage()
3659{
Bram Moolenaard326ce82007-03-11 14:48:29 +00003660 int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003661
Bram Moolenaard326ce82007-03-11 14:48:29 +00003662 if (n != 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003663 {
3664 cmdmod.tab = 0; /* reset it to avoid doing it twice */
Bram Moolenaard326ce82007-03-11 14:48:29 +00003665 postponed_split_tab = 0;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003666 return win_new_tabpage(n);
3667 }
3668 return FAIL;
3669}
3670
3671/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003672 * Create up to "maxcount" tabpages with empty windows.
3673 * Returns the number of resulting tab pages.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003674 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003675 int
3676make_tabpages(maxcount)
3677 int maxcount;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003678{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003679 int count = maxcount;
3680 int todo;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003681
Bram Moolenaare1438bb2006-03-01 22:01:55 +00003682 /* Limit to 'tabpagemax' tabs. */
3683 if (count > p_tpm)
3684 count = p_tpm;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003685
3686#ifdef FEAT_AUTOCMD
3687 /*
3688 * Don't execute autocommands while creating the tab pages. Must do that
3689 * when putting the buffers in the windows.
3690 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003691 block_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003692#endif
3693
3694 for (todo = count - 1; todo > 0; --todo)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003695 if (win_new_tabpage(0) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003696 break;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003697
3698#ifdef FEAT_AUTOCMD
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003699 unblock_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003700#endif
3701
3702 /* return actual number of tab pages */
3703 return (count - todo);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003704}
3705
3706/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003707 * Return TRUE when "tpc" points to a valid tab page.
3708 */
3709 int
3710valid_tabpage(tpc)
3711 tabpage_T *tpc;
3712{
3713 tabpage_T *tp;
3714
3715 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
3716 if (tp == tpc)
3717 return TRUE;
3718 return FALSE;
3719}
3720
3721/*
3722 * Find tab page "n" (first one is 1). Returns NULL when not found.
3723 */
3724 tabpage_T *
3725find_tabpage(n)
3726 int n;
3727{
3728 tabpage_T *tp;
3729 int i = 1;
3730
3731 for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
3732 ++i;
3733 return tp;
3734}
3735
3736/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003737 * Get index of tab page "tp". First one has index 1.
Bram Moolenaarba6c0522006-02-25 21:45:02 +00003738 * When not found returns number of tab pages plus one.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003739 */
3740 int
3741tabpage_index(ftp)
3742 tabpage_T *ftp;
3743{
3744 int i = 1;
3745 tabpage_T *tp;
3746
3747 for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
3748 ++i;
3749 return i;
3750}
3751
3752/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003753 * Prepare for leaving the current tab page.
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003754 * When autocommands change "curtab" we don't leave the tab page and return
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003755 * FAIL.
3756 * Careful: When OK is returned need to get a new tab page very very soon!
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003757 */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003758 static int
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003759leave_tabpage(new_curbuf, trigger_leave_autocmds)
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00003760 buf_T *new_curbuf UNUSED; /* what is going to be the new curbuf,
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003761 NULL if unknown */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003762 int trigger_leave_autocmds UNUSED;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003763{
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003764 tabpage_T *tp = curtab;
3765
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003766 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003767#ifdef FEAT_AUTOCMD
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003768 if (trigger_leave_autocmds)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003769 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003770 if (new_curbuf != curbuf)
3771 {
3772 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
3773 if (curtab != tp)
3774 return FAIL;
3775 }
3776 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
3777 if (curtab != tp)
3778 return FAIL;
3779 apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003780 if (curtab != tp)
3781 return FAIL;
3782 }
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003783#endif
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003784#if defined(FEAT_GUI)
3785 /* Remove the scrollbars. They may be added back later. */
3786 if (gui.in_use)
3787 gui_remove_scrollbars();
3788#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003789 tp->tp_curwin = curwin;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003790 tp->tp_prevwin = prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003791 tp->tp_firstwin = firstwin;
3792 tp->tp_lastwin = lastwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003793 tp->tp_old_Rows = Rows;
3794 tp->tp_old_Columns = Columns;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003795 firstwin = NULL;
3796 lastwin = NULL;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003797 return OK;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003798}
3799
3800/*
3801 * Start using tab page "tp".
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003802 * Only to be used after leave_tabpage() or freeing the current tab page.
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003803 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
3804 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003805 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003806 static void
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003807enter_tabpage(tp, old_curbuf, trigger_enter_autocmds, trigger_leave_autocmds)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003808 tabpage_T *tp;
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00003809 buf_T *old_curbuf UNUSED;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003810 int trigger_enter_autocmds UNUSED;
3811 int trigger_leave_autocmds UNUSED;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003812{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003813 int old_off = tp->tp_firstwin->w_winrow;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003814 win_T *next_prevwin = tp->tp_prevwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003815
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003816 curtab = tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003817 firstwin = tp->tp_firstwin;
3818 lastwin = tp->tp_lastwin;
3819 topframe = tp->tp_topframe;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003820
3821 /* We would like doing the TabEnter event first, but we don't have a
3822 * valid current window yet, which may break some commands.
3823 * This triggers autocommands, thus may make "tp" invalid. */
Bram Moolenaard6949742013-06-16 14:18:28 +02003824 win_enter_ext(tp->tp_curwin, FALSE, TRUE,
3825 trigger_enter_autocmds, trigger_leave_autocmds);
Bram Moolenaar773560b2006-05-06 21:38:18 +00003826 prevwin = next_prevwin;
3827
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003828 last_status(FALSE); /* status line may appear or disappear */
3829 (void)win_comp_pos(); /* recompute w_winrow for all windows */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003830 must_redraw = CLEAR; /* need to redraw everything */
3831#ifdef FEAT_DIFF
3832 diff_need_scrollbind = TRUE;
3833#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003834
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003835 /* The tabpage line may have appeared or disappeared, may need to resize
3836 * the frames for that. When the Vim window was resized need to update
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003837 * frame sizes too. Use the stored value of p_ch, so that it can be
3838 * different for each tab page. */
3839 p_ch = curtab->tp_ch_used;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003840 if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
3841#ifdef FEAT_GUI_TABLINE
3842 && !gui_use_tabline()
3843#endif
3844 ))
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003845 shell_new_rows();
3846#ifdef FEAT_VERTSPLIT
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003847 if (curtab->tp_old_Columns != Columns && starting == 0)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003848 shell_new_columns(); /* update window widths */
3849#endif
3850
3851#if defined(FEAT_GUI)
3852 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3853 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003854 gui_may_update_scrollbars();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003855#endif
3856
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003857#ifdef FEAT_AUTOCMD
3858 /* Apply autocommands after updating the display, when 'rows' and
3859 * 'columns' have been set correctly. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003860 if (trigger_enter_autocmds)
Bram Moolenaara8596c42012-06-13 14:28:20 +02003861 {
3862 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
3863 if (old_curbuf != curbuf)
3864 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
3865 }
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003866#endif
3867
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003868 redraw_all_later(CLEAR);
3869}
3870
3871/*
3872 * Go to tab page "n". For ":tab N" and "Ngt".
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003873 * When "n" is 9999 go to the last tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003874 */
3875 void
3876goto_tabpage(n)
3877 int n;
3878{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003879 tabpage_T *tp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003880 tabpage_T *ttp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003881 int i;
3882
Bram Moolenaard68071d2006-05-02 22:08:30 +00003883 if (text_locked())
3884 {
3885 /* Not allowed when editing the command line. */
3886#ifdef FEAT_CMDWIN
3887 if (cmdwin_type != 0)
3888 EMSG(_(e_cmdwin));
3889 else
3890#endif
3891 EMSG(_(e_secure));
3892 return;
3893 }
3894
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003895 /* If there is only one it can't work. */
3896 if (first_tabpage->tp_next == NULL)
3897 {
3898 if (n > 1)
3899 beep_flush();
3900 return;
3901 }
3902
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003903 if (n == 0)
3904 {
3905 /* No count, go to next tab page, wrap around end. */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003906 if (curtab->tp_next == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003907 tp = first_tabpage;
3908 else
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003909 tp = curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003910 }
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003911 else if (n < 0)
3912 {
3913 /* "gT": go to previous tab page, wrap around end. "N gT" repeats
3914 * this N times. */
3915 ttp = curtab;
3916 for (i = n; i < 0; ++i)
3917 {
3918 for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
3919 tp = tp->tp_next)
3920 ;
3921 ttp = tp;
3922 }
3923 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003924 else if (n == 9999)
3925 {
3926 /* Go to last tab page. */
3927 for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
3928 ;
3929 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003930 else
3931 {
3932 /* Go to tab page "n". */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003933 tp = find_tabpage(n);
Bram Moolenaarf740b292006-02-16 22:11:02 +00003934 if (tp == NULL)
3935 {
3936 beep_flush();
3937 return;
3938 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003939 }
3940
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003941 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003942
3943#ifdef FEAT_GUI_TABLINE
3944 if (gui_use_tabline())
Bram Moolenaara226a6d2006-02-26 23:59:20 +00003945 gui_mch_set_curtab(tabpage_index(curtab));
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003946#endif
3947}
3948
3949/*
3950 * Go to tabpage "tp".
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003951 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
3952 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003953 * Note: doesn't update the GUI tab.
3954 */
3955 void
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003956goto_tabpage_tp(tp, trigger_enter_autocmds, trigger_leave_autocmds)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003957 tabpage_T *tp;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003958 int trigger_enter_autocmds;
3959 int trigger_leave_autocmds;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003960{
Bram Moolenaarc6af8122010-05-21 12:04:55 +02003961 /* Don't repeat a message in another tab page. */
3962 set_keep_msg(NULL, 0);
3963
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003964 if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
3965 trigger_leave_autocmds) == OK)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003966 {
3967 if (valid_tabpage(tp))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003968 enter_tabpage(tp, curbuf, trigger_enter_autocmds,
3969 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003970 else
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003971 enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
3972 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003973 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003974}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975
3976/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003977 * Enter window "wp" in tab page "tp".
3978 * Also updates the GUI tab.
3979 */
3980 void
3981goto_tabpage_win(tp, wp)
3982 tabpage_T *tp;
3983 win_T *wp;
3984{
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003985 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar779b74b2006-04-10 14:55:34 +00003986 if (curtab == tp && win_valid(wp))
3987 {
3988 win_enter(wp, TRUE);
3989# ifdef FEAT_GUI_TABLINE
3990 if (gui_use_tabline())
3991 gui_mch_set_curtab(tabpage_index(curtab));
3992# endif
3993 }
3994}
3995
3996/*
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003997 * Move the current tab page to before tab page "nr".
3998 */
3999 void
4000tabpage_move(nr)
4001 int nr;
4002{
4003 int n = nr;
4004 tabpage_T *tp;
4005
4006 if (first_tabpage->tp_next == NULL)
4007 return;
4008
4009 /* Remove the current tab page from the list of tab pages. */
4010 if (curtab == first_tabpage)
4011 first_tabpage = curtab->tp_next;
4012 else
4013 {
4014 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
4015 if (tp->tp_next == curtab)
4016 break;
4017 if (tp == NULL) /* "cannot happen" */
4018 return;
4019 tp->tp_next = curtab->tp_next;
4020 }
4021
4022 /* Re-insert it at the specified position. */
Bram Moolenaar8cb8dca2012-07-06 18:27:39 +02004023 if (n <= 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004024 {
4025 curtab->tp_next = first_tabpage;
4026 first_tabpage = curtab;
4027 }
4028 else
4029 {
4030 for (tp = first_tabpage; tp->tp_next != NULL && n > 1; tp = tp->tp_next)
4031 --n;
4032 curtab->tp_next = tp->tp_next;
4033 tp->tp_next = curtab;
4034 }
4035
4036 /* Need to redraw the tabline. Tab page contents doesn't change. */
4037 redraw_tabline = TRUE;
4038}
4039
4040
4041/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 * Go to another window.
4043 * When jumping to another buffer, stop Visual mode. Do this before
4044 * changing windows so we can yank the selection into the '*' register.
4045 * When jumping to another window on the same buffer, adjust its cursor
4046 * position to keep the same Visual area.
4047 */
4048 void
4049win_goto(wp)
4050 win_T *wp;
4051{
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004052#ifdef FEAT_CONCEAL
4053 win_T *owp = curwin;
4054#endif
4055
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004056 if (text_locked())
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 {
4058 beep_flush();
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004059 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060 return;
4061 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004062#ifdef FEAT_AUTOCMD
4063 if (curbuf_locked())
4064 return;
4065#endif
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00004066
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067 if (wp->w_buffer != curbuf)
4068 reset_VIsual_and_resel();
4069 else if (VIsual_active)
4070 wp->w_cursor = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071
4072#ifdef FEAT_GUI
4073 need_mouse_correct = TRUE;
4074#endif
4075 win_enter(wp, TRUE);
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004076
4077#ifdef FEAT_CONCEAL
4078 /* Conceal cursor line in previous window, unconceal in current window. */
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004079 if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004080 update_single_line(owp, owp->w_cursor.lnum);
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004081 if (curwin->w_p_cole > 0 && !msg_scrolled)
4082 need_cursor_line_redraw = TRUE;
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004083#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084}
4085
4086#if defined(FEAT_PERL) || defined(PROTO)
4087/*
4088 * Find window number "winnr" (counting top to bottom).
4089 */
4090 win_T *
4091win_find_nr(winnr)
4092 int winnr;
4093{
4094 win_T *wp;
4095
4096# ifdef FEAT_WINDOWS
4097 for (wp = firstwin; wp != NULL; wp = wp->w_next)
4098 if (--winnr == 0)
4099 break;
4100 return wp;
4101# else
4102 return curwin;
4103# endif
4104}
4105#endif
4106
Bram Moolenaar6fa41fb2013-05-18 20:55:35 +02004107#if (defined(FEAT_WINDOWS) && (defined(FEAT_PYTHON) || defined(FEAT_PYTHON3))) \
4108 || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004109/*
4110 * Find the tabpage for window "win".
4111 */
4112 tabpage_T *
4113win_find_tabpage(win)
4114 win_T *win;
4115{
4116 win_T *wp;
4117 tabpage_T *tp;
4118
4119 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
Bram Moolenaar5e6d5ca2013-07-03 14:01:56 +02004120 for (wp = (tp == curtab ? firstwin : tp->tp_firstwin);
4121 wp != NULL; wp = wp->w_next)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004122 if (wp == win)
4123 return tp;
4124 return NULL;
4125}
4126#endif
4127
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128#ifdef FEAT_VERTSPLIT
4129/*
4130 * Move to window above or below "count" times.
4131 */
4132 static void
4133win_goto_ver(up, count)
4134 int up; /* TRUE to go to win above */
4135 long count;
4136{
4137 frame_T *fr;
4138 frame_T *nfr;
4139 frame_T *foundfr;
4140
4141 foundfr = curwin->w_frame;
4142 while (count--)
4143 {
4144 /*
4145 * First go upwards in the tree of frames until we find a upwards or
4146 * downwards neighbor.
4147 */
4148 fr = foundfr;
4149 for (;;)
4150 {
4151 if (fr == topframe)
4152 goto end;
4153 if (up)
4154 nfr = fr->fr_prev;
4155 else
4156 nfr = fr->fr_next;
4157 if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
4158 break;
4159 fr = fr->fr_parent;
4160 }
4161
4162 /*
4163 * Now go downwards to find the bottom or top frame in it.
4164 */
4165 for (;;)
4166 {
4167 if (nfr->fr_layout == FR_LEAF)
4168 {
4169 foundfr = nfr;
4170 break;
4171 }
4172 fr = nfr->fr_child;
4173 if (nfr->fr_layout == FR_ROW)
4174 {
4175 /* Find the frame at the cursor row. */
4176 while (fr->fr_next != NULL
4177 && frame2win(fr)->w_wincol + fr->fr_width
4178 <= curwin->w_wincol + curwin->w_wcol)
4179 fr = fr->fr_next;
4180 }
4181 if (nfr->fr_layout == FR_COL && up)
4182 while (fr->fr_next != NULL)
4183 fr = fr->fr_next;
4184 nfr = fr;
4185 }
4186 }
4187end:
4188 if (foundfr != NULL)
4189 win_goto(foundfr->fr_win);
4190}
4191
4192/*
4193 * Move to left or right window.
4194 */
4195 static void
4196win_goto_hor(left, count)
4197 int left; /* TRUE to go to left win */
4198 long count;
4199{
4200 frame_T *fr;
4201 frame_T *nfr;
4202 frame_T *foundfr;
4203
4204 foundfr = curwin->w_frame;
4205 while (count--)
4206 {
4207 /*
4208 * First go upwards in the tree of frames until we find a left or
4209 * right neighbor.
4210 */
4211 fr = foundfr;
4212 for (;;)
4213 {
4214 if (fr == topframe)
4215 goto end;
4216 if (left)
4217 nfr = fr->fr_prev;
4218 else
4219 nfr = fr->fr_next;
4220 if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
4221 break;
4222 fr = fr->fr_parent;
4223 }
4224
4225 /*
4226 * Now go downwards to find the leftmost or rightmost frame in it.
4227 */
4228 for (;;)
4229 {
4230 if (nfr->fr_layout == FR_LEAF)
4231 {
4232 foundfr = nfr;
4233 break;
4234 }
4235 fr = nfr->fr_child;
4236 if (nfr->fr_layout == FR_COL)
4237 {
4238 /* Find the frame at the cursor row. */
4239 while (fr->fr_next != NULL
4240 && frame2win(fr)->w_winrow + fr->fr_height
4241 <= curwin->w_winrow + curwin->w_wrow)
4242 fr = fr->fr_next;
4243 }
4244 if (nfr->fr_layout == FR_ROW && left)
4245 while (fr->fr_next != NULL)
4246 fr = fr->fr_next;
4247 nfr = fr;
4248 }
4249 }
4250end:
4251 if (foundfr != NULL)
4252 win_goto(foundfr->fr_win);
4253}
4254#endif
4255
4256/*
4257 * Make window "wp" the current window.
4258 */
4259 void
4260win_enter(wp, undo_sync)
4261 win_T *wp;
4262 int undo_sync;
4263{
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004264 win_enter_ext(wp, undo_sync, FALSE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265}
4266
4267/*
4268 * Make window wp the current window.
4269 * Can be called with "curwin_invalid" TRUE, which means that curwin has just
4270 * been closed and isn't valid.
4271 */
4272 static void
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004273win_enter_ext(wp, undo_sync, curwin_invalid, trigger_enter_autocmds, trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 win_T *wp;
4275 int undo_sync;
4276 int curwin_invalid;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004277 int trigger_enter_autocmds UNUSED;
4278 int trigger_leave_autocmds UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279{
4280#ifdef FEAT_AUTOCMD
4281 int other_buffer = FALSE;
4282#endif
4283
4284 if (wp == curwin && !curwin_invalid) /* nothing to do */
4285 return;
4286
4287#ifdef FEAT_AUTOCMD
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004288 if (!curwin_invalid && trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 {
4290 /*
4291 * Be careful: If autocommands delete the window, return now.
4292 */
4293 if (wp->w_buffer != curbuf)
4294 {
4295 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
4296 other_buffer = TRUE;
4297 if (!win_valid(wp))
4298 return;
4299 }
4300 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
4301 if (!win_valid(wp))
4302 return;
4303# ifdef FEAT_EVAL
4304 /* autocmds may abort script processing */
4305 if (aborting())
4306 return;
4307# endif
4308 }
4309#endif
4310
4311 /* sync undo before leaving the current buffer */
4312 if (undo_sync && curbuf != wp->w_buffer)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004313 u_sync(FALSE);
Bram Moolenaarec1561c2014-06-17 13:52:40 +02004314
4315 /* Might need to scroll the old window before switching, e.g., when the
4316 * cursor was moved. */
4317 update_topline();
4318
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 /* may have to copy the buffer options when 'cpo' contains 'S' */
4320 if (wp->w_buffer != curbuf)
4321 buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
4322 if (!curwin_invalid)
4323 {
4324 prevwin = curwin; /* remember for CTRL-W p */
4325 curwin->w_redr_status = TRUE;
4326 }
4327 curwin = wp;
4328 curbuf = wp->w_buffer;
4329 check_cursor();
4330#ifdef FEAT_VIRTUALEDIT
4331 if (!virtual_active())
4332 curwin->w_cursor.coladd = 0;
4333#endif
4334 changed_line_abv_curs(); /* assume cursor position needs updating */
4335
4336 if (curwin->w_localdir != NULL)
4337 {
4338 /* Window has a local directory: Save current directory as global
4339 * directory (unless that was done already) and change to the local
4340 * directory. */
4341 if (globaldir == NULL)
4342 {
4343 char_u cwd[MAXPATHL];
4344
4345 if (mch_dirname(cwd, MAXPATHL) == OK)
4346 globaldir = vim_strsave(cwd);
4347 }
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004348 if (mch_chdir((char *)curwin->w_localdir) == 0)
4349 shorten_fnames(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350 }
4351 else if (globaldir != NULL)
4352 {
4353 /* Window doesn't have a local directory and we are not in the global
4354 * directory: Change to the global directory. */
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004355 ignored = mch_chdir((char *)globaldir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 vim_free(globaldir);
4357 globaldir = NULL;
4358 shorten_fnames(TRUE);
4359 }
4360
4361#ifdef FEAT_AUTOCMD
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004362 if (trigger_enter_autocmds)
4363 {
4364 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
4365 if (other_buffer)
4366 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
4367 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368#endif
4369
4370#ifdef FEAT_TITLE
4371 maketitle();
4372#endif
4373 curwin->w_redr_status = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00004374 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004375 if (restart_edit)
4376 redraw_later(VALID); /* causes status line redraw */
4377
4378 /* set window height to desired minimal value */
4379 if (curwin->w_height < p_wh && !curwin->w_p_wfh)
4380 win_setheight((int)p_wh);
4381 else if (curwin->w_height == 0)
4382 win_setheight(1);
4383
4384#ifdef FEAT_VERTSPLIT
4385 /* set window width to desired minimal value */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004386 if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387 win_setwidth((int)p_wiw);
4388#endif
4389
4390#ifdef FEAT_MOUSE
4391 setmouse(); /* in case jumped to/from help buffer */
4392#endif
4393
Bram Moolenaar498efdb2006-09-05 14:31:54 +00004394 /* Change directories when the 'acd' option is set. */
4395 DO_AUTOCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396}
4397
4398#endif /* FEAT_WINDOWS */
4399
4400#if defined(FEAT_WINDOWS) || defined(FEAT_SIGNS) || defined(PROTO)
4401/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004402 * Jump to the first open window that contains buffer "buf", if one exists.
4403 * Returns a pointer to the window found, otherwise NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404 */
4405 win_T *
4406buf_jump_open_win(buf)
4407 buf_T *buf;
4408{
4409# ifdef FEAT_WINDOWS
4410 win_T *wp;
4411
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004412 for (wp = firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413 if (wp->w_buffer == buf)
4414 break;
4415 if (wp != NULL)
4416 win_enter(wp, FALSE);
4417 return wp;
4418# else
4419 if (curwin->w_buffer == buf)
4420 return curwin;
4421 return NULL;
4422# endif
4423}
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004424
4425/*
4426 * Jump to the first open window in any tab page that contains buffer "buf",
4427 * if one exists.
4428 * Returns a pointer to the window found, otherwise NULL.
4429 */
4430 win_T *
4431buf_jump_open_tab(buf)
4432 buf_T *buf;
4433{
4434# ifdef FEAT_WINDOWS
4435 win_T *wp;
4436 tabpage_T *tp;
4437
4438 /* First try the current tab page. */
4439 wp = buf_jump_open_win(buf);
4440 if (wp != NULL)
4441 return wp;
4442
4443 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
4444 if (tp != curtab)
4445 {
4446 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
4447 if (wp->w_buffer == buf)
4448 break;
4449 if (wp != NULL)
4450 {
4451 goto_tabpage_win(tp, wp);
4452 if (curwin != wp)
4453 wp = NULL; /* something went wrong */
4454 break;
4455 }
4456 }
4457
4458 return wp;
4459# else
4460 if (curwin->w_buffer == buf)
4461 return curwin;
4462 return NULL;
4463# endif
4464}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465#endif
4466
4467/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004468 * Allocate a window structure and link it in the window list when "hidden" is
4469 * FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 static win_T *
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004472win_alloc(after, hidden)
Bram Moolenaar4bdbbf72009-05-21 21:27:43 +00004473 win_T *after UNUSED;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004474 int hidden UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004476 win_T *new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477
4478 /*
4479 * allocate window structure and linesizes arrays
4480 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004481 new_wp = (win_T *)alloc_clear((unsigned)sizeof(win_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02004482 if (new_wp == NULL)
4483 return NULL;
4484
4485 if (win_alloc_lines(new_wp) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004487 vim_free(new_wp);
Bram Moolenaar429fa852013-04-15 12:27:36 +02004488 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489 }
4490
Bram Moolenaar429fa852013-04-15 12:27:36 +02004491#ifdef FEAT_EVAL
4492 /* init w: variables */
4493 new_wp->w_vars = dict_alloc();
4494 if (new_wp->w_vars == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 {
Bram Moolenaar429fa852013-04-15 12:27:36 +02004496 win_free_lsize(new_wp);
4497 vim_free(new_wp);
4498 return NULL;
4499 }
4500 init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004501#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004502
4503#ifdef FEAT_AUTOCMD
4504 /* Don't execute autocommands while the window is not properly
4505 * initialized yet. gui_create_scrollbar() may trigger a FocusGained
4506 * event. */
4507 block_autocmds();
4508#endif
4509 /*
4510 * link the window in the window list
4511 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004512#ifdef FEAT_WINDOWS
Bram Moolenaar429fa852013-04-15 12:27:36 +02004513 if (!hidden)
4514 win_append(after, new_wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515#endif
4516#ifdef FEAT_VERTSPLIT
Bram Moolenaar429fa852013-04-15 12:27:36 +02004517 new_wp->w_wincol = 0;
4518 new_wp->w_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519#endif
4520
Bram Moolenaar429fa852013-04-15 12:27:36 +02004521 /* position the display and the cursor at the top of the file. */
4522 new_wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523#ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02004524 new_wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004526 new_wp->w_botline = 2;
4527 new_wp->w_cursor.lnum = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528#ifdef FEAT_SCROLLBIND
Bram Moolenaar429fa852013-04-15 12:27:36 +02004529 new_wp->w_scbind_pos = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530#endif
4531
Bram Moolenaar429fa852013-04-15 12:27:36 +02004532 /* We won't calculate w_fraction until resizing the window */
4533 new_wp->w_fraction = 0;
4534 new_wp->w_prev_fraction_row = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535
4536#ifdef FEAT_GUI
Bram Moolenaar429fa852013-04-15 12:27:36 +02004537 if (gui.in_use)
4538 {
4539 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
4540 SBAR_LEFT, new_wp);
4541 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
4542 SBAR_RIGHT, new_wp);
4543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544#endif
4545#ifdef FEAT_FOLDING
Bram Moolenaar429fa852013-04-15 12:27:36 +02004546 foldInitWin(new_wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547#endif
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004548#ifdef FEAT_AUTOCMD
Bram Moolenaar429fa852013-04-15 12:27:36 +02004549 unblock_autocmds();
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004550#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004551#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar429fa852013-04-15 12:27:36 +02004552 new_wp->w_match_head = NULL;
4553 new_wp->w_next_match_id = 4;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004554#endif
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004555 return new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556}
4557
4558#if defined(FEAT_WINDOWS) || defined(PROTO)
4559
4560/*
Bram Moolenaarff18df02013-07-24 17:51:57 +02004561 * Remove window 'wp' from the window list and free the structure.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 */
4563 static void
Bram Moolenaarf740b292006-02-16 22:11:02 +00004564win_free(wp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004566 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567{
4568 int i;
Bram Moolenaarff18df02013-07-24 17:51:57 +02004569 buf_T *buf;
4570 wininfo_T *wip;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004572#ifdef FEAT_FOLDING
4573 clearFolding(wp);
4574#endif
4575
4576 /* reduce the reference count to the argument list. */
4577 alist_unlink(wp->w_alist);
4578
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004579#ifdef FEAT_AUTOCMD
4580 /* Don't execute autocommands while the window is halfway being deleted.
4581 * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004582 block_autocmds();
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004583#endif
4584
Bram Moolenaar0ba04292010-07-14 23:23:17 +02004585#ifdef FEAT_LUA
4586 lua_window_free(wp);
4587#endif
4588
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004589#ifdef FEAT_MZSCHEME
4590 mzscheme_window_free(wp);
4591#endif
4592
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593#ifdef FEAT_PERL
4594 perl_win_free(wp);
4595#endif
4596
4597#ifdef FEAT_PYTHON
4598 python_window_free(wp);
4599#endif
4600
Bram Moolenaarbd5e15f2010-07-17 21:19:38 +02004601#ifdef FEAT_PYTHON3
4602 python3_window_free(wp);
4603#endif
4604
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605#ifdef FEAT_TCL
4606 tcl_window_free(wp);
4607#endif
4608
4609#ifdef FEAT_RUBY
4610 ruby_window_free(wp);
4611#endif
4612
4613 clear_winopt(&wp->w_onebuf_opt);
4614 clear_winopt(&wp->w_allbuf_opt);
4615
4616#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02004617 vars_clear(&wp->w_vars->dv_hashtab); /* free all w: variables */
4618 hash_init(&wp->w_vars->dv_hashtab);
4619 unref_var_dict(wp->w_vars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620#endif
4621
4622 if (prevwin == wp)
4623 prevwin = NULL;
4624 win_free_lsize(wp);
4625
4626 for (i = 0; i < wp->w_tagstacklen; ++i)
4627 vim_free(wp->w_tagstack[i].tagname);
4628
4629 vim_free(wp->w_localdir);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004630
Bram Moolenaarff18df02013-07-24 17:51:57 +02004631 /* Remove the window from the b_wininfo lists, it may happen that the
4632 * freed memory is re-used for another window. */
4633 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
4634 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
4635 if (wip->wi_win == wp)
4636 wip->wi_win = NULL;
4637
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004639 clear_matches(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004641
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642#ifdef FEAT_JUMPLIST
4643 free_jumplist(wp);
4644#endif
4645
Bram Moolenaar28c258f2006-01-25 22:02:51 +00004646#ifdef FEAT_QUICKFIX
4647 qf_free_all(wp);
4648#endif
4649
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650#ifdef FEAT_GUI
4651 if (gui.in_use)
4652 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
4654 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
4655 }
4656#endif /* FEAT_GUI */
4657
Bram Moolenaar860cae12010-06-05 23:22:07 +02004658#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02004659 vim_free(wp->w_p_cc_cols);
Bram Moolenaar860cae12010-06-05 23:22:07 +02004660#endif
4661
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004662#ifdef FEAT_AUTOCMD
4663 if (wp != aucmd_win)
4664#endif
Bram Moolenaarfd29f462010-06-06 16:11:09 +02004665 win_remove(wp, tp);
Bram Moolenaarf0224c92014-06-14 12:53:33 +02004666#ifdef FEAT_AUTOCMD
Bram Moolenaar3be85852014-06-12 14:01:31 +02004667 if (autocmd_busy)
4668 {
4669 wp->w_next = au_pending_free_win;
4670 au_pending_free_win = wp;
4671 }
4672 else
Bram Moolenaarf0224c92014-06-14 12:53:33 +02004673#endif
Bram Moolenaar3be85852014-06-12 14:01:31 +02004674 vim_free(wp);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004675
4676#ifdef FEAT_AUTOCMD
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004677 unblock_autocmds();
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004678#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679}
4680
4681/*
4682 * Append window "wp" in the window list after window "after".
4683 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004684 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685win_append(after, wp)
4686 win_T *after, *wp;
4687{
4688 win_T *before;
4689
4690 if (after == NULL) /* after NULL is in front of the first */
4691 before = firstwin;
4692 else
4693 before = after->w_next;
4694
4695 wp->w_next = before;
4696 wp->w_prev = after;
4697 if (after == NULL)
4698 firstwin = wp;
4699 else
4700 after->w_next = wp;
4701 if (before == NULL)
4702 lastwin = wp;
4703 else
4704 before->w_prev = wp;
4705}
4706
4707/*
4708 * Remove a window from the window list.
4709 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004710 void
Bram Moolenaarf740b292006-02-16 22:11:02 +00004711win_remove(wp, tp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004713 tabpage_T *tp; /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714{
4715 if (wp->w_prev != NULL)
4716 wp->w_prev->w_next = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004717 else if (tp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718 firstwin = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004719 else
4720 tp->tp_firstwin = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 if (wp->w_next != NULL)
4722 wp->w_next->w_prev = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004723 else if (tp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724 lastwin = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004725 else
4726 tp->tp_lastwin = wp->w_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727}
4728
4729/*
4730 * Append frame "frp" in a frame list after frame "after".
4731 */
4732 static void
4733frame_append(after, frp)
4734 frame_T *after, *frp;
4735{
4736 frp->fr_next = after->fr_next;
4737 after->fr_next = frp;
4738 if (frp->fr_next != NULL)
4739 frp->fr_next->fr_prev = frp;
4740 frp->fr_prev = after;
4741}
4742
4743/*
4744 * Insert frame "frp" in a frame list before frame "before".
4745 */
4746 static void
4747frame_insert(before, frp)
4748 frame_T *before, *frp;
4749{
4750 frp->fr_next = before;
4751 frp->fr_prev = before->fr_prev;
4752 before->fr_prev = frp;
4753 if (frp->fr_prev != NULL)
4754 frp->fr_prev->fr_next = frp;
4755 else
4756 frp->fr_parent->fr_child = frp;
4757}
4758
4759/*
4760 * Remove a frame from a frame list.
4761 */
4762 static void
4763frame_remove(frp)
4764 frame_T *frp;
4765{
4766 if (frp->fr_prev != NULL)
4767 frp->fr_prev->fr_next = frp->fr_next;
4768 else
4769 frp->fr_parent->fr_child = frp->fr_next;
4770 if (frp->fr_next != NULL)
4771 frp->fr_next->fr_prev = frp->fr_prev;
4772}
4773
4774#endif /* FEAT_WINDOWS */
4775
4776/*
4777 * Allocate w_lines[] for window "wp".
4778 * Return FAIL for failure, OK for success.
4779 */
4780 int
4781win_alloc_lines(wp)
4782 win_T *wp;
4783{
4784 wp->w_lines_valid = 0;
Bram Moolenaar9334c342006-11-21 19:57:30 +00004785 wp->w_lines = (wline_T *)alloc_clear((unsigned)(Rows * sizeof(wline_T)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 if (wp->w_lines == NULL)
4787 return FAIL;
4788 return OK;
4789}
4790
4791/*
4792 * free lsize arrays for a window
4793 */
4794 void
4795win_free_lsize(wp)
4796 win_T *wp;
4797{
Bram Moolenaar06e4a6d2014-06-12 11:49:46 +02004798 /* TODO: why would wp be NULL here? */
4799 if (wp != NULL)
4800 {
4801 vim_free(wp->w_lines);
4802 wp->w_lines = NULL;
4803 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804}
4805
4806/*
4807 * Called from win_new_shellsize() after Rows changed.
Bram Moolenaarf740b292006-02-16 22:11:02 +00004808 * This only does the current tab page, others must be done when made active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809 */
4810 void
4811shell_new_rows()
4812{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004813 int h = (int)ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004814
4815 if (firstwin == NULL) /* not initialized yet */
4816 return;
4817#ifdef FEAT_WINDOWS
4818 if (h < frame_minheight(topframe, NULL))
4819 h = frame_minheight(topframe, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004820
4821 /* First try setting the heights of windows with 'winfixheight'. If
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 * that doesn't result in the right height, forget about that option. */
4823 frame_new_height(topframe, h, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004824 if (!frame_check_height(topframe, h))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825 frame_new_height(topframe, h, FALSE, FALSE);
4826
4827 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
4828#else
4829 if (h < 1)
4830 h = 1;
4831 win_new_height(firstwin, h);
4832#endif
4833 compute_cmdrow();
Bram Moolenaar05159a02005-02-26 23:04:13 +00004834#ifdef FEAT_WINDOWS
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00004835 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004836#endif
4837
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838#if 0
4839 /* Disabled: don't want making the screen smaller make a window larger. */
4840 if (p_ea)
4841 win_equal(curwin, FALSE, 'v');
4842#endif
4843}
4844
4845#if defined(FEAT_VERTSPLIT) || defined(PROTO)
4846/*
4847 * Called from win_new_shellsize() after Columns changed.
4848 */
4849 void
4850shell_new_columns()
4851{
4852 if (firstwin == NULL) /* not initialized yet */
4853 return;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004854
4855 /* First try setting the widths of windows with 'winfixwidth'. If that
4856 * doesn't result in the right width, forget about that option. */
4857 frame_new_width(topframe, (int)Columns, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004858 if (!frame_check_width(topframe, Columns))
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004859 frame_new_width(topframe, (int)Columns, FALSE, FALSE);
4860
Bram Moolenaar071d4272004-06-13 20:20:40 +00004861 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
4862#if 0
4863 /* Disabled: don't want making the screen smaller make a window larger. */
4864 if (p_ea)
4865 win_equal(curwin, FALSE, 'h');
4866#endif
4867}
4868#endif
4869
4870#if defined(FEAT_CMDWIN) || defined(PROTO)
4871/*
4872 * Save the size of all windows in "gap".
4873 */
4874 void
4875win_size_save(gap)
4876 garray_T *gap;
4877
4878{
4879 win_T *wp;
4880
4881 ga_init2(gap, (int)sizeof(int), 1);
4882 if (ga_grow(gap, win_count() * 2) == OK)
4883 for (wp = firstwin; wp != NULL; wp = wp->w_next)
4884 {
4885 ((int *)gap->ga_data)[gap->ga_len++] =
4886 wp->w_width + wp->w_vsep_width;
4887 ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
4888 }
4889}
4890
4891/*
4892 * Restore window sizes, but only if the number of windows is still the same.
4893 * Does not free the growarray.
4894 */
4895 void
4896win_size_restore(gap)
4897 garray_T *gap;
4898{
4899 win_T *wp;
Bram Moolenaarb643e772014-07-16 15:18:26 +02004900 int i, j;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901
4902 if (win_count() * 2 == gap->ga_len)
4903 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004904 /* The order matters, because frames contain other frames, but it's
4905 * difficult to get right. The easy way out is to do it twice. */
4906 for (j = 0; j < 2; ++j)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004908 i = 0;
4909 for (wp = firstwin; wp != NULL; wp = wp->w_next)
4910 {
4911 frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
4912 win_setheight_win(((int *)gap->ga_data)[i++], wp);
4913 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004914 }
4915 /* recompute the window positions */
4916 (void)win_comp_pos();
4917 }
4918}
4919#endif /* FEAT_CMDWIN */
4920
4921#if defined(FEAT_WINDOWS) || defined(PROTO)
4922/*
4923 * Update the position for all windows, using the width and height of the
4924 * frames.
4925 * Returns the row just after the last window.
4926 */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00004927 int
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928win_comp_pos()
4929{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004930 int row = tabline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004931 int col = 0;
4932
4933 frame_comp_pos(topframe, &row, &col);
4934 return row;
4935}
4936
4937/*
4938 * Update the position of the windows in frame "topfrp", using the width and
4939 * height of the frames.
4940 * "*row" and "*col" are the top-left position of the frame. They are updated
4941 * to the bottom-right position plus one.
4942 */
4943 static void
4944frame_comp_pos(topfrp, row, col)
4945 frame_T *topfrp;
4946 int *row;
4947 int *col;
4948{
4949 win_T *wp;
4950 frame_T *frp;
4951#ifdef FEAT_VERTSPLIT
4952 int startcol;
4953 int startrow;
4954#endif
4955
4956 wp = topfrp->fr_win;
4957 if (wp != NULL)
4958 {
4959 if (wp->w_winrow != *row
4960#ifdef FEAT_VERTSPLIT
4961 || wp->w_wincol != *col
4962#endif
4963 )
4964 {
4965 /* position changed, redraw */
4966 wp->w_winrow = *row;
4967#ifdef FEAT_VERTSPLIT
4968 wp->w_wincol = *col;
4969#endif
4970 redraw_win_later(wp, NOT_VALID);
4971 wp->w_redr_status = TRUE;
4972 }
4973 *row += wp->w_height + wp->w_status_height;
4974#ifdef FEAT_VERTSPLIT
4975 *col += wp->w_width + wp->w_vsep_width;
4976#endif
4977 }
4978 else
4979 {
4980#ifdef FEAT_VERTSPLIT
4981 startrow = *row;
4982 startcol = *col;
4983#endif
4984 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
4985 {
4986#ifdef FEAT_VERTSPLIT
4987 if (topfrp->fr_layout == FR_ROW)
4988 *row = startrow; /* all frames are at the same row */
4989 else
4990 *col = startcol; /* all frames are at the same col */
4991#endif
4992 frame_comp_pos(frp, row, col);
4993 }
4994 }
4995}
4996
4997#endif /* FEAT_WINDOWS */
4998
4999/*
5000 * Set current window height and take care of repositioning other windows to
5001 * fit around it.
5002 */
5003 void
5004win_setheight(height)
5005 int height;
5006{
5007 win_setheight_win(height, curwin);
5008}
5009
5010/*
5011 * Set the window height of window "win" and take care of repositioning other
5012 * windows to fit around it.
5013 */
5014 void
5015win_setheight_win(height, win)
5016 int height;
5017 win_T *win;
5018{
5019 int row;
5020
5021 if (win == curwin)
5022 {
5023 /* Always keep current window at least one line high, even when
5024 * 'winminheight' is zero. */
5025#ifdef FEAT_WINDOWS
5026 if (height < p_wmh)
5027 height = p_wmh;
5028#endif
5029 if (height == 0)
5030 height = 1;
5031 }
5032
5033#ifdef FEAT_WINDOWS
5034 frame_setheight(win->w_frame, height + win->w_status_height);
5035
5036 /* recompute the window positions */
5037 row = win_comp_pos();
5038#else
5039 if (height > topframe->fr_height)
5040 height = topframe->fr_height;
5041 win->w_height = height;
5042 row = height;
5043#endif
5044
5045 /*
5046 * If there is extra space created between the last window and the command
5047 * line, clear it.
5048 */
5049 if (full_screen && msg_scrolled == 0 && row < cmdline_row)
5050 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5051 cmdline_row = row;
5052 msg_row = row;
5053 msg_col = 0;
5054
5055 redraw_all_later(NOT_VALID);
5056}
5057
5058#if defined(FEAT_WINDOWS) || defined(PROTO)
5059
5060/*
5061 * Set the height of a frame to "height" and take care that all frames and
5062 * windows inside it are resized. Also resize frames on the left and right if
5063 * the are in the same FR_ROW frame.
5064 *
5065 * Strategy:
5066 * If the frame is part of a FR_COL frame, try fitting the frame in that
5067 * frame. If that doesn't work (the FR_COL frame is too small), recursively
5068 * go to containing frames to resize them and make room.
5069 * If the frame is part of a FR_ROW frame, all frames must be resized as well.
5070 * Check for the minimal height of the FR_ROW frame.
5071 * At the top level we can also use change the command line height.
5072 */
5073 static void
5074frame_setheight(curfrp, height)
5075 frame_T *curfrp;
5076 int height;
5077{
5078 int room; /* total number of lines available */
5079 int take; /* number of lines taken from other windows */
5080 int room_cmdline; /* lines available from cmdline */
5081 int run;
5082 frame_T *frp;
5083 int h;
5084 int room_reserved;
5085
5086 /* If the height already is the desired value, nothing to do. */
5087 if (curfrp->fr_height == height)
5088 return;
5089
5090 if (curfrp->fr_parent == NULL)
5091 {
5092 /* topframe: can only change the command line */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005093 if (height > ROWS_AVAIL)
5094 height = ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095 if (height > 0)
5096 frame_new_height(curfrp, height, FALSE, FALSE);
5097 }
5098 else if (curfrp->fr_parent->fr_layout == FR_ROW)
5099 {
5100 /* Row of frames: Also need to resize frames left and right of this
5101 * one. First check for the minimal height of these. */
5102 h = frame_minheight(curfrp->fr_parent, NULL);
5103 if (height < h)
5104 height = h;
5105 frame_setheight(curfrp->fr_parent, height);
5106 }
5107 else
5108 {
5109 /*
5110 * Column of frames: try to change only frames in this column.
5111 */
5112#ifdef FEAT_VERTSPLIT
5113 /*
5114 * Do this twice:
5115 * 1: compute room available, if it's not enough try resizing the
5116 * containing frame.
5117 * 2: compute the room available and adjust the height to it.
5118 * Try not to reduce the height of a window with 'winfixheight' set.
5119 */
5120 for (run = 1; run <= 2; ++run)
5121#else
5122 for (;;)
5123#endif
5124 {
5125 room = 0;
5126 room_reserved = 0;
5127 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
5128 frp = frp->fr_next)
5129 {
5130 if (frp != curfrp
5131 && frp->fr_win != NULL
5132 && frp->fr_win->w_p_wfh)
5133 room_reserved += frp->fr_height;
5134 room += frp->fr_height;
5135 if (frp != curfrp)
5136 room -= frame_minheight(frp, NULL);
5137 }
5138#ifdef FEAT_VERTSPLIT
5139 if (curfrp->fr_width != Columns)
5140 room_cmdline = 0;
5141 else
5142#endif
5143 {
5144 room_cmdline = Rows - p_ch - (lastwin->w_winrow
5145 + lastwin->w_height + lastwin->w_status_height);
5146 if (room_cmdline < 0)
5147 room_cmdline = 0;
5148 }
5149
5150 if (height <= room + room_cmdline)
5151 break;
5152#ifdef FEAT_VERTSPLIT
5153 if (run == 2 || curfrp->fr_width == Columns)
5154#endif
5155 {
5156 if (height > room + room_cmdline)
5157 height = room + room_cmdline;
5158 break;
5159 }
5160#ifdef FEAT_VERTSPLIT
5161 frame_setheight(curfrp->fr_parent, height
5162 + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
5163#endif
5164 /*NOTREACHED*/
5165 }
5166
5167 /*
5168 * Compute the number of lines we will take from others frames (can be
5169 * negative!).
5170 */
5171 take = height - curfrp->fr_height;
5172
5173 /* If there is not enough room, also reduce the height of a window
5174 * with 'winfixheight' set. */
5175 if (height > room + room_cmdline - room_reserved)
5176 room_reserved = room + room_cmdline - height;
5177 /* If there is only a 'winfixheight' window and making the
5178 * window smaller, need to make the other window taller. */
5179 if (take < 0 && room - curfrp->fr_height < room_reserved)
5180 room_reserved = 0;
5181
5182 if (take > 0 && room_cmdline > 0)
5183 {
5184 /* use lines from cmdline first */
5185 if (take < room_cmdline)
5186 room_cmdline = take;
5187 take -= room_cmdline;
5188 topframe->fr_height += room_cmdline;
5189 }
5190
5191 /*
5192 * set the current frame to the new height
5193 */
5194 frame_new_height(curfrp, height, FALSE, FALSE);
5195
5196 /*
5197 * First take lines from the frames after the current frame. If
5198 * that is not enough, takes lines from frames above the current
5199 * frame.
5200 */
5201 for (run = 0; run < 2; ++run)
5202 {
5203 if (run == 0)
5204 frp = curfrp->fr_next; /* 1st run: start with next window */
5205 else
5206 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5207 while (frp != NULL && take != 0)
5208 {
5209 h = frame_minheight(frp, NULL);
5210 if (room_reserved > 0
5211 && frp->fr_win != NULL
5212 && frp->fr_win->w_p_wfh)
5213 {
5214 if (room_reserved >= frp->fr_height)
5215 room_reserved -= frp->fr_height;
5216 else
5217 {
5218 if (frp->fr_height - room_reserved > take)
5219 room_reserved = frp->fr_height - take;
5220 take -= frp->fr_height - room_reserved;
5221 frame_new_height(frp, room_reserved, FALSE, FALSE);
5222 room_reserved = 0;
5223 }
5224 }
5225 else
5226 {
5227 if (frp->fr_height - take < h)
5228 {
5229 take -= frp->fr_height - h;
5230 frame_new_height(frp, h, FALSE, FALSE);
5231 }
5232 else
5233 {
5234 frame_new_height(frp, frp->fr_height - take,
5235 FALSE, FALSE);
5236 take = 0;
5237 }
5238 }
5239 if (run == 0)
5240 frp = frp->fr_next;
5241 else
5242 frp = frp->fr_prev;
5243 }
5244 }
5245 }
5246}
5247
5248#if defined(FEAT_VERTSPLIT) || defined(PROTO)
5249/*
5250 * Set current window width and take care of repositioning other windows to
5251 * fit around it.
5252 */
5253 void
5254win_setwidth(width)
5255 int width;
5256{
5257 win_setwidth_win(width, curwin);
5258}
5259
5260 void
5261win_setwidth_win(width, wp)
5262 int width;
5263 win_T *wp;
5264{
5265 /* Always keep current window at least one column wide, even when
5266 * 'winminwidth' is zero. */
5267 if (wp == curwin)
5268 {
5269 if (width < p_wmw)
5270 width = p_wmw;
5271 if (width == 0)
5272 width = 1;
5273 }
5274
5275 frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
5276
5277 /* recompute the window positions */
5278 (void)win_comp_pos();
5279
5280 redraw_all_later(NOT_VALID);
5281}
5282
5283/*
5284 * Set the width of a frame to "width" and take care that all frames and
5285 * windows inside it are resized. Also resize frames above and below if the
5286 * are in the same FR_ROW frame.
5287 *
5288 * Strategy is similar to frame_setheight().
5289 */
5290 static void
5291frame_setwidth(curfrp, width)
5292 frame_T *curfrp;
5293 int width;
5294{
5295 int room; /* total number of lines available */
5296 int take; /* number of lines taken from other windows */
5297 int run;
5298 frame_T *frp;
5299 int w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005300 int room_reserved;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005301
5302 /* If the width already is the desired value, nothing to do. */
5303 if (curfrp->fr_width == width)
5304 return;
5305
5306 if (curfrp->fr_parent == NULL)
5307 /* topframe: can't change width */
5308 return;
5309
5310 if (curfrp->fr_parent->fr_layout == FR_COL)
5311 {
5312 /* Column of frames: Also need to resize frames above and below of
5313 * this one. First check for the minimal width of these. */
5314 w = frame_minwidth(curfrp->fr_parent, NULL);
5315 if (width < w)
5316 width = w;
5317 frame_setwidth(curfrp->fr_parent, width);
5318 }
5319 else
5320 {
5321 /*
5322 * Row of frames: try to change only frames in this row.
5323 *
5324 * Do this twice:
5325 * 1: compute room available, if it's not enough try resizing the
5326 * containing frame.
5327 * 2: compute the room available and adjust the width to it.
5328 */
5329 for (run = 1; run <= 2; ++run)
5330 {
5331 room = 0;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005332 room_reserved = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005333 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
5334 frp = frp->fr_next)
5335 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005336 if (frp != curfrp
5337 && frp->fr_win != NULL
5338 && frp->fr_win->w_p_wfw)
5339 room_reserved += frp->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340 room += frp->fr_width;
5341 if (frp != curfrp)
5342 room -= frame_minwidth(frp, NULL);
5343 }
5344
5345 if (width <= room)
5346 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005347 if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005348 {
5349 if (width > room)
5350 width = room;
5351 break;
5352 }
5353 frame_setwidth(curfrp->fr_parent, width
5354 + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
5355 }
5356
Bram Moolenaar071d4272004-06-13 20:20:40 +00005357 /*
5358 * Compute the number of lines we will take from others frames (can be
5359 * negative!).
5360 */
5361 take = width - curfrp->fr_width;
5362
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005363 /* If there is not enough room, also reduce the width of a window
5364 * with 'winfixwidth' set. */
5365 if (width > room - room_reserved)
5366 room_reserved = room - width;
5367 /* If there is only a 'winfixwidth' window and making the
5368 * window smaller, need to make the other window narrower. */
5369 if (take < 0 && room - curfrp->fr_width < room_reserved)
5370 room_reserved = 0;
5371
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372 /*
5373 * set the current frame to the new width
5374 */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005375 frame_new_width(curfrp, width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005376
5377 /*
5378 * First take lines from the frames right of the current frame. If
5379 * that is not enough, takes lines from frames left of the current
5380 * frame.
5381 */
5382 for (run = 0; run < 2; ++run)
5383 {
5384 if (run == 0)
5385 frp = curfrp->fr_next; /* 1st run: start with next window */
5386 else
5387 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5388 while (frp != NULL && take != 0)
5389 {
5390 w = frame_minwidth(frp, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005391 if (room_reserved > 0
5392 && frp->fr_win != NULL
5393 && frp->fr_win->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005395 if (room_reserved >= frp->fr_width)
5396 room_reserved -= frp->fr_width;
5397 else
5398 {
5399 if (frp->fr_width - room_reserved > take)
5400 room_reserved = frp->fr_width - take;
5401 take -= frp->fr_width - room_reserved;
5402 frame_new_width(frp, room_reserved, FALSE, FALSE);
5403 room_reserved = 0;
5404 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005405 }
5406 else
5407 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005408 if (frp->fr_width - take < w)
5409 {
5410 take -= frp->fr_width - w;
5411 frame_new_width(frp, w, FALSE, FALSE);
5412 }
5413 else
5414 {
5415 frame_new_width(frp, frp->fr_width - take,
5416 FALSE, FALSE);
5417 take = 0;
5418 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005419 }
5420 if (run == 0)
5421 frp = frp->fr_next;
5422 else
5423 frp = frp->fr_prev;
5424 }
5425 }
5426 }
5427}
5428#endif /* FEAT_VERTSPLIT */
5429
5430/*
5431 * Check 'winminheight' for a valid value.
5432 */
5433 void
5434win_setminheight()
5435{
5436 int room;
5437 int first = TRUE;
5438 win_T *wp;
5439
5440 /* loop until there is a 'winminheight' that is possible */
5441 while (p_wmh > 0)
5442 {
5443 /* TODO: handle vertical splits */
5444 room = -p_wh;
5445 for (wp = firstwin; wp != NULL; wp = wp->w_next)
5446 room += wp->w_height - p_wmh;
5447 if (room >= 0)
5448 break;
5449 --p_wmh;
5450 if (first)
5451 {
5452 EMSG(_(e_noroom));
5453 first = FALSE;
5454 }
5455 }
5456}
5457
5458#ifdef FEAT_MOUSE
5459
5460/*
5461 * Status line of dragwin is dragged "offset" lines down (negative is up).
5462 */
5463 void
5464win_drag_status_line(dragwin, offset)
5465 win_T *dragwin;
5466 int offset;
5467{
5468 frame_T *curfr;
5469 frame_T *fr;
5470 int room;
5471 int row;
5472 int up; /* if TRUE, drag status line up, otherwise down */
5473 int n;
5474
5475 fr = dragwin->w_frame;
5476 curfr = fr;
5477 if (fr != topframe) /* more than one window */
5478 {
5479 fr = fr->fr_parent;
5480 /* When the parent frame is not a column of frames, its parent should
5481 * be. */
5482 if (fr->fr_layout != FR_COL)
5483 {
5484 curfr = fr;
5485 if (fr != topframe) /* only a row of windows, may drag statusline */
5486 fr = fr->fr_parent;
5487 }
5488 }
5489
5490 /* If this is the last frame in a column, may want to resize the parent
5491 * frame instead (go two up to skip a row of frames). */
5492 while (curfr != topframe && curfr->fr_next == NULL)
5493 {
5494 if (fr != topframe)
5495 fr = fr->fr_parent;
5496 curfr = fr;
5497 if (fr != topframe)
5498 fr = fr->fr_parent;
5499 }
5500
5501 if (offset < 0) /* drag up */
5502 {
5503 up = TRUE;
5504 offset = -offset;
5505 /* sum up the room of the current frame and above it */
5506 if (fr == curfr)
5507 {
5508 /* only one window */
5509 room = fr->fr_height - frame_minheight(fr, NULL);
5510 }
5511 else
5512 {
5513 room = 0;
5514 for (fr = fr->fr_child; ; fr = fr->fr_next)
5515 {
5516 room += fr->fr_height - frame_minheight(fr, NULL);
5517 if (fr == curfr)
5518 break;
5519 }
5520 }
5521 fr = curfr->fr_next; /* put fr at frame that grows */
5522 }
5523 else /* drag down */
5524 {
5525 up = FALSE;
5526 /*
5527 * Only dragging the last status line can reduce p_ch.
5528 */
5529 room = Rows - cmdline_row;
5530 if (curfr->fr_next == NULL)
5531 room -= 1;
5532 else
5533 room -= p_ch;
5534 if (room < 0)
5535 room = 0;
5536 /* sum up the room of frames below of the current one */
5537 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
5538 room += fr->fr_height - frame_minheight(fr, NULL);
5539 fr = curfr; /* put fr at window that grows */
5540 }
5541
5542 if (room < offset) /* Not enough room */
5543 offset = room; /* Move as far as we can */
5544 if (offset <= 0)
5545 return;
5546
5547 /*
5548 * Grow frame fr by "offset" lines.
5549 * Doesn't happen when dragging the last status line up.
5550 */
5551 if (fr != NULL)
5552 frame_new_height(fr, fr->fr_height + offset, up, FALSE);
5553
5554 if (up)
5555 fr = curfr; /* current frame gets smaller */
5556 else
5557 fr = curfr->fr_next; /* next frame gets smaller */
5558
5559 /*
5560 * Now make the other frames smaller.
5561 */
5562 while (fr != NULL && offset > 0)
5563 {
5564 n = frame_minheight(fr, NULL);
5565 if (fr->fr_height - offset <= n)
5566 {
5567 offset -= fr->fr_height - n;
5568 frame_new_height(fr, n, !up, FALSE);
5569 }
5570 else
5571 {
5572 frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
5573 break;
5574 }
5575 if (up)
5576 fr = fr->fr_prev;
5577 else
5578 fr = fr->fr_next;
5579 }
5580 row = win_comp_pos();
5581 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5582 cmdline_row = row;
5583 p_ch = Rows - cmdline_row;
5584 if (p_ch < 1)
5585 p_ch = 1;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005586 curtab->tp_ch_used = p_ch;
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005587 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005588 showmode();
5589}
5590
5591#ifdef FEAT_VERTSPLIT
5592/*
5593 * Separator line of dragwin is dragged "offset" lines right (negative is left).
5594 */
5595 void
5596win_drag_vsep_line(dragwin, offset)
5597 win_T *dragwin;
5598 int offset;
5599{
5600 frame_T *curfr;
5601 frame_T *fr;
5602 int room;
5603 int left; /* if TRUE, drag separator line left, otherwise right */
5604 int n;
5605
5606 fr = dragwin->w_frame;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005607 if (fr == topframe) /* only one window (cannot happen?) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608 return;
5609 curfr = fr;
5610 fr = fr->fr_parent;
5611 /* When the parent frame is not a row of frames, its parent should be. */
5612 if (fr->fr_layout != FR_ROW)
5613 {
5614 if (fr == topframe) /* only a column of windows (cannot happen?) */
5615 return;
5616 curfr = fr;
5617 fr = fr->fr_parent;
5618 }
5619
5620 /* If this is the last frame in a row, may want to resize a parent
5621 * frame instead. */
5622 while (curfr->fr_next == NULL)
5623 {
5624 if (fr == topframe)
5625 break;
5626 curfr = fr;
5627 fr = fr->fr_parent;
5628 if (fr != topframe)
5629 {
5630 curfr = fr;
5631 fr = fr->fr_parent;
5632 }
5633 }
5634
5635 if (offset < 0) /* drag left */
5636 {
5637 left = TRUE;
5638 offset = -offset;
5639 /* sum up the room of the current frame and left of it */
5640 room = 0;
5641 for (fr = fr->fr_child; ; fr = fr->fr_next)
5642 {
5643 room += fr->fr_width - frame_minwidth(fr, NULL);
5644 if (fr == curfr)
5645 break;
5646 }
5647 fr = curfr->fr_next; /* put fr at frame that grows */
5648 }
5649 else /* drag right */
5650 {
5651 left = FALSE;
5652 /* sum up the room of frames right of the current one */
5653 room = 0;
5654 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
5655 room += fr->fr_width - frame_minwidth(fr, NULL);
5656 fr = curfr; /* put fr at window that grows */
5657 }
5658
5659 if (room < offset) /* Not enough room */
5660 offset = room; /* Move as far as we can */
5661 if (offset <= 0) /* No room at all, quit. */
5662 return;
5663
5664 /* grow frame fr by offset lines */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005665 frame_new_width(fr, fr->fr_width + offset, left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005666
5667 /* shrink other frames: current and at the left or at the right */
5668 if (left)
5669 fr = curfr; /* current frame gets smaller */
5670 else
5671 fr = curfr->fr_next; /* next frame gets smaller */
5672
5673 while (fr != NULL && offset > 0)
5674 {
5675 n = frame_minwidth(fr, NULL);
5676 if (fr->fr_width - offset <= n)
5677 {
5678 offset -= fr->fr_width - n;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005679 frame_new_width(fr, n, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 }
5681 else
5682 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005683 frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684 break;
5685 }
5686 if (left)
5687 fr = fr->fr_prev;
5688 else
5689 fr = fr->fr_next;
5690 }
5691 (void)win_comp_pos();
5692 redraw_all_later(NOT_VALID);
5693}
5694#endif /* FEAT_VERTSPLIT */
5695#endif /* FEAT_MOUSE */
5696
5697#endif /* FEAT_WINDOWS */
5698
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005699#define FRACTION_MULT 16384L
5700
5701/*
5702 * Set wp->w_fraction for the current w_wrow and w_height.
5703 */
5704 static void
5705set_fraction(wp)
5706 win_T *wp;
5707{
5708 wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005709 + wp->w_height / 2) / (long)wp->w_height;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005710}
5711
Bram Moolenaar071d4272004-06-13 20:20:40 +00005712/*
5713 * Set the height of a window.
5714 * This takes care of the things inside the window, not what happens to the
5715 * window position, the frame or to other windows.
5716 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005717 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00005718win_new_height(wp, height)
5719 win_T *wp;
5720 int height;
5721{
5722 linenr_T lnum;
5723 int sline, line_size;
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005724 int prev_height = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005725
5726 /* Don't want a negative height. Happens when splitting a tiny window.
5727 * Will equalize heights soon to fix it. */
5728 if (height < 0)
5729 height = 0;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00005730 if (wp->w_height == height)
5731 return; /* nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005732
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005733 if (wp->w_height > 0)
5734 {
5735 if (wp == curwin)
Bram Moolenaar0ae36a52014-06-13 20:08:45 +02005736 /* w_wrow needs to be valid. When setting 'laststatus' this may
5737 * call win_new_height() recursively. */
5738 validate_cursor();
5739 if (wp->w_height != prev_height)
5740 return; /* Recursive call already changed the size, bail out here
5741 to avoid the following to mess things up. */
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005742 if (wp->w_wrow != wp->w_prev_fraction_row)
5743 set_fraction(wp);
5744 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005745
5746 wp->w_height = height;
5747 wp->w_skipcol = 0;
5748
5749 /* Don't change w_topline when height is zero. Don't set w_topline when
5750 * 'scrollbind' is set and this isn't the current window. */
5751 if (height > 0
5752#ifdef FEAT_SCROLLBIND
5753 && (!wp->w_p_scb || wp == curwin)
5754#endif
5755 )
5756 {
Bram Moolenaar34114692005-01-02 11:28:13 +00005757 /*
5758 * Find a value for w_topline that shows the cursor at the same
5759 * relative position in the window as before (more or less).
5760 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005761 lnum = wp->w_cursor.lnum;
5762 if (lnum < 1) /* can happen when starting up */
5763 lnum = 1;
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005764 wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L
5765 + FRACTION_MULT / 2) / FRACTION_MULT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005766 line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
5767 sline = wp->w_wrow - line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005768
5769 if (sline >= 0)
5770 {
5771 /* Make sure the whole cursor line is visible, if possible. */
5772 int rows = plines_win(wp, lnum, FALSE);
5773
5774 if (sline > wp->w_height - rows)
5775 {
5776 sline = wp->w_height - rows;
5777 wp->w_wrow -= rows - line_size;
5778 }
5779 }
5780
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 if (sline < 0)
5782 {
5783 /*
5784 * Cursor line would go off top of screen if w_wrow was this high.
Bram Moolenaar26470632006-10-24 19:12:40 +00005785 * Make cursor line the first line in the window. If not enough
5786 * room use w_skipcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787 */
5788 wp->w_wrow = line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005789 if (wp->w_wrow >= wp->w_height
5790 && (W_WIDTH(wp) - win_col_off(wp)) > 0)
5791 {
5792 wp->w_skipcol += W_WIDTH(wp) - win_col_off(wp);
5793 --wp->w_wrow;
5794 while (wp->w_wrow >= wp->w_height)
5795 {
5796 wp->w_skipcol += W_WIDTH(wp) - win_col_off(wp)
5797 + win_col_off2(wp);
5798 --wp->w_wrow;
5799 }
5800 }
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005801 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005803 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005804 {
Bram Moolenaar26470632006-10-24 19:12:40 +00005805 while (sline > 0 && lnum > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005806 {
5807#ifdef FEAT_FOLDING
5808 hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
5809 if (lnum == 1)
5810 {
5811 /* first line in buffer is folded */
5812 line_size = 1;
5813 --sline;
5814 break;
5815 }
5816#endif
5817 --lnum;
5818#ifdef FEAT_DIFF
5819 if (lnum == wp->w_topline)
5820 line_size = plines_win_nofill(wp, lnum, TRUE)
5821 + wp->w_topfill;
5822 else
5823#endif
5824 line_size = plines_win(wp, lnum, TRUE);
5825 sline -= line_size;
5826 }
Bram Moolenaar34114692005-01-02 11:28:13 +00005827
Bram Moolenaar071d4272004-06-13 20:20:40 +00005828 if (sline < 0)
5829 {
5830 /*
5831 * Line we want at top would go off top of screen. Use next
5832 * line instead.
5833 */
5834#ifdef FEAT_FOLDING
5835 hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
5836#endif
5837 lnum++;
5838 wp->w_wrow -= line_size + sline;
5839 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005840 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005841 {
5842 /* First line of file reached, use that as topline. */
5843 lnum = 1;
5844 wp->w_wrow -= sline;
5845 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005846
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005847 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005848 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849 }
5850
5851 if (wp == curwin)
5852 {
5853 if (p_so)
5854 update_topline();
5855 curs_columns(FALSE); /* validate w_wrow */
5856 }
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005857 if (prev_height > 0)
5858 wp->w_prev_fraction_row = wp->w_wrow;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005859
5860 win_comp_scroll(wp);
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005861 redraw_win_later(wp, SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005862#ifdef FEAT_WINDOWS
5863 wp->w_redr_status = TRUE;
5864#endif
5865 invalidate_botline_win(wp);
5866}
5867
5868#ifdef FEAT_VERTSPLIT
5869/*
5870 * Set the width of a window.
5871 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005872 void
Bram Moolenaar071d4272004-06-13 20:20:40 +00005873win_new_width(wp, width)
5874 win_T *wp;
5875 int width;
5876{
5877 wp->w_width = width;
5878 wp->w_lines_valid = 0;
5879 changed_line_abv_curs_win(wp);
5880 invalidate_botline_win(wp);
5881 if (wp == curwin)
5882 {
5883 update_topline();
5884 curs_columns(TRUE); /* validate w_wrow */
5885 }
5886 redraw_win_later(wp, NOT_VALID);
5887 wp->w_redr_status = TRUE;
5888}
5889#endif
5890
5891 void
5892win_comp_scroll(wp)
5893 win_T *wp;
5894{
5895 wp->w_p_scr = ((unsigned)wp->w_height >> 1);
5896 if (wp->w_p_scr == 0)
5897 wp->w_p_scr = 1;
5898}
5899
5900/*
5901 * command_height: called whenever p_ch has been changed
5902 */
5903 void
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005904command_height()
Bram Moolenaar071d4272004-06-13 20:20:40 +00005905{
5906#ifdef FEAT_WINDOWS
5907 int h;
5908 frame_T *frp;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005909 int old_p_ch = curtab->tp_ch_used;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005910
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005911 /* Use the value of p_ch that we remembered. This is needed for when the
5912 * GUI starts up, we can't be sure in what order things happen. And when
5913 * p_ch was changed in another tab page. */
5914 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00005915
Bram Moolenaar071d4272004-06-13 20:20:40 +00005916 /* Find bottom frame with width of screen. */
5917 frp = lastwin->w_frame;
5918# ifdef FEAT_VERTSPLIT
5919 while (frp->fr_width != Columns && frp->fr_parent != NULL)
5920 frp = frp->fr_parent;
5921# endif
5922
5923 /* Avoid changing the height of a window with 'winfixheight' set. */
5924 while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
5925 && frp->fr_win->w_p_wfh)
5926 frp = frp->fr_prev;
5927
5928 if (starting != NO_SCREEN)
5929 {
5930 cmdline_row = Rows - p_ch;
5931
5932 if (p_ch > old_p_ch) /* p_ch got bigger */
5933 {
5934 while (p_ch > old_p_ch)
5935 {
5936 if (frp == NULL)
5937 {
5938 EMSG(_(e_noroom));
5939 p_ch = old_p_ch;
Bram Moolenaar719939c2007-09-25 12:51:28 +00005940 curtab->tp_ch_used = p_ch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941 cmdline_row = Rows - p_ch;
5942 break;
5943 }
5944 h = frp->fr_height - frame_minheight(frp, NULL);
5945 if (h > p_ch - old_p_ch)
5946 h = p_ch - old_p_ch;
5947 old_p_ch += h;
5948 frame_add_height(frp, -h);
5949 frp = frp->fr_prev;
5950 }
5951
5952 /* Recompute window positions. */
5953 (void)win_comp_pos();
5954
5955 /* clear the lines added to cmdline */
5956 if (full_screen)
5957 screen_fill((int)(cmdline_row), (int)Rows, 0,
5958 (int)Columns, ' ', ' ', 0);
5959 msg_row = cmdline_row;
5960 redraw_cmdline = TRUE;
5961 return;
5962 }
5963
5964 if (msg_row < cmdline_row)
5965 msg_row = cmdline_row;
5966 redraw_cmdline = TRUE;
5967 }
5968 frame_add_height(frp, (int)(old_p_ch - p_ch));
5969
5970 /* Recompute window positions. */
5971 if (frp != lastwin->w_frame)
5972 (void)win_comp_pos();
5973#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005974 cmdline_row = Rows - p_ch;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005975 win_setheight(cmdline_row);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005976#endif
5977}
5978
5979#if defined(FEAT_WINDOWS) || defined(PROTO)
5980/*
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
5985frame_add_height(frp, n)
5986 frame_T *frp;
5987 int n;
5988{
5989 frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
5990 for (;;)
5991 {
5992 frp = frp->fr_parent;
5993 if (frp == NULL)
5994 break;
5995 frp->fr_height += n;
5996 }
5997}
5998
5999/*
6000 * Add or remove a status line for the bottom window(s), according to the
6001 * value of 'laststatus'.
6002 */
6003 void
6004last_status(morewin)
6005 int morewin; /* pretend there are two or more windows */
6006{
6007 /* Don't make a difference between horizontal or vertical split. */
6008 last_status_rec(topframe, (p_ls == 2
6009 || (p_ls == 1 && (morewin || lastwin != firstwin))));
6010}
6011
6012 static void
6013last_status_rec(fr, statusline)
6014 frame_T *fr;
6015 int statusline;
6016{
6017 frame_T *fp;
6018 win_T *wp;
6019
6020 if (fr->fr_layout == FR_LEAF)
6021 {
6022 wp = fr->fr_win;
6023 if (wp->w_status_height != 0 && !statusline)
6024 {
6025 /* remove status line */
6026 win_new_height(wp, wp->w_height + 1);
6027 wp->w_status_height = 0;
6028 comp_col();
6029 }
6030 else if (wp->w_status_height == 0 && statusline)
6031 {
6032 /* Find a frame to take a line from. */
6033 fp = fr;
6034 while (fp->fr_height <= frame_minheight(fp, NULL))
6035 {
6036 if (fp == topframe)
6037 {
6038 EMSG(_(e_noroom));
6039 return;
6040 }
6041 /* In a column of frames: go to frame above. If already at
6042 * the top or in a row of frames: go to parent. */
6043 if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
6044 fp = fp->fr_prev;
6045 else
6046 fp = fp->fr_parent;
6047 }
6048 wp->w_status_height = 1;
6049 if (fp != fr)
6050 {
6051 frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
6052 frame_fix_height(wp);
6053 (void)win_comp_pos();
6054 }
6055 else
6056 win_new_height(wp, wp->w_height - 1);
6057 comp_col();
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00006058 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059 }
6060 }
6061#ifdef FEAT_VERTSPLIT
6062 else if (fr->fr_layout == FR_ROW)
6063 {
6064 /* vertically split windows, set status line for each one */
6065 for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
6066 last_status_rec(fp, statusline);
6067 }
6068#endif
6069 else
6070 {
6071 /* horizontally split window, set status line for last one */
6072 for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
6073 ;
6074 last_status_rec(fp, statusline);
6075 }
6076}
6077
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006078/*
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006079 * Return the number of lines used by the tab page line.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006080 */
6081 int
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006082tabline_height()
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006083{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006084#ifdef FEAT_GUI_TABLINE
6085 /* When the GUI has the tabline then this always returns zero. */
6086 if (gui_use_tabline())
6087 return 0;
6088#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00006089 switch (p_stal)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006090 {
6091 case 0: return 0;
6092 case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
6093 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006094 return 1;
6095}
6096
Bram Moolenaar071d4272004-06-13 20:20:40 +00006097#endif /* FEAT_WINDOWS */
6098
6099#if defined(FEAT_SEARCHPATH) || defined(PROTO)
6100/*
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006101 * Get the file name at the cursor.
6102 * If Visual mode is active, use the selected text if it's in one line.
6103 * Returns the name in allocated memory, NULL for failure.
6104 */
6105 char_u *
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006106grab_file_name(count, file_lnum)
6107 long count;
6108 linenr_T *file_lnum;
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006109{
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006110 if (VIsual_active)
6111 {
6112 int len;
6113 char_u *ptr;
6114
6115 if (get_visual_text(NULL, &ptr, &len) == FAIL)
6116 return NULL;
6117 return find_file_name_in_path(ptr, len,
6118 FNAME_MESS|FNAME_EXP|FNAME_REL, count, curbuf->b_ffname);
6119 }
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006120 return file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP|FNAME_REL, count,
6121 file_lnum);
6122
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006123}
6124
6125/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006126 * Return the file name under or after the cursor.
6127 *
6128 * The 'path' option is searched if the file name is not absolute.
6129 * The string returned has been alloc'ed and should be freed by the caller.
6130 * NULL is returned if the file name or file is not found.
6131 *
6132 * options:
6133 * FNAME_MESS give error messages
6134 * FNAME_EXP expand to path
6135 * FNAME_HYP check for hypertext link
6136 * FNAME_INCL apply "includeexpr"
6137 */
6138 char_u *
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006139file_name_at_cursor(options, count, file_lnum)
6140 int options;
6141 long count;
6142 linenr_T *file_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006143{
6144 return file_name_in_line(ml_get_curline(),
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006145 curwin->w_cursor.col, options, count, curbuf->b_ffname,
6146 file_lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006147}
6148
6149/*
6150 * Return the name of the file under or after ptr[col].
6151 * Otherwise like file_name_at_cursor().
6152 */
6153 char_u *
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006154file_name_in_line(line, col, options, count, rel_fname, file_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006155 char_u *line;
6156 int col;
6157 int options;
6158 long count;
6159 char_u *rel_fname; /* file we are searching relative to */
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006160 linenr_T *file_lnum; /* line number after the file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006161{
6162 char_u *ptr;
6163 int len;
6164
6165 /*
6166 * search forward for what could be the start of a file name
6167 */
6168 ptr = line + col;
6169 while (*ptr != NUL && !vim_isfilec(*ptr))
Bram Moolenaar0dd492f2005-06-22 22:25:07 +00006170 mb_ptr_adv(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171 if (*ptr == NUL) /* nothing found */
6172 {
6173 if (options & FNAME_MESS)
6174 EMSG(_("E446: No file name under cursor"));
6175 return NULL;
6176 }
6177
6178 /*
6179 * Search backward for first char of the file name.
6180 * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
6181 */
6182 while (ptr > line)
6183 {
6184#ifdef FEAT_MBYTE
6185 if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
6186 ptr -= len + 1;
6187 else
6188#endif
6189 if (vim_isfilec(ptr[-1])
6190 || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
6191 --ptr;
6192 else
6193 break;
6194 }
6195
6196 /*
6197 * Search forward for the last char of the file name.
6198 * Also allow "://" when ':' is not in 'isfname'.
6199 */
6200 len = 0;
6201 while (vim_isfilec(ptr[len])
6202 || ((options & FNAME_HYP) && path_is_url(ptr + len)))
6203#ifdef FEAT_MBYTE
6204 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006205 len += (*mb_ptr2len)(ptr + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006206 else
6207#endif
6208 ++len;
6209
6210 /*
6211 * If there is trailing punctuation, remove it.
6212 * But don't remove "..", could be a directory name.
6213 */
6214 if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
6215 && ptr[len - 2] != '.')
6216 --len;
6217
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006218 if (file_lnum != NULL)
6219 {
6220 char_u *p;
6221
6222 /* Get the number after the file name and a separator character */
6223 p = ptr + len;
6224 p = skipwhite(p);
6225 if (*p != NUL)
6226 {
6227 if (!isdigit(*p))
6228 ++p; /* skip the separator */
6229 p = skipwhite(p);
6230 if (isdigit(*p))
6231 *file_lnum = (int)getdigits(&p);
6232 }
6233 }
6234
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235 return find_file_name_in_path(ptr, len, options, count, rel_fname);
6236}
6237
6238# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6239static char_u *eval_includeexpr __ARGS((char_u *ptr, int len));
6240
6241 static char_u *
6242eval_includeexpr(ptr, len)
6243 char_u *ptr;
6244 int len;
6245{
6246 char_u *res;
6247
6248 set_vim_var_string(VV_FNAME, ptr, len);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00006249 res = eval_to_string_safe(curbuf->b_p_inex, NULL,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006250 was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006251 set_vim_var_string(VV_FNAME, NULL, 0);
6252 return res;
6253}
6254#endif
6255
6256/*
6257 * Return the name of the file ptr[len] in 'path'.
6258 * Otherwise like file_name_at_cursor().
6259 */
6260 char_u *
6261find_file_name_in_path(ptr, len, options, count, rel_fname)
6262 char_u *ptr;
6263 int len;
6264 int options;
6265 long count;
6266 char_u *rel_fname; /* file we are searching relative to */
6267{
6268 char_u *file_name;
6269 int c;
6270# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6271 char_u *tofree = NULL;
6272
6273 if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
6274 {
6275 tofree = eval_includeexpr(ptr, len);
6276 if (tofree != NULL)
6277 {
6278 ptr = tofree;
6279 len = (int)STRLEN(ptr);
6280 }
6281 }
6282# endif
6283
6284 if (options & FNAME_EXP)
6285 {
6286 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
6287 TRUE, rel_fname);
6288
6289# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6290 /*
6291 * If the file could not be found in a normal way, try applying
6292 * 'includeexpr' (unless done already).
6293 */
6294 if (file_name == NULL
6295 && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
6296 {
6297 tofree = eval_includeexpr(ptr, len);
6298 if (tofree != NULL)
6299 {
6300 ptr = tofree;
6301 len = (int)STRLEN(ptr);
6302 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
6303 TRUE, rel_fname);
6304 }
6305 }
6306# endif
6307 if (file_name == NULL && (options & FNAME_MESS))
6308 {
6309 c = ptr[len];
6310 ptr[len] = NUL;
6311 EMSG2(_("E447: Can't find file \"%s\" in path"), ptr);
6312 ptr[len] = c;
6313 }
6314
6315 /* Repeat finding the file "count" times. This matters when it
6316 * appears several times in the path. */
6317 while (file_name != NULL && --count > 0)
6318 {
6319 vim_free(file_name);
6320 file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
6321 }
6322 }
6323 else
6324 file_name = vim_strnsave(ptr, len);
6325
6326# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6327 vim_free(tofree);
6328# endif
6329
6330 return file_name;
6331}
6332#endif /* FEAT_SEARCHPATH */
6333
6334/*
6335 * Check if the "://" of a URL is at the pointer, return URL_SLASH.
6336 * Also check for ":\\", which MS Internet Explorer accepts, return
6337 * URL_BACKSLASH.
6338 */
6339 static int
6340path_is_url(p)
6341 char_u *p;
6342{
6343 if (STRNCMP(p, "://", (size_t)3) == 0)
6344 return URL_SLASH;
6345 else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
6346 return URL_BACKSLASH;
6347 return 0;
6348}
6349
6350/*
6351 * Check if "fname" starts with "name://". Return URL_SLASH if it does.
6352 * Return URL_BACKSLASH for "name:\\".
6353 * Return zero otherwise.
6354 */
6355 int
6356path_with_url(fname)
6357 char_u *fname;
6358{
6359 char_u *p;
6360
6361 for (p = fname; isalpha(*p); ++p)
6362 ;
6363 return path_is_url(p);
6364}
6365
6366/*
6367 * Return TRUE if "name" is a full (absolute) path name or URL.
6368 */
6369 int
6370vim_isAbsName(name)
6371 char_u *name;
6372{
6373 return (path_with_url(name) != 0 || mch_isFullName(name));
6374}
6375
6376/*
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00006377 * Get absolute file name into buffer "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006378 *
6379 * return FAIL for failure, OK otherwise
6380 */
6381 int
6382vim_FullName(fname, buf, len, force)
6383 char_u *fname, *buf;
6384 int len;
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00006385 int force; /* force expansion even when already absolute */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006386{
6387 int retval = OK;
6388 int url;
6389
6390 *buf = NUL;
6391 if (fname == NULL)
6392 return FAIL;
6393
6394 url = path_with_url(fname);
6395 if (!url)
6396 retval = mch_FullName(fname, buf, len, force);
6397 if (url || retval == FAIL)
6398 {
6399 /* something failed; use the file name (truncate when too long) */
Bram Moolenaarb6356332005-07-18 21:40:44 +00006400 vim_strncpy(buf, fname, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006401 }
6402#if defined(MACOS_CLASSIC) || defined(OS2) || defined(MSDOS) || defined(MSWIN)
6403 slash_adjust(buf);
6404#endif
6405 return retval;
6406}
6407
6408/*
6409 * Return the minimal number of rows that is needed on the screen to display
6410 * the current number of windows.
6411 */
6412 int
6413min_rows()
6414{
6415 int total;
Bram Moolenaarf740b292006-02-16 22:11:02 +00006416#ifdef FEAT_WINDOWS
6417 tabpage_T *tp;
6418 int n;
6419#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006420
6421 if (firstwin == NULL) /* not initialized yet */
6422 return MIN_LINES;
6423
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00006425 total = 0;
6426 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
6427 {
6428 n = frame_minheight(tp->tp_topframe, NULL);
6429 if (total < n)
6430 total = n;
6431 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006432 total += tabline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433#else
Bram Moolenaarf740b292006-02-16 22:11:02 +00006434 total = 1; /* at least one window should have a line! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435#endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00006436 total += 1; /* count the room for the command line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437 return total;
6438}
6439
6440/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00006441 * Return TRUE if there is only one window (in the current tab page), not
6442 * counting a help or preview window, unless it is the current window.
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006443 * Does not count "aucmd_win".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006444 */
6445 int
6446only_one_window()
6447{
6448#ifdef FEAT_WINDOWS
6449 int count = 0;
6450 win_T *wp;
6451
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006452 /* If there is another tab page there always is another window. */
6453 if (first_tabpage->tp_next != NULL)
6454 return FALSE;
6455
Bram Moolenaar071d4272004-06-13 20:20:40 +00006456 for (wp = firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar802418d2013-01-17 14:00:11 +01006457 if (wp->w_buffer != NULL
6458 && (!((wp->w_buffer->b_help && !curbuf->b_help)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006459# ifdef FEAT_QUICKFIX
6460 || wp->w_p_pvw
6461# endif
6462 ) || wp == curwin)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006463# ifdef FEAT_AUTOCMD
6464 && wp != aucmd_win
6465# endif
6466 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00006467 ++count;
6468 return (count <= 1);
6469#else
6470 return TRUE;
6471#endif
6472}
6473
6474#if defined(FEAT_WINDOWS) || defined(FEAT_AUTOCMD) || defined(PROTO)
6475/*
6476 * Correct the cursor line number in other windows. Used after changing the
6477 * current buffer, and before applying autocommands.
6478 * When "do_curwin" is TRUE, also check current window.
6479 */
6480 void
6481check_lnums(do_curwin)
6482 int do_curwin;
6483{
6484 win_T *wp;
6485
6486#ifdef FEAT_WINDOWS
Bram Moolenaarf740b292006-02-16 22:11:02 +00006487 tabpage_T *tp;
6488
6489 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006490 if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
6491#else
6492 wp = curwin;
6493 if (do_curwin)
6494#endif
6495 {
6496 if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6497 wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6498 if (wp->w_topline > curbuf->b_ml.ml_line_count)
6499 wp->w_topline = curbuf->b_ml.ml_line_count;
6500 }
6501}
6502#endif
6503
6504#if defined(FEAT_WINDOWS) || defined(PROTO)
6505
6506/*
6507 * A snapshot of the window sizes, to restore them after closing the help
6508 * window.
6509 * Only these fields are used:
6510 * fr_layout
6511 * fr_width
6512 * fr_height
6513 * fr_next
6514 * fr_child
6515 * fr_win (only valid for the old curwin, NULL otherwise)
6516 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517
6518/*
6519 * Create a snapshot of the current frame sizes.
6520 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006521 void
6522make_snapshot(idx)
6523 int idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006524{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006525 clear_snapshot(curtab, idx);
6526 make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006527}
6528
6529 static void
6530make_snapshot_rec(fr, frp)
6531 frame_T *fr;
6532 frame_T **frp;
6533{
6534 *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
6535 if (*frp == NULL)
6536 return;
6537 (*frp)->fr_layout = fr->fr_layout;
6538# ifdef FEAT_VERTSPLIT
6539 (*frp)->fr_width = fr->fr_width;
6540# endif
6541 (*frp)->fr_height = fr->fr_height;
6542 if (fr->fr_next != NULL)
6543 make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
6544 if (fr->fr_child != NULL)
6545 make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
6546 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
6547 (*frp)->fr_win = curwin;
6548}
6549
6550/*
6551 * Remove any existing snapshot.
6552 */
6553 static void
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006554clear_snapshot(tp, idx)
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00006555 tabpage_T *tp;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006556 int idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006557{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006558 clear_snapshot_rec(tp->tp_snapshot[idx]);
6559 tp->tp_snapshot[idx] = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560}
6561
6562 static void
6563clear_snapshot_rec(fr)
6564 frame_T *fr;
6565{
6566 if (fr != NULL)
6567 {
6568 clear_snapshot_rec(fr->fr_next);
6569 clear_snapshot_rec(fr->fr_child);
6570 vim_free(fr);
6571 }
6572}
6573
6574/*
6575 * Restore a previously created snapshot, if there is any.
6576 * This is only done if the screen size didn't change and the window layout is
6577 * still the same.
6578 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006579 void
6580restore_snapshot(idx, close_curwin)
6581 int idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 int close_curwin; /* closing current window */
6583{
6584 win_T *wp;
6585
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006586 if (curtab->tp_snapshot[idx] != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006587# ifdef FEAT_VERTSPLIT
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006588 && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
Bram Moolenaar071d4272004-06-13 20:20:40 +00006589# endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006590 && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
6591 && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006592 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006593 wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006594 win_comp_pos();
6595 if (wp != NULL && close_curwin)
6596 win_goto(wp);
6597 redraw_all_later(CLEAR);
6598 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006599 clear_snapshot(curtab, idx);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006600}
6601
6602/*
6603 * Check if frames "sn" and "fr" have the same layout, same following frames
6604 * and same children.
6605 */
6606 static int
6607check_snapshot_rec(sn, fr)
6608 frame_T *sn;
6609 frame_T *fr;
6610{
6611 if (sn->fr_layout != fr->fr_layout
6612 || (sn->fr_next == NULL) != (fr->fr_next == NULL)
6613 || (sn->fr_child == NULL) != (fr->fr_child == NULL)
6614 || (sn->fr_next != NULL
6615 && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
6616 || (sn->fr_child != NULL
6617 && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL))
6618 return FAIL;
6619 return OK;
6620}
6621
6622/*
6623 * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all
6624 * following frames and children.
6625 * Returns a pointer to the old current window, or NULL.
6626 */
6627 static win_T *
6628restore_snapshot_rec(sn, fr)
6629 frame_T *sn;
6630 frame_T *fr;
6631{
6632 win_T *wp = NULL;
6633 win_T *wp2;
6634
6635 fr->fr_height = sn->fr_height;
6636# ifdef FEAT_VERTSPLIT
6637 fr->fr_width = sn->fr_width;
6638# endif
6639 if (fr->fr_layout == FR_LEAF)
6640 {
6641 frame_new_height(fr, fr->fr_height, FALSE, FALSE);
6642# ifdef FEAT_VERTSPLIT
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00006643 frame_new_width(fr, fr->fr_width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006644# endif
6645 wp = sn->fr_win;
6646 }
6647 if (sn->fr_next != NULL)
6648 {
6649 wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
6650 if (wp2 != NULL)
6651 wp = wp2;
6652 }
6653 if (sn->fr_child != NULL)
6654 {
6655 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
6656 if (wp2 != NULL)
6657 wp = wp2;
6658 }
6659 return wp;
6660}
6661
6662#endif
6663
Bram Moolenaar95064ec2013-07-17 17:15:25 +02006664#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
6665 || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006666/*
6667 * Set "win" to be the curwin and "tp" to be the current tab page.
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02006668 * restore_win() MUST be called to undo, also when FAIL is returned.
6669 * No autocommands will be executed until restore_win() is called.
Bram Moolenaard6949742013-06-16 14:18:28 +02006670 * When "no_display" is TRUE the display won't be affected, no redraw is
6671 * triggered, another tabpage access is limited.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006672 * Returns FAIL if switching to "win" failed.
6673 */
6674 int
Bram Moolenaard6949742013-06-16 14:18:28 +02006675switch_win(save_curwin, save_curtab, win, tp, no_display)
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02006676 win_T **save_curwin UNUSED;
6677 tabpage_T **save_curtab UNUSED;
6678 win_T *win UNUSED;
6679 tabpage_T *tp UNUSED;
6680 int no_display UNUSED;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006681{
6682# ifdef FEAT_AUTOCMD
6683 block_autocmds();
6684# endif
6685# ifdef FEAT_WINDOWS
6686 *save_curwin = curwin;
6687 if (tp != NULL)
6688 {
6689 *save_curtab = curtab;
Bram Moolenaard6949742013-06-16 14:18:28 +02006690 if (no_display)
6691 {
6692 curtab->tp_firstwin = firstwin;
6693 curtab->tp_lastwin = lastwin;
6694 curtab = tp;
6695 firstwin = curtab->tp_firstwin;
6696 lastwin = curtab->tp_lastwin;
6697 }
6698 else
6699 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar105bc352013-05-17 16:03:57 +02006700 }
6701 if (!win_valid(win))
Bram Moolenaar105bc352013-05-17 16:03:57 +02006702 return FAIL;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006703 curwin = win;
6704 curbuf = curwin->w_buffer;
6705# endif
6706 return OK;
6707}
6708
6709/*
6710 * Restore current tabpage and window saved by switch_win(), if still valid.
Bram Moolenaard6949742013-06-16 14:18:28 +02006711 * When "no_display" is TRUE the display won't be affected, no redraw is
6712 * triggered.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006713 */
6714 void
Bram Moolenaard6949742013-06-16 14:18:28 +02006715restore_win(save_curwin, save_curtab, no_display)
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02006716 win_T *save_curwin UNUSED;
6717 tabpage_T *save_curtab UNUSED;
6718 int no_display UNUSED;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006719{
6720# ifdef FEAT_WINDOWS
6721 if (save_curtab != NULL && valid_tabpage(save_curtab))
Bram Moolenaard6949742013-06-16 14:18:28 +02006722 {
6723 if (no_display)
6724 {
6725 curtab->tp_firstwin = firstwin;
6726 curtab->tp_lastwin = lastwin;
6727 curtab = save_curtab;
6728 firstwin = curtab->tp_firstwin;
6729 lastwin = curtab->tp_lastwin;
6730 }
6731 else
6732 goto_tabpage_tp(save_curtab, FALSE, FALSE);
6733 }
Bram Moolenaar105bc352013-05-17 16:03:57 +02006734 if (win_valid(save_curwin))
6735 {
6736 curwin = save_curwin;
6737 curbuf = curwin->w_buffer;
6738 }
6739# endif
6740# ifdef FEAT_AUTOCMD
6741 unblock_autocmds();
6742# endif
6743}
6744
6745/*
6746 * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
6747 * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
6748 */
6749 void
6750switch_buffer(save_curbuf, buf)
6751 buf_T *buf;
6752 buf_T **save_curbuf;
6753{
6754# ifdef FEAT_AUTOCMD
6755 block_autocmds();
6756# endif
6757 *save_curbuf = curbuf;
6758 --curbuf->b_nwindows;
6759 curbuf = buf;
6760 curwin->w_buffer = buf;
6761 ++curbuf->b_nwindows;
6762}
6763
6764/*
6765 * Restore the current buffer after using switch_buffer().
6766 */
6767 void
6768restore_buffer(save_curbuf)
6769 buf_T *save_curbuf;
6770{
6771# ifdef FEAT_AUTOCMD
6772 unblock_autocmds();
6773# endif
6774 /* Check for valid buffer, just in case. */
6775 if (buf_valid(save_curbuf))
6776 {
6777 --curbuf->b_nwindows;
6778 curwin->w_buffer = save_curbuf;
6779 curbuf = save_curbuf;
6780 ++curbuf->b_nwindows;
6781 }
6782}
6783#endif
6784
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785#if (defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)) || defined(PROTO)
6786/*
6787 * Return TRUE if there is any vertically split window.
6788 */
6789 int
6790win_hasvertsplit()
6791{
6792 frame_T *fr;
6793
6794 if (topframe->fr_layout == FR_ROW)
6795 return TRUE;
6796
6797 if (topframe->fr_layout == FR_COL)
6798 for (fr = topframe->fr_child; fr != NULL; fr = fr->fr_next)
6799 if (fr->fr_layout == FR_ROW)
6800 return TRUE;
6801
6802 return FALSE;
6803}
6804#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006805
6806#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
6807/*
6808 * Add match to the match list of window 'wp'. The pattern 'pat' will be
Bram Moolenaare37d50a2008-08-06 17:06:04 +00006809 * highlighted with the group 'grp' with priority 'prio'.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006810 * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
6811 * If no particular ID is desired, -1 must be specified for 'id'.
6812 * Return ID of added match, -1 on failure.
6813 */
6814 int
Bram Moolenaarb3414592014-06-17 17:48:32 +02006815match_add(wp, grp, pat, prio, id, pos_list)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006816 win_T *wp;
6817 char_u *grp;
6818 char_u *pat;
6819 int prio;
6820 int id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006821 list_T *pos_list;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006822{
Bram Moolenaarb3414592014-06-17 17:48:32 +02006823 matchitem_T *cur;
6824 matchitem_T *prev;
6825 matchitem_T *m;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006826 int hlg_id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006827 regprog_T *regprog = NULL;
6828 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006829
Bram Moolenaarb3414592014-06-17 17:48:32 +02006830 if (*grp == NUL || (pat != NULL && *pat == NUL))
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006831 return -1;
6832 if (id < -1 || id == 0)
6833 {
6834 EMSGN("E799: Invalid ID: %ld (must be greater than or equal to 1)", id);
6835 return -1;
6836 }
6837 if (id != -1)
6838 {
6839 cur = wp->w_match_head;
6840 while (cur != NULL)
6841 {
6842 if (cur->id == id)
6843 {
6844 EMSGN("E801: ID already taken: %ld", id);
6845 return -1;
6846 }
6847 cur = cur->next;
6848 }
6849 }
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00006850 if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006851 {
6852 EMSG2(_(e_nogroup), grp);
6853 return -1;
6854 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006855 if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006856 {
6857 EMSG2(_(e_invarg2), pat);
6858 return -1;
6859 }
6860
6861 /* Find available match ID. */
6862 while (id == -1)
6863 {
6864 cur = wp->w_match_head;
6865 while (cur != NULL && cur->id != wp->w_next_match_id)
6866 cur = cur->next;
6867 if (cur == NULL)
6868 id = wp->w_next_match_id;
6869 wp->w_next_match_id++;
6870 }
6871
6872 /* Build new match. */
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006873 m = (matchitem_T *)alloc_clear(sizeof(matchitem_T));
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006874 m->id = id;
6875 m->priority = prio;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006876 m->pattern = pat == NULL ? NULL : vim_strsave(pat);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006877 m->hlg_id = hlg_id;
Bram Moolenaar0963cd92007-08-05 16:49:43 +00006878 m->match.regprog = regprog;
6879 m->match.rmm_ic = FALSE;
6880 m->match.rmm_maxcol = 0;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006881
Bram Moolenaarb3414592014-06-17 17:48:32 +02006882 /* Set up position matches */
6883 if (pos_list != NULL)
6884 {
6885 linenr_T toplnum = 0;
6886 linenr_T botlnum = 0;
6887 listitem_T *li;
6888 int i;
6889
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006890 for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006891 i++, li = li->li_next)
6892 {
6893 linenr_T lnum = 0;
6894 colnr_T col = 0;
6895 int len = 1;
6896 list_T *subl;
6897 listitem_T *subli;
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006898 int error = FALSE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006899
Bram Moolenaarb3414592014-06-17 17:48:32 +02006900 if (li->li_tv.v_type == VAR_LIST)
6901 {
6902 subl = li->li_tv.vval.v_list;
6903 if (subl == NULL)
6904 goto fail;
6905 subli = subl->lv_first;
6906 if (subli == NULL)
6907 goto fail;
6908 lnum = get_tv_number_chk(&subli->li_tv, &error);
6909 if (error == TRUE)
6910 goto fail;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006911 if (lnum == 0)
6912 {
6913 --i;
6914 continue;
6915 }
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006916 m->pos.pos[i].lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006917 subli = subli->li_next;
6918 if (subli != NULL)
6919 {
6920 col = get_tv_number_chk(&subli->li_tv, &error);
6921 if (error == TRUE)
6922 goto fail;
6923 subli = subli->li_next;
6924 if (subli != NULL)
6925 {
6926 len = get_tv_number_chk(&subli->li_tv, &error);
6927 if (error == TRUE)
6928 goto fail;
6929 }
6930 }
6931 m->pos.pos[i].col = col;
6932 m->pos.pos[i].len = len;
6933 }
6934 else if (li->li_tv.v_type == VAR_NUMBER)
6935 {
6936 if (li->li_tv.vval.v_number == 0)
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006937 {
6938 --i;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006939 continue;
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006940 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006941 m->pos.pos[i].lnum = li->li_tv.vval.v_number;
6942 m->pos.pos[i].col = 0;
6943 m->pos.pos[i].len = 0;
6944 }
6945 else
6946 {
6947 EMSG(_("List or number required"));
6948 goto fail;
6949 }
6950 if (toplnum == 0 || lnum < toplnum)
6951 toplnum = lnum;
Bram Moolenaar41d75232014-06-25 17:58:11 +02006952 if (botlnum == 0 || lnum >= botlnum)
6953 botlnum = lnum + 1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006954 }
6955
6956 /* Calculate top and bottom lines for redrawing area */
6957 if (toplnum != 0)
6958 {
6959 if (wp->w_buffer->b_mod_set)
6960 {
6961 if (wp->w_buffer->b_mod_top > toplnum)
6962 wp->w_buffer->b_mod_top = toplnum;
6963 if (wp->w_buffer->b_mod_bot < botlnum)
6964 wp->w_buffer->b_mod_bot = botlnum;
6965 }
6966 else
6967 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02006968 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006969 wp->w_buffer->b_mod_top = toplnum;
6970 wp->w_buffer->b_mod_bot = botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02006971 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006972 }
6973 m->pos.toplnum = toplnum;
6974 m->pos.botlnum = botlnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006975 rtype = VALID;
6976 }
6977 }
6978
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006979 /* Insert new match. The match list is in ascending order with regard to
6980 * the match priorities. */
6981 cur = wp->w_match_head;
6982 prev = cur;
6983 while (cur != NULL && prio >= cur->priority)
6984 {
6985 prev = cur;
6986 cur = cur->next;
6987 }
6988 if (cur == prev)
6989 wp->w_match_head = m;
6990 else
6991 prev->next = m;
6992 m->next = cur;
6993
Bram Moolenaarb3414592014-06-17 17:48:32 +02006994 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006995 return id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006996
6997fail:
6998 vim_free(m);
6999 return -1;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007000}
7001
7002/*
7003 * Delete match with ID 'id' in the match list of window 'wp'.
7004 * Print error messages if 'perr' is TRUE.
7005 */
7006 int
7007match_delete(wp, id, perr)
7008 win_T *wp;
7009 int id;
7010 int perr;
7011{
Bram Moolenaarb3414592014-06-17 17:48:32 +02007012 matchitem_T *cur = wp->w_match_head;
7013 matchitem_T *prev = cur;
7014 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007015
7016 if (id < 1)
7017 {
7018 if (perr == TRUE)
7019 EMSGN("E802: Invalid ID: %ld (must be greater than or equal to 1)",
7020 id);
7021 return -1;
7022 }
7023 while (cur != NULL && cur->id != id)
7024 {
7025 prev = cur;
7026 cur = cur->next;
7027 }
7028 if (cur == NULL)
7029 {
7030 if (perr == TRUE)
7031 EMSGN("E803: ID not found: %ld", id);
7032 return -1;
7033 }
7034 if (cur == prev)
7035 wp->w_match_head = cur->next;
7036 else
7037 prev->next = cur->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02007038 vim_regfree(cur->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007039 vim_free(cur->pattern);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007040 if (cur->pos.toplnum != 0)
7041 {
7042 if (wp->w_buffer->b_mod_set)
7043 {
7044 if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
7045 wp->w_buffer->b_mod_top = cur->pos.toplnum;
7046 if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
7047 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
7048 }
7049 else
7050 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02007051 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007052 wp->w_buffer->b_mod_top = cur->pos.toplnum;
7053 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02007054 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007055 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02007056 rtype = VALID;
7057 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007058 vim_free(cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007059 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007060 return 0;
7061}
7062
7063/*
7064 * Delete all matches in the match list of window 'wp'.
7065 */
7066 void
7067clear_matches(wp)
7068 win_T *wp;
7069{
7070 matchitem_T *m;
7071
7072 while (wp->w_match_head != NULL)
7073 {
7074 m = wp->w_match_head->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02007075 vim_regfree(wp->w_match_head->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007076 vim_free(wp->w_match_head->pattern);
7077 vim_free(wp->w_match_head);
7078 wp->w_match_head = m;
7079 }
7080 redraw_later(SOME_VALID);
7081}
7082
7083/*
7084 * Get match from ID 'id' in window 'wp'.
7085 * Return NULL if match not found.
7086 */
7087 matchitem_T *
7088get_match(wp, id)
7089 win_T *wp;
7090 int id;
7091{
7092 matchitem_T *cur = wp->w_match_head;
7093
7094 while (cur != NULL && cur->id != id)
7095 cur = cur->next;
7096 return cur;
7097}
7098#endif
Bram Moolenaar6d216452013-05-12 19:00:41 +02007099
7100#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
7101 int
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007102get_win_number(win_T *wp, win_T *first_win)
Bram Moolenaar6d216452013-05-12 19:00:41 +02007103{
7104 int i = 1;
7105 win_T *w;
7106
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007107 for (w = first_win; w != NULL && w != wp; w = W_NEXT(w))
Bram Moolenaar6d216452013-05-12 19:00:41 +02007108 ++i;
7109
7110 if (w == NULL)
7111 return 0;
7112 else
7113 return i;
7114}
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007115
7116 int
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02007117get_tab_number(tabpage_T *tp UNUSED)
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007118{
7119 int i = 1;
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02007120# ifdef FEAT_WINDOWS
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007121 tabpage_T *t;
7122
7123 for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next)
7124 ++i;
7125
7126 if (t == NULL)
7127 return 0;
7128 else
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02007129# endif
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007130 return i;
7131}
Bram Moolenaar6d216452013-05-12 19:00:41 +02007132#endif
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007133
Bram Moolenaarf0327f62013-06-28 20:16:55 +02007134#ifdef FEAT_WINDOWS
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007135/*
7136 * Return TRUE if "topfrp" and its children are at the right height.
7137 */
7138 static int
7139frame_check_height(topfrp, height)
7140 frame_T *topfrp;
7141 int height;
7142{
7143 frame_T *frp;
7144
7145 if (topfrp->fr_height != height)
7146 return FALSE;
7147
7148 if (topfrp->fr_layout == FR_ROW)
7149 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
7150 if (frp->fr_height != height)
7151 return FALSE;
7152
7153 return TRUE;
7154}
Bram Moolenaarf0327f62013-06-28 20:16:55 +02007155#endif
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007156
7157#ifdef FEAT_VERTSPLIT
7158/*
7159 * Return TRUE if "topfrp" and its children are at the right width.
7160 */
7161 static int
7162frame_check_width(topfrp, width)
7163 frame_T *topfrp;
7164 int width;
7165{
7166 frame_T *frp;
7167
7168 if (topfrp->fr_width != width)
7169 return FALSE;
7170
7171 if (topfrp->fr_layout == FR_COL)
7172 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
7173 if (frp->fr_width != width)
7174 return FALSE;
7175
7176 return TRUE;
7177}
7178#endif
7179