blob: e1781d3f46340c941cdc9c113917949b5d81428e [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read a list of people who contributed.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10#include "vim.h"
11
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010012static int path_is_url(char_u *p);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010013static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, long Prenum);
14static void win_init(win_T *newp, win_T *oldp, int flags);
15static void win_init_some(win_T *newp, win_T *oldp);
16static void frame_comp_pos(frame_T *topfrp, int *row, int *col);
17static void frame_setheight(frame_T *curfrp, int height);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010018static void frame_setwidth(frame_T *curfrp, int width);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010019static void win_exchange(long);
20static void win_rotate(int, int);
21static void win_totop(int size, int flags);
22static void win_equal_rec(win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height);
23static int last_window(void);
24static int close_last_window_tabpage(win_T *win, int free_buf, tabpage_T *prev_curtab);
25static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp);
26static frame_T *win_altframe(win_T *win, tabpage_T *tp);
27static tabpage_T *alt_tabpage(void);
28static win_T *frame2win(frame_T *frp);
29static int frame_has_win(frame_T *frp, win_T *wp);
30static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
31static int frame_fixed_height(frame_T *frp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010032static int frame_fixed_width(frame_T *frp);
33static void frame_add_statusline(frame_T *frp);
34static void frame_new_width(frame_T *topfrp, int width, int leftfirst, int wfw);
35static void frame_add_vsep(frame_T *frp);
36static int frame_minwidth(frame_T *topfrp, win_T *next_curwin);
37static void frame_fix_width(win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010038static int win_alloc_firstwin(win_T *oldwin);
39static void new_frame(win_T *wp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010040static tabpage_T *alloc_tabpage(void);
41static int leave_tabpage(buf_T *new_curbuf, int trigger_leave_autocmds);
42static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds);
43static void frame_fix_height(win_T *wp);
44static int frame_minheight(frame_T *topfrp, win_T *next_curwin);
Bram Moolenaarc917da42016-07-19 22:31:36 +020045static void win_enter_ext(win_T *wp, int undo_sync, int no_curwin, int trigger_new_autocmds, int trigger_enter_autocmds, int trigger_leave_autocmds);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010046static void win_free(win_T *wp, tabpage_T *tp);
47static void frame_append(frame_T *after, frame_T *frp);
48static void frame_insert(frame_T *before, frame_T *frp);
49static void frame_remove(frame_T *frp);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010050static void win_goto_ver(int up, long count);
51static void win_goto_hor(int left, long count);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010052static void frame_add_height(frame_T *frp, int n);
53static void last_status_rec(frame_T *fr, int statusline);
Bram Moolenaar071d4272004-06-13 20:20:40 +000054
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010055static void make_snapshot_rec(frame_T *fr, frame_T **frp);
56static void clear_snapshot(tabpage_T *tp, int idx);
57static void clear_snapshot_rec(frame_T *fr);
58static int check_snapshot_rec(frame_T *sn, frame_T *fr);
59static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr);
Bram Moolenaar071d4272004-06-13 20:20:40 +000060
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010061static int frame_check_height(frame_T *topfrp, int height);
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010062static int frame_check_width(frame_T *topfrp, int width);
Bram Moolenaarb893ac22013-06-26 14:04:47 +020063
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010064static win_T *win_alloc(win_T *after, int hidden);
Bram Moolenaar071d4272004-06-13 20:20:40 +000065
66#define URL_SLASH 1 /* path_is_url() has found "://" */
67#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
68
Bram Moolenaarb6799ac2007-05-10 16:44:05 +000069#define NOWIN (win_T *)-1 /* non-existing window */
Bram Moolenaar071d4272004-06-13 20:20:40 +000070
Bram Moolenaar4033c552017-09-16 20:54:51 +020071#define ROWS_AVAIL (Rows - p_ch - tabline_height())
Bram Moolenaar4c3f5362006-04-11 21:38:50 +000072
73static char *m_onlyone = N_("Already only one window");
74
Bram Moolenaar071d4272004-06-13 20:20:40 +000075/*
76 * all CTRL-W window commands are handled here, called from normal_cmd().
77 */
78 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +010079do_window(
80 int nchar,
81 long Prenum,
82 int xchar) /* extra char from ":wincmd gx" or NUL */
Bram Moolenaar071d4272004-06-13 20:20:40 +000083{
84 long Prenum1;
85 win_T *wp;
86#if defined(FEAT_SEARCHPATH) || defined(FEAT_FIND_ID)
87 char_u *ptr;
Bram Moolenaard1f56e62006-02-22 21:25:37 +000088 linenr_T lnum = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +000089#endif
90#ifdef FEAT_FIND_ID
91 int type = FIND_DEFINE;
92 int len;
93#endif
94 char_u cbuf[40];
95
96 if (Prenum == 0)
97 Prenum1 = 1;
98 else
99 Prenum1 = Prenum;
100
101#ifdef FEAT_CMDWIN
Bram Moolenaar6f470022018-04-10 18:47:20 +0200102# define CHECK_CMDWIN \
103 do { \
104 if (cmdwin_type != 0) \
105 { \
106 EMSG(_(e_cmdwin)); \
107 return; \
108 } \
109 } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110#else
Bram Moolenaar6f470022018-04-10 18:47:20 +0200111# define CHECK_CMDWIN do { /**/ } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112#endif
113
114 switch (nchar)
115 {
116/* split current window in two parts, horizontally */
117 case 'S':
118 case Ctrl_S:
119 case 's':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200120 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000122#ifdef FEAT_QUICKFIX
123 /* When splitting the quickfix window open a new buffer in it,
124 * don't replicate the quickfix buffer. */
125 if (bt_quickfix(curbuf))
126 goto newwindow;
127#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000128#ifdef FEAT_GUI
129 need_mouse_correct = TRUE;
130#endif
Bram Moolenaarcde88542015-08-11 19:14:00 +0200131 (void)win_split((int)Prenum, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132 break;
133
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134/* split current window in two parts, vertically */
135 case Ctrl_V:
136 case 'v':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200137 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100139#ifdef FEAT_QUICKFIX
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000140 /* When splitting the quickfix window open a new buffer in it,
141 * don't replicate the quickfix buffer. */
142 if (bt_quickfix(curbuf))
143 goto newwindow;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100144#endif
145#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146 need_mouse_correct = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100147#endif
Bram Moolenaarcde88542015-08-11 19:14:00 +0200148 (void)win_split((int)Prenum, WSP_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150
151/* split current window and edit alternate file */
152 case Ctrl_HAT:
153 case '^':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200154 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100156 cmd_with_count("split #", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 do_cmdline_cmd(cbuf);
158 break;
159
160/* open new window */
161 case Ctrl_N:
162 case 'n':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200163 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaarb1b715d2006-01-21 22:09:43 +0000165#ifdef FEAT_QUICKFIX
166newwindow:
167#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168 if (Prenum)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000169 /* window height */
170 vim_snprintf((char *)cbuf, sizeof(cbuf) - 5, "%ld", Prenum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171 else
172 cbuf[0] = NUL;
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100173#if defined(FEAT_QUICKFIX)
Bram Moolenaar990d95c2008-07-07 19:23:37 +0000174 if (nchar == 'v' || nchar == Ctrl_V)
175 STRCAT(cbuf, "v");
176#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177 STRCAT(cbuf, "new");
178 do_cmdline_cmd(cbuf);
179 break;
180
181/* quit current window */
182 case Ctrl_Q:
183 case 'q':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100185 cmd_with_count("quit", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100186 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 break;
188
189/* close current window */
190 case Ctrl_C:
191 case 'c':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100193 cmd_with_count("close", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100194 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195 break;
196
Bram Moolenaar4033c552017-09-16 20:54:51 +0200197#if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198/* close preview window */
199 case Ctrl_Z:
200 case 'z':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200201 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203 do_cmdline_cmd((char_u *)"pclose");
204 break;
205
206/* cursor to preview window */
207 case 'P':
Bram Moolenaar29323592016-07-24 22:04:11 +0200208 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209 if (wp->w_p_pvw)
210 break;
211 if (wp == NULL)
212 EMSG(_("E441: There is no preview window"));
213 else
214 win_goto(wp);
215 break;
216#endif
217
218/* close all but current window */
219 case Ctrl_O:
220 case 'o':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200221 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100223 cmd_with_count("only", cbuf, sizeof(cbuf), Prenum);
Bram Moolenaarb96a7f32014-11-27 16:22:48 +0100224 do_cmdline_cmd(cbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225 break;
226
227/* cursor to next window with wrap around */
228 case Ctrl_W:
229 case 'w':
230/* cursor to previous window with wrap around */
231 case 'W':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200232 CHECK_CMDWIN;
Bram Moolenaara1f4cb92016-11-06 15:25:42 +0100233 if (ONE_WINDOW && Prenum != 1) /* just one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 beep_flush();
235 else
236 {
237 if (Prenum) /* go to specified window */
238 {
239 for (wp = firstwin; --Prenum > 0; )
240 {
241 if (wp->w_next == NULL)
242 break;
243 else
244 wp = wp->w_next;
245 }
246 }
247 else
248 {
249 if (nchar == 'W') /* go to previous window */
250 {
251 wp = curwin->w_prev;
252 if (wp == NULL)
253 wp = lastwin; /* wrap around */
254 }
255 else /* go to next window */
256 {
257 wp = curwin->w_next;
258 if (wp == NULL)
259 wp = firstwin; /* wrap around */
260 }
261 }
262 win_goto(wp);
263 }
264 break;
265
266/* cursor to window below */
267 case 'j':
268 case K_DOWN:
269 case Ctrl_J:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200270 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271 win_goto_ver(FALSE, Prenum1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 break;
273
274/* cursor to window above */
275 case 'k':
276 case K_UP:
277 case Ctrl_K:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200278 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279 win_goto_ver(TRUE, Prenum1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 break;
281
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282/* cursor to left window */
283 case 'h':
284 case K_LEFT:
285 case Ctrl_H:
286 case K_BS:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200287 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288 win_goto_hor(TRUE, Prenum1);
289 break;
290
291/* cursor to right window */
292 case 'l':
293 case K_RIGHT:
294 case Ctrl_L:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200295 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 win_goto_hor(FALSE, Prenum1);
297 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000299/* move window to new tab page */
300 case 'T':
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000301 if (one_window())
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000302 MSG(_(m_onlyone));
303 else
304 {
305 tabpage_T *oldtab = curtab;
306 tabpage_T *newtab;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000307
308 /* First create a new tab with the window, then go back to
309 * the old tab and close the window there. */
Bram Moolenaar89d40322006-08-29 15:30:07 +0000310 wp = curwin;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000311 if (win_new_tabpage((int)Prenum) == OK
312 && valid_tabpage(oldtab))
313 {
314 newtab = curtab;
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200315 goto_tabpage_tp(oldtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000316 if (curwin == wp)
317 win_close(curwin, FALSE);
318 if (valid_tabpage(newtab))
Bram Moolenaar49e649f2013-05-06 04:50:35 +0200319 goto_tabpage_tp(newtab, TRUE, TRUE);
Bram Moolenaar4c3f5362006-04-11 21:38:50 +0000320 }
321 }
322 break;
323
Bram Moolenaar071d4272004-06-13 20:20:40 +0000324/* cursor to top-left window */
325 case 't':
326 case Ctrl_T:
327 win_goto(firstwin);
328 break;
329
330/* cursor to bottom-right window */
331 case 'b':
332 case Ctrl_B:
333 win_goto(lastwin);
334 break;
335
336/* cursor to last accessed (previous) window */
337 case 'p':
338 case Ctrl_P:
Bram Moolenaar3dda7db2016-04-03 21:22:58 +0200339 if (!win_valid(prevwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000340 beep_flush();
341 else
342 win_goto(prevwin);
343 break;
344
345/* exchange current and next window */
346 case 'x':
347 case Ctrl_X:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200348 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 win_exchange(Prenum);
350 break;
351
352/* rotate windows downwards */
353 case Ctrl_R:
354 case 'r':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200355 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 win_rotate(FALSE, (int)Prenum1); /* downwards */
358 break;
359
360/* rotate windows upwards */
361 case 'R':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200362 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 win_rotate(TRUE, (int)Prenum1); /* upwards */
365 break;
366
367/* move window to the very top/bottom/left/right */
368 case 'K':
369 case 'J':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 case 'H':
371 case 'L':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200372 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 win_totop((int)Prenum,
374 ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
375 | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
376 break;
377
378/* make all windows the same height */
379 case '=':
380#ifdef FEAT_GUI
381 need_mouse_correct = TRUE;
382#endif
383 win_equal(NULL, FALSE, 'b');
384 break;
385
386/* increase current window height */
387 case '+':
388#ifdef FEAT_GUI
389 need_mouse_correct = TRUE;
390#endif
391 win_setheight(curwin->w_height + (int)Prenum1);
392 break;
393
394/* decrease current window height */
395 case '-':
396#ifdef FEAT_GUI
397 need_mouse_correct = TRUE;
398#endif
399 win_setheight(curwin->w_height - (int)Prenum1);
400 break;
401
402/* set current window height */
403 case Ctrl__:
404 case '_':
405#ifdef FEAT_GUI
406 need_mouse_correct = TRUE;
407#endif
408 win_setheight(Prenum ? (int)Prenum : 9999);
409 break;
410
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411/* increase current window width */
412 case '>':
413#ifdef FEAT_GUI
414 need_mouse_correct = TRUE;
415#endif
416 win_setwidth(curwin->w_width + (int)Prenum1);
417 break;
418
419/* decrease current window width */
420 case '<':
421#ifdef FEAT_GUI
422 need_mouse_correct = TRUE;
423#endif
424 win_setwidth(curwin->w_width - (int)Prenum1);
425 break;
426
427/* set current window width */
428 case '|':
429#ifdef FEAT_GUI
430 need_mouse_correct = TRUE;
431#endif
432 win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
433 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434
435/* jump to tag and split window if tag exists (in preview window) */
436#if defined(FEAT_QUICKFIX)
437 case '}':
Bram Moolenaar6f470022018-04-10 18:47:20 +0200438 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 if (Prenum)
440 g_do_tagpreview = Prenum;
441 else
442 g_do_tagpreview = p_pvh;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443#endif
Bram Moolenaar2f40d122017-10-24 21:49:36 +0200444 /* FALLTHROUGH */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445 case ']':
446 case Ctrl_RSB:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200447 CHECK_CMDWIN;
Bram Moolenaard355c502014-09-23 13:48:43 +0200448 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 if (Prenum)
450 postponed_split = Prenum;
451 else
452 postponed_split = -1;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200453#ifdef FEAT_QUICKFIX
Bram Moolenaar56095e12014-10-09 10:44:37 +0200454 if (nchar != '}')
455 g_do_tagpreview = 0;
Bram Moolenaarda014b92014-09-24 13:26:44 +0200456#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457
Bram Moolenaard355c502014-09-23 13:48:43 +0200458 /* Execute the command right here, required when "wincmd ]"
459 * was used in a function. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460 do_nv_ident(Ctrl_RSB, NUL);
461 break;
462
463#ifdef FEAT_SEARCHPATH
464/* edit file name under cursor in a new window */
465 case 'f':
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000466 case 'F':
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467 case Ctrl_F:
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000468wingotofile:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200469 CHECK_CMDWIN;
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000470
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000471 ptr = grab_file_name(Prenum1, &lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472 if (ptr != NULL)
473 {
Bram Moolenaar5d2ca042016-06-26 17:11:21 +0200474 tabpage_T *oldtab = curtab;
475 win_T *oldwin = curwin;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000476# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 need_mouse_correct = TRUE;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000478# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 setpcmark();
480 if (win_split(0, 0) == OK)
481 {
Bram Moolenaar3368ea22010-09-21 16:56:35 +0200482 RESET_BINDING(curwin);
Bram Moolenaar5d2ca042016-06-26 17:11:21 +0200483 if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL,
484 ECMD_HIDE, NULL) == FAIL)
485 {
486 /* Failed to open the file, close the window
487 * opened for it. */
488 win_close(curwin, FALSE);
489 goto_tabpage_win(oldtab, oldwin);
490 }
491 else if (nchar == 'F' && lnum >= 0)
Bram Moolenaard1f56e62006-02-22 21:25:37 +0000492 {
493 curwin->w_cursor.lnum = lnum;
494 check_cursor_lnum();
495 beginline(BL_SOL | BL_FIX);
496 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000497 }
498 vim_free(ptr);
499 }
500 break;
501#endif
502
503#ifdef FEAT_FIND_ID
Bram Moolenaarb6799ac2007-05-10 16:44:05 +0000504/* Go to the first occurrence of the identifier under cursor along path in a
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 * new window -- webb
506 */
507 case 'i': /* Go to any match */
508 case Ctrl_I:
509 type = FIND_ANY;
510 /* FALLTHROUGH */
511 case 'd': /* Go to definition, using 'define' */
512 case Ctrl_D:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200513 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
515 break;
516 find_pattern_in_path(ptr, 0, len, TRUE,
517 Prenum == 0 ? TRUE : FALSE, type,
518 Prenum1, ACTION_SPLIT, (linenr_T)1, (linenr_T)MAXLNUM);
519 curwin->w_set_curswant = TRUE;
520 break;
521#endif
522
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200523/* Quickfix window only: view the result under the cursor in a new split. */
524#if defined(FEAT_QUICKFIX)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000525 case K_KENTER:
526 case CAR:
Bram Moolenaar05159a02005-02-26 23:04:13 +0000527 if (bt_quickfix(curbuf))
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200528 qf_view_result(TRUE);
Bram Moolenaar05159a02005-02-26 23:04:13 +0000529 break;
Bram Moolenaar0a08c632018-07-25 22:36:52 +0200530#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000531
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532/* CTRL-W g extended commands */
533 case 'g':
534 case Ctrl_G:
Bram Moolenaar6f470022018-04-10 18:47:20 +0200535 CHECK_CMDWIN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536#ifdef USE_ON_FLY_SCROLL
537 dont_scroll = TRUE; /* disallow scrolling here */
538#endif
539 ++no_mapping;
540 ++allow_keys; /* no mapping for xchar, but allow key codes */
541 if (xchar == NUL)
Bram Moolenaar61abfd12007-09-13 16:26:47 +0000542 xchar = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543 LANGMAP_ADJUST(xchar, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 --no_mapping;
545 --allow_keys;
546#ifdef FEAT_CMDL_INFO
547 (void)add_to_showcmd(xchar);
548#endif
549 switch (xchar)
550 {
551#if defined(FEAT_QUICKFIX)
552 case '}':
553 xchar = Ctrl_RSB;
554 if (Prenum)
555 g_do_tagpreview = Prenum;
556 else
557 g_do_tagpreview = p_pvh;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558#endif
Bram Moolenaar2f40d122017-10-24 21:49:36 +0200559 /* FALLTHROUGH */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 case ']':
561 case Ctrl_RSB:
Bram Moolenaard355c502014-09-23 13:48:43 +0200562 /* keep Visual mode, can select words to use as a tag */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 if (Prenum)
564 postponed_split = Prenum;
565 else
566 postponed_split = -1;
567
568 /* Execute the command right here, required when
569 * "wincmd g}" was used in a function. */
570 do_nv_ident('g', xchar);
571 break;
572
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000573#ifdef FEAT_SEARCHPATH
574 case 'f': /* CTRL-W gf: "gf" in a new tab page */
Bram Moolenaar57657d82006-04-21 22:12:41 +0000575 case 'F': /* CTRL-W gF: "gF" in a new tab page */
Bram Moolenaar6d1dcff2010-01-27 20:26:46 +0100576 cmdmod.tab = tabpage_index(curtab) + 1;
Bram Moolenaar57657d82006-04-21 22:12:41 +0000577 nchar = xchar;
Bram Moolenaar8dff8182006-04-06 20:18:50 +0000578 goto wingotofile;
579#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580 default:
581 beep_flush();
582 break;
583 }
584 break;
585
586 default: beep_flush();
587 break;
588 }
589}
590
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100591/*
592 * Figure out the address type for ":wnncmd".
593 */
594 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100595get_wincmd_addr_type(char_u *arg, exarg_T *eap)
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100596{
597 switch (*arg)
598 {
599 case 'S':
600 case Ctrl_S:
601 case 's':
602 case Ctrl_N:
603 case 'n':
604 case 'j':
605 case Ctrl_J:
606 case 'k':
607 case Ctrl_K:
608 case 'T':
609 case Ctrl_R:
610 case 'r':
611 case 'R':
612 case 'K':
613 case 'J':
614 case '+':
615 case '-':
616 case Ctrl__:
617 case '_':
618 case '|':
619 case ']':
620 case Ctrl_RSB:
621 case 'g':
622 case Ctrl_G:
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100623 case Ctrl_V:
624 case 'v':
625 case 'h':
626 case Ctrl_H:
627 case 'l':
628 case Ctrl_L:
629 case 'H':
630 case 'L':
631 case '>':
632 case '<':
Bram Moolenaar84c8e5a2015-01-14 15:47:36 +0100633#if defined(FEAT_QUICKFIX)
634 case '}':
635#endif
636#ifdef FEAT_SEARCHPATH
637 case 'f':
638 case 'F':
639 case Ctrl_F:
640#endif
641#ifdef FEAT_FIND_ID
642 case 'i':
643 case Ctrl_I:
644 case 'd':
645 case Ctrl_D:
646#endif
647 /* window size or any count */
648 eap->addr_type = ADDR_LINES;
649 break;
650
651 case Ctrl_HAT:
652 case '^':
653 /* buffer number */
654 eap->addr_type = ADDR_BUFFERS;
655 break;
656
657 case Ctrl_Q:
658 case 'q':
659 case Ctrl_C:
660 case 'c':
661 case Ctrl_O:
662 case 'o':
663 case Ctrl_W:
664 case 'w':
665 case 'W':
666 case 'x':
667 case Ctrl_X:
668 /* window number */
669 eap->addr_type = ADDR_WINDOWS;
670 break;
671
672#if defined(FEAT_QUICKFIX)
673 case Ctrl_Z:
674 case 'z':
675 case 'P':
676#endif
677 case 't':
678 case Ctrl_T:
679 case 'b':
680 case Ctrl_B:
681 case 'p':
682 case Ctrl_P:
683 case '=':
684 case CAR:
685 /* no count */
686 eap->addr_type = 0;
687 break;
688 }
689}
690
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100691 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100692cmd_with_count(
693 char *cmd,
694 char_u *bufp,
695 size_t bufsize,
696 long Prenum)
Bram Moolenaar2f1e51a2014-12-13 03:58:09 +0100697{
698 size_t len = STRLEN(cmd);
699
700 STRCPY(bufp, cmd);
701 if (Prenum > 0)
702 vim_snprintf((char *)bufp + len, bufsize - len, "%ld", Prenum);
703}
704
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705/*
706 * split the current window, implements CTRL-W s and :split
707 *
708 * "size" is the height or width for the new window, 0 to use half of current
709 * height or width.
710 *
711 * "flags":
712 * WSP_ROOM: require enough room for new window
713 * WSP_VERT: vertical split.
714 * WSP_TOP: open window at the top-left of the shell (help window).
715 * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
716 * WSP_HELP: creating the help window, keep layout snapshot
717 *
718 * return FAIL for failure, OK otherwise
719 */
720 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100721win_split(int size, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722{
Bram Moolenaar80a94a52006-02-23 21:26:58 +0000723 /* When the ":tab" modifier was used open a new tab page instead. */
724 if (may_open_tabpage() == OK)
725 return OK;
726
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 /* Add flags from ":vertical", ":topleft" and ":botright". */
728 flags |= cmdmod.split;
729 if ((flags & WSP_TOP) && (flags & WSP_BOT))
730 {
731 EMSG(_("E442: Can't split topleft and botright at the same time"));
732 return FAIL;
733 }
734
735 /* When creating the help window make a snapshot of the window layout.
736 * Otherwise clear the snapshot, it's now invalid. */
737 if (flags & WSP_HELP)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000738 make_snapshot(SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000740 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741
742 return win_split_ins(size, flags, NULL, 0);
743}
744
745/*
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100746 * When "new_wp" is NULL: split the current window in two.
747 * When "new_wp" is not NULL: insert this window at the far
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 * top/left/right/bottom.
749 * return FAIL for failure, OK otherwise
750 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000751 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100752win_split_ins(
753 int size,
754 int flags,
755 win_T *new_wp,
756 int dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757{
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100758 win_T *wp = new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 win_T *oldwin;
760 int new_size = size;
761 int i;
762 int need_status = 0;
763 int do_equal = FALSE;
764 int needed;
765 int available;
766 int oldwin_height = 0;
767 int layout;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200768 frame_T *frp, *curfrp, *frp2, *prevfrp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 int before;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200770 int minheight;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200771 int wmh1;
Bram Moolenaar98da6ec2018-04-13 22:15:46 +0200772 int did_set_fraction = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773
774 if (flags & WSP_TOP)
775 oldwin = firstwin;
776 else if (flags & WSP_BOT)
777 oldwin = lastwin;
778 else
779 oldwin = curwin;
780
781 /* add a status line when p_ls == 1 and splitting the first window */
Bram Moolenaar459ca562016-11-10 18:16:33 +0100782 if (ONE_WINDOW && p_ls == 1 && oldwin->w_status_height == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 {
Bram Moolenaar415a6932017-12-05 20:31:07 +0100784 if (VISIBLE_HEIGHT(oldwin) <= p_wmh && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 {
786 EMSG(_(e_noroom));
787 return FAIL;
788 }
789 need_status = STATUS_HEIGHT;
790 }
791
Bram Moolenaaree79cbc2007-05-02 19:50:14 +0000792#ifdef FEAT_GUI
793 /* May be needed for the scrollbars that are going to change. */
794 if (gui.in_use)
795 out_flush();
796#endif
797
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 if (flags & WSP_VERT)
799 {
Bram Moolenaara0485492014-07-16 23:39:54 +0200800 int wmw1;
801 int minwidth;
802
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 layout = FR_ROW;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804
805 /*
806 * Check if we are able to split the current window and compute its
807 * width.
808 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200809 /* Current window requires at least 1 space. */
810 wmw1 = (p_wmw == 0 ? 1 : p_wmw);
811 needed = wmw1 + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200813 needed += p_wiw - wmw1;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200814 if (flags & (WSP_BOT | WSP_TOP))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200816 minwidth = frame_minwidth(topframe, NOWIN);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 available = topframe->fr_width;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200818 needed += minwidth;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200820 else if (p_ea)
821 {
822 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
823 prevfrp = oldwin->w_frame;
824 for (frp = oldwin->w_frame->fr_parent; frp != NULL;
825 frp = frp->fr_parent)
826 {
827 if (frp->fr_layout == FR_ROW)
828 for (frp2 = frp->fr_child; frp2 != NULL;
829 frp2 = frp2->fr_next)
830 if (frp2 != prevfrp)
831 minwidth += frame_minwidth(frp2, NOWIN);
832 prevfrp = frp;
833 }
834 available = topframe->fr_width;
835 needed += minwidth;
836 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 else
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200838 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200839 minwidth = frame_minwidth(oldwin->w_frame, NOWIN);
840 available = oldwin->w_frame->fr_width;
841 needed += minwidth;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200842 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100843 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 {
845 EMSG(_(e_noroom));
846 return FAIL;
847 }
848 if (new_size == 0)
849 new_size = oldwin->w_width / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200850 if (new_size > available - minwidth - 1)
851 new_size = available - minwidth - 1;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200852 if (new_size < wmw1)
853 new_size = wmw1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854
855 /* if it doesn't fit in the current window, need win_equal() */
856 if (oldwin->w_width - new_size - 1 < p_wmw)
857 do_equal = TRUE;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +0000858
859 /* We don't like to take lines for the new window from a
860 * 'winfixwidth' window. Take them from a window to the left or right
Bram Moolenaar38e34832017-03-19 20:22:36 +0100861 * instead, if possible. Add one for the separator. */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +0000862 if (oldwin->w_p_wfw)
Bram Moolenaar38e34832017-03-19 20:22:36 +0100863 win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
Bram Moolenaar67f71312007-08-12 14:55:56 +0000864
865 /* Only make all windows the same width if one of them (except oldwin)
866 * is wider than one of the split windows. */
867 if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
868 && oldwin->w_frame->fr_parent != NULL)
869 {
870 frp = oldwin->w_frame->fr_parent->fr_child;
871 while (frp != NULL)
872 {
873 if (frp->fr_win != oldwin && frp->fr_win != NULL
874 && (frp->fr_win->w_width > new_size
875 || frp->fr_win->w_width > oldwin->w_width
Bram Moolenaardf46f6f2014-11-19 13:40:08 +0100876 - new_size - 1))
Bram Moolenaar67f71312007-08-12 14:55:56 +0000877 {
878 do_equal = TRUE;
879 break;
880 }
881 frp = frp->fr_next;
882 }
883 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 }
885 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
887 layout = FR_COL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888
889 /*
890 * Check if we are able to split the current window and compute its
891 * height.
892 */
Bram Moolenaar1f538352014-07-16 18:19:27 +0200893 /* Current window requires at least 1 space. */
Bram Moolenaar415a6932017-12-05 20:31:07 +0100894 wmh1 = (p_wmh == 0 ? 1 : p_wmh) + WINBAR_HEIGHT(curwin);
Bram Moolenaar1f538352014-07-16 18:19:27 +0200895 needed = wmh1 + STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 if (flags & WSP_ROOM)
Bram Moolenaar1f538352014-07-16 18:19:27 +0200897 needed += p_wh - wmh1;
Bram Moolenaar54368f22014-07-23 15:21:20 +0200898 if (flags & (WSP_BOT | WSP_TOP))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200900 minheight = frame_minheight(topframe, NOWIN) + need_status;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 available = topframe->fr_height;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200902 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 }
Bram Moolenaar54368f22014-07-23 15:21:20 +0200904 else if (p_ea)
905 {
906 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
907 prevfrp = oldwin->w_frame;
908 for (frp = oldwin->w_frame->fr_parent; frp != NULL;
909 frp = frp->fr_parent)
910 {
911 if (frp->fr_layout == FR_COL)
912 for (frp2 = frp->fr_child; frp2 != NULL;
913 frp2 = frp2->fr_next)
914 if (frp2 != prevfrp)
915 minheight += frame_minheight(frp2, NOWIN);
916 prevfrp = frp;
917 }
918 available = topframe->fr_height;
919 needed += minheight;
920 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 else
922 {
Bram Moolenaar1f538352014-07-16 18:19:27 +0200923 minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
924 available = oldwin->w_frame->fr_height;
925 needed += minheight;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926 }
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100927 if (available < needed && new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 {
929 EMSG(_(e_noroom));
930 return FAIL;
931 }
932 oldwin_height = oldwin->w_height;
933 if (need_status)
934 {
935 oldwin->w_status_height = STATUS_HEIGHT;
936 oldwin_height -= STATUS_HEIGHT;
937 }
938 if (new_size == 0)
939 new_size = oldwin_height / 2;
Bram Moolenaarb4d21352014-07-16 14:16:46 +0200940 if (new_size > available - minheight - STATUS_HEIGHT)
941 new_size = available - minheight - STATUS_HEIGHT;
Bram Moolenaar1f538352014-07-16 18:19:27 +0200942 if (new_size < wmh1)
943 new_size = wmh1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944
945 /* if it doesn't fit in the current window, need win_equal() */
946 if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
947 do_equal = TRUE;
948
949 /* We don't like to take lines for the new window from a
950 * 'winfixheight' window. Take them from a window above or below
951 * instead, if possible. */
952 if (oldwin->w_p_wfh)
953 {
Bram Moolenaar98da6ec2018-04-13 22:15:46 +0200954 /* Set w_fraction now so that the cursor keeps the same relative
955 * vertical position using the old height. */
956 set_fraction(oldwin);
957 did_set_fraction = TRUE;
958
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
960 oldwin);
961 oldwin_height = oldwin->w_height;
962 if (need_status)
963 oldwin_height -= STATUS_HEIGHT;
964 }
Bram Moolenaar67f71312007-08-12 14:55:56 +0000965
966 /* Only make all windows the same height if one of them (except oldwin)
967 * is higher than one of the split windows. */
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100968 if (!do_equal && p_ea && size == 0 && *p_ead != 'h'
Bram Moolenaar67f71312007-08-12 14:55:56 +0000969 && oldwin->w_frame->fr_parent != NULL)
970 {
971 frp = oldwin->w_frame->fr_parent->fr_child;
972 while (frp != NULL)
973 {
974 if (frp->fr_win != oldwin && frp->fr_win != NULL
975 && (frp->fr_win->w_height > new_size
976 || frp->fr_win->w_height > oldwin_height - new_size
977 - STATUS_HEIGHT))
978 {
979 do_equal = TRUE;
980 break;
981 }
982 frp = frp->fr_next;
983 }
984 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985 }
986
987 /*
988 * allocate new window structure and link it in the window list
989 */
990 if ((flags & WSP_TOP) == 0
991 && ((flags & WSP_BOT)
992 || (flags & WSP_BELOW)
993 || (!(flags & WSP_ABOVE)
Bram Moolenaar44a2f922016-03-19 22:11:51 +0100994 && ( (flags & WSP_VERT) ? p_spr : p_sb))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 {
996 /* new window below/right of current one */
Bram Moolenaar70b2a562012-01-10 22:26:17 +0100997 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +0000998 wp = win_alloc(oldwin, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999 else
1000 win_append(oldwin, wp);
1001 }
1002 else
1003 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001004 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001005 wp = win_alloc(oldwin->w_prev, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 else
1007 win_append(oldwin->w_prev, wp);
1008 }
1009
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001010 if (new_wp == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 {
1012 if (wp == NULL)
1013 return FAIL;
1014
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001015 new_frame(wp);
1016 if (wp->w_frame == NULL)
1017 {
1018 win_free(wp, NULL);
1019 return FAIL;
1020 }
1021
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001022 /* make the contents of the new window the same as the current one */
Bram Moolenaar884ae642009-02-22 01:37:59 +00001023 win_init(wp, curwin, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024 }
1025
1026 /*
1027 * Reorganise the tree of frames to insert the new window.
1028 */
1029 if (flags & (WSP_TOP | WSP_BOT))
1030 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
1032 || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 {
1034 curfrp = topframe->fr_child;
1035 if (flags & WSP_BOT)
1036 while (curfrp->fr_next != NULL)
1037 curfrp = curfrp->fr_next;
1038 }
1039 else
1040 curfrp = topframe;
1041 before = (flags & WSP_TOP);
1042 }
1043 else
1044 {
1045 curfrp = oldwin->w_frame;
1046 if (flags & WSP_BELOW)
1047 before = FALSE;
1048 else if (flags & WSP_ABOVE)
1049 before = TRUE;
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001050 else if (flags & WSP_VERT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 before = !p_spr;
1052 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 before = !p_sb;
1054 }
1055 if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout)
1056 {
1057 /* Need to create a new frame in the tree to make a branch. */
1058 frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
1059 *frp = *curfrp;
1060 curfrp->fr_layout = layout;
1061 frp->fr_parent = curfrp;
1062 frp->fr_next = NULL;
1063 frp->fr_prev = NULL;
1064 curfrp->fr_child = frp;
1065 curfrp->fr_win = NULL;
1066 curfrp = frp;
1067 if (frp->fr_win != NULL)
1068 oldwin->w_frame = frp;
1069 else
1070 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
1071 frp->fr_parent = curfrp;
1072 }
1073
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001074 if (new_wp == NULL)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001075 frp = wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 else
Bram Moolenaar70b2a562012-01-10 22:26:17 +01001077 frp = new_wp->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 frp->fr_parent = curfrp->fr_parent;
1079
1080 /* Insert the new frame at the right place in the frame list. */
1081 if (before)
1082 frame_insert(curfrp, frp);
1083 else
1084 frame_append(curfrp, frp);
1085
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001086 /* Set w_fraction now so that the cursor keeps the same relative
1087 * vertical position. */
Bram Moolenaar98da6ec2018-04-13 22:15:46 +02001088 if (!did_set_fraction)
1089 set_fraction(oldwin);
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001090 wp->w_fraction = oldwin->w_fraction;
1091
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 if (flags & WSP_VERT)
1093 {
1094 wp->w_p_scr = curwin->w_p_scr;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01001095
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 if (need_status)
1097 {
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001098 win_new_height(oldwin, oldwin->w_height - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 oldwin->w_status_height = need_status;
1100 }
1101 if (flags & (WSP_TOP | WSP_BOT))
1102 {
1103 /* set height and row of new window to full height */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001104 wp->w_winrow = tabline_height();
Bram Moolenaard326ad62017-09-18 20:31:41 +02001105 win_new_height(wp, curfrp->fr_height - (p_ls > 0)
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01001106 - WINBAR_HEIGHT(wp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107 wp->w_status_height = (p_ls > 0);
1108 }
1109 else
1110 {
1111 /* height and row of new window is same as current window */
1112 wp->w_winrow = oldwin->w_winrow;
Bram Moolenaar415a6932017-12-05 20:31:07 +01001113 win_new_height(wp, VISIBLE_HEIGHT(oldwin));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 wp->w_status_height = oldwin->w_status_height;
1115 }
1116 frp->fr_height = curfrp->fr_height;
1117
1118 /* "new_size" of the current window goes to the new window, use
1119 * one column for the vertical separator */
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001120 win_new_width(wp, new_size);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 if (before)
1122 wp->w_vsep_width = 1;
1123 else
1124 {
1125 wp->w_vsep_width = oldwin->w_vsep_width;
1126 oldwin->w_vsep_width = 1;
1127 }
1128 if (flags & (WSP_TOP | WSP_BOT))
1129 {
1130 if (flags & WSP_BOT)
1131 frame_add_vsep(curfrp);
1132 /* Set width of neighbor frame */
1133 frame_new_width(curfrp, curfrp->fr_width
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001134 - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
1135 FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136 }
1137 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001138 win_new_width(oldwin, oldwin->w_width - (new_size + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 if (before) /* new window left of current one */
1140 {
1141 wp->w_wincol = oldwin->w_wincol;
1142 oldwin->w_wincol += new_size + 1;
1143 }
1144 else /* new window right of current one */
1145 wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
1146 frame_fix_width(oldwin);
1147 frame_fix_width(wp);
1148 }
1149 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150 {
1151 /* width and column of new window is same as current window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 if (flags & (WSP_TOP | WSP_BOT))
1153 {
1154 wp->w_wincol = 0;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001155 win_new_width(wp, Columns);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156 wp->w_vsep_width = 0;
1157 }
1158 else
1159 {
1160 wp->w_wincol = oldwin->w_wincol;
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001161 win_new_width(wp, oldwin->w_width);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162 wp->w_vsep_width = oldwin->w_vsep_width;
1163 }
1164 frp->fr_width = curfrp->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165
1166 /* "new_size" of the current window goes to the new window, use
1167 * one row for the status line */
1168 win_new_height(wp, new_size);
1169 if (flags & (WSP_TOP | WSP_BOT))
Bram Moolenaar991dea32016-05-24 11:31:32 +02001170 {
Bram Moolenaard326ad62017-09-18 20:31:41 +02001171 int new_fr_height = curfrp->fr_height - new_size
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01001172 + WINBAR_HEIGHT(wp) ;
Bram Moolenaar991dea32016-05-24 11:31:32 +02001173
1174 if (!((flags & WSP_BOT) && p_ls == 0))
1175 new_fr_height -= STATUS_HEIGHT;
1176 frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, FALSE);
1177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178 else
1179 win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
1180 if (before) /* new window above current one */
1181 {
1182 wp->w_winrow = oldwin->w_winrow;
1183 wp->w_status_height = STATUS_HEIGHT;
1184 oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
1185 }
1186 else /* new window below current one */
1187 {
Bram Moolenaar415a6932017-12-05 20:31:07 +01001188 wp->w_winrow = oldwin->w_winrow + VISIBLE_HEIGHT(oldwin)
1189 + STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001190 wp->w_status_height = oldwin->w_status_height;
Bram Moolenaar991dea32016-05-24 11:31:32 +02001191 if (!(flags & WSP_BOT))
1192 oldwin->w_status_height = STATUS_HEIGHT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001193 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001194 if (flags & WSP_BOT)
1195 frame_add_statusline(curfrp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196 frame_fix_height(wp);
1197 frame_fix_height(oldwin);
1198 }
1199
1200 if (flags & (WSP_TOP | WSP_BOT))
1201 (void)win_comp_pos();
1202
1203 /*
1204 * Both windows need redrawing
1205 */
1206 redraw_win_later(wp, NOT_VALID);
1207 wp->w_redr_status = TRUE;
1208 redraw_win_later(oldwin, NOT_VALID);
1209 oldwin->w_redr_status = TRUE;
1210
1211 if (need_status)
1212 {
1213 msg_row = Rows - 1;
1214 msg_col = sc_col;
1215 msg_clr_eos_force(); /* Old command/ruler may still be there */
1216 comp_col();
1217 msg_row = Rows - 1;
1218 msg_col = 0; /* put position back at start of line */
1219 }
1220
1221 /*
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001222 * equalize the window sizes.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 */
1224 if (do_equal || dir != 0)
1225 win_equal(wp, TRUE,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001226 (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001227 : dir == 'h' ? 'b' : 'v');
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228
1229 /* Don't change the window height/width to 'winheight' / 'winwidth' if a
1230 * size was given. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231 if (flags & WSP_VERT)
1232 {
1233 i = p_wiw;
1234 if (size != 0)
1235 p_wiw = size;
1236
1237# ifdef FEAT_GUI
1238 /* When 'guioptions' includes 'L' or 'R' may have to add scrollbars. */
1239 if (gui.in_use)
1240 gui_init_which_components(NULL);
1241# endif
1242 }
1243 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244 {
1245 i = p_wh;
1246 if (size != 0)
1247 p_wh = size;
1248 }
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001249
Bram Moolenaar23fb7a92014-07-30 14:05:00 +02001250#ifdef FEAT_JUMPLIST
1251 /* Keep same changelist position in new window. */
1252 wp->w_changelistidx = oldwin->w_changelistidx;
1253#endif
1254
Bram Moolenaar9b73a782010-03-17 16:54:57 +01001255 /*
1256 * make the new window the current window
1257 */
Bram Moolenaarc917da42016-07-19 22:31:36 +02001258 win_enter_ext(wp, FALSE, FALSE, TRUE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001259 if (flags & WSP_VERT)
1260 p_wiw = i;
1261 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 p_wh = i;
1263
1264 return OK;
1265}
1266
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001267
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001268/*
1269 * Initialize window "newp" from window "oldp".
1270 * Used when splitting a window and when creating a new tab page.
1271 * The windows will both edit the same buffer.
Bram Moolenaar884ae642009-02-22 01:37:59 +00001272 * WSP_NEWLOC may be specified in flags to prevent the location list from
1273 * being copied.
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001274 */
1275 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001276win_init(win_T *newp, win_T *oldp, int flags UNUSED)
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001277{
1278 int i;
1279
1280 newp->w_buffer = oldp->w_buffer;
Bram Moolenaar860cae12010-06-05 23:22:07 +02001281#ifdef FEAT_SYN_HL
Bram Moolenaarfd29f462010-06-06 16:11:09 +02001282 newp->w_s = &(oldp->w_buffer->b_s);
Bram Moolenaar860cae12010-06-05 23:22:07 +02001283#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001284 oldp->w_buffer->b_nwindows++;
1285 newp->w_cursor = oldp->w_cursor;
1286 newp->w_valid = 0;
1287 newp->w_curswant = oldp->w_curswant;
1288 newp->w_set_curswant = oldp->w_set_curswant;
1289 newp->w_topline = oldp->w_topline;
1290#ifdef FEAT_DIFF
1291 newp->w_topfill = oldp->w_topfill;
1292#endif
1293 newp->w_leftcol = oldp->w_leftcol;
1294 newp->w_pcmark = oldp->w_pcmark;
1295 newp->w_prev_pcmark = oldp->w_prev_pcmark;
1296 newp->w_alt_fnum = oldp->w_alt_fnum;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00001297 newp->w_wrow = oldp->w_wrow;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001298 newp->w_fraction = oldp->w_fraction;
1299 newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
1300#ifdef FEAT_JUMPLIST
1301 copy_jumplist(oldp, newp);
1302#endif
1303#ifdef FEAT_QUICKFIX
Bram Moolenaar884ae642009-02-22 01:37:59 +00001304 if (flags & WSP_NEWLOC)
1305 {
1306 /* Don't copy the location list. */
1307 newp->w_llist = NULL;
1308 newp->w_llist_ref = NULL;
1309 }
1310 else
1311 copy_loclist(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001312#endif
Bram Moolenaarbd2dc342014-01-10 15:53:13 +01001313 newp->w_localdir = (oldp->w_localdir == NULL)
1314 ? NULL : vim_strsave(oldp->w_localdir);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001315
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001316 /* copy tagstack and folds */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001317 for (i = 0; i < oldp->w_tagstacklen; i++)
1318 {
1319 newp->w_tagstack[i] = oldp->w_tagstack[i];
1320 if (newp->w_tagstack[i].tagname != NULL)
1321 newp->w_tagstack[i].tagname =
1322 vim_strsave(newp->w_tagstack[i].tagname);
1323 }
1324 newp->w_tagstackidx = oldp->w_tagstackidx;
1325 newp->w_tagstacklen = oldp->w_tagstacklen;
Bram Moolenaara971b822011-09-14 14:43:25 +02001326#ifdef FEAT_FOLDING
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001327 copyFoldingState(oldp, newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001328#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001329
1330 win_init_some(newp, oldp);
Bram Moolenaar1a384422010-07-14 19:53:30 +02001331
Bram Moolenaara971b822011-09-14 14:43:25 +02001332#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02001333 check_colorcolumn(newp);
Bram Moolenaara971b822011-09-14 14:43:25 +02001334#endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001335}
1336
1337/*
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02001338 * Initialize window "newp" from window "old".
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001339 * Only the essential things are copied.
1340 */
1341 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001342win_init_some(win_T *newp, win_T *oldp)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001343{
1344 /* Use the same argument list. */
1345 newp->w_alist = oldp->w_alist;
1346 ++newp->w_alist->al_refcount;
1347 newp->w_arg_idx = oldp->w_arg_idx;
1348
1349 /* copy options from existing window */
1350 win_copy_options(oldp, newp);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00001351}
1352
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354/*
Bram Moolenaare59215c2016-08-14 19:08:45 +02001355 * Check if "win" is a pointer to an existing window in the current tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 */
1357 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001358win_valid(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359{
1360 win_T *wp;
1361
1362 if (win == NULL)
1363 return FALSE;
Bram Moolenaar29323592016-07-24 22:04:11 +02001364 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365 if (wp == win)
1366 return TRUE;
1367 return FALSE;
1368}
1369
1370/*
Bram Moolenaare59215c2016-08-14 19:08:45 +02001371 * Check if "win" is a pointer to an existing window in any tab page.
1372 */
1373 int
1374win_valid_any_tab(win_T *win)
1375{
1376 win_T *wp;
1377 tabpage_T *tp;
1378
1379 if (win == NULL)
1380 return FALSE;
1381 FOR_ALL_TABPAGES(tp)
1382 {
1383 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
1384 {
1385 if (wp == win)
1386 return TRUE;
1387 }
1388 }
1389 return FALSE;
1390}
1391
1392/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001393 * Return the number of windows.
1394 */
1395 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001396win_count(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397{
1398 win_T *wp;
1399 int count = 0;
1400
Bram Moolenaar29323592016-07-24 22:04:11 +02001401 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402 ++count;
1403 return count;
1404}
1405
1406/*
1407 * Make "count" windows on the screen.
1408 * Return actual number of windows on the screen.
1409 * Must be called when there is just one window, filling the whole screen
1410 * (excluding the command line).
1411 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001412 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001413make_windows(
1414 int count,
1415 int vertical UNUSED) /* split windows vertically if TRUE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416{
1417 int maxcount;
1418 int todo;
1419
Bram Moolenaar071d4272004-06-13 20:20:40 +00001420 if (vertical)
1421 {
1422 /* Each windows needs at least 'winminwidth' lines and a separator
1423 * column. */
1424 maxcount = (curwin->w_width + curwin->w_vsep_width
1425 - (p_wiw - p_wmw)) / (p_wmw + 1);
1426 }
1427 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001428 {
1429 /* Each window needs at least 'winminheight' lines and a status line. */
Bram Moolenaar415a6932017-12-05 20:31:07 +01001430 maxcount = (VISIBLE_HEIGHT(curwin) + curwin->w_status_height
Bram Moolenaar071d4272004-06-13 20:20:40 +00001431 - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
1432 }
1433
1434 if (maxcount < 2)
1435 maxcount = 2;
1436 if (count > maxcount)
1437 count = maxcount;
1438
1439 /*
1440 * add status line now, otherwise first window will be too big
1441 */
1442 if (count > 1)
1443 last_status(TRUE);
1444
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445 /*
1446 * Don't execute autocommands while creating the windows. Must do that
1447 * when putting the buffers in the windows.
1448 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001449 block_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450
1451 /* todo is number of windows left to create */
1452 for (todo = count - 1; todo > 0; --todo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453 if (vertical)
1454 {
1455 if (win_split(curwin->w_width - (curwin->w_width - todo)
1456 / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
1457 break;
1458 }
1459 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 {
1461 if (win_split(curwin->w_height - (curwin->w_height - todo
1462 * STATUS_HEIGHT) / (todo + 1)
1463 - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
1464 break;
1465 }
1466
Bram Moolenaar78ab3312007-09-29 12:16:41 +00001467 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468
1469 /* return actual number of windows */
1470 return (count - todo);
1471}
1472
1473/*
1474 * Exchange current and next window
1475 */
1476 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001477win_exchange(long Prenum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001478{
1479 frame_T *frp;
1480 frame_T *frp2;
1481 win_T *wp;
1482 win_T *wp2;
1483 int temp;
1484
Bram Moolenaar459ca562016-11-10 18:16:33 +01001485 if (ONE_WINDOW) /* just one window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486 {
1487 beep_flush();
1488 return;
1489 }
1490
1491#ifdef FEAT_GUI
1492 need_mouse_correct = TRUE;
1493#endif
1494
1495 /*
1496 * find window to exchange with
1497 */
1498 if (Prenum)
1499 {
1500 frp = curwin->w_frame->fr_parent->fr_child;
1501 while (frp != NULL && --Prenum > 0)
1502 frp = frp->fr_next;
1503 }
1504 else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
1505 frp = curwin->w_frame->fr_next;
1506 else /* Swap last window in row/col with previous */
1507 frp = curwin->w_frame->fr_prev;
1508
1509 /* We can only exchange a window with another window, not with a frame
1510 * containing windows. */
1511 if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
1512 return;
1513 wp = frp->fr_win;
1514
1515/*
1516 * 1. remove curwin from the list. Remember after which window it was in wp2
1517 * 2. insert curwin before wp in the list
1518 * if wp != wp2
1519 * 3. remove wp from the list
1520 * 4. insert wp after wp2
1521 * 5. exchange the status line height and vsep width.
1522 */
1523 wp2 = curwin->w_prev;
1524 frp2 = curwin->w_frame->fr_prev;
1525 if (wp->w_prev != curwin)
1526 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001527 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528 frame_remove(curwin->w_frame);
1529 win_append(wp->w_prev, curwin);
1530 frame_insert(frp, curwin->w_frame);
1531 }
1532 if (wp != wp2)
1533 {
Bram Moolenaarf740b292006-02-16 22:11:02 +00001534 win_remove(wp, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535 frame_remove(wp->w_frame);
1536 win_append(wp2, wp);
1537 if (frp2 == NULL)
1538 frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
1539 else
1540 frame_append(frp2, wp->w_frame);
1541 }
1542 temp = curwin->w_status_height;
1543 curwin->w_status_height = wp->w_status_height;
1544 wp->w_status_height = temp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001545 temp = curwin->w_vsep_width;
1546 curwin->w_vsep_width = wp->w_vsep_width;
1547 wp->w_vsep_width = temp;
1548
1549 /* If the windows are not in the same frame, exchange the sizes to avoid
1550 * messing up the window layout. Otherwise fix the frame sizes. */
1551 if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent)
1552 {
1553 temp = curwin->w_height;
1554 curwin->w_height = wp->w_height;
1555 wp->w_height = temp;
1556 temp = curwin->w_width;
1557 curwin->w_width = wp->w_width;
1558 wp->w_width = temp;
1559 }
1560 else
1561 {
1562 frame_fix_height(curwin);
1563 frame_fix_height(wp);
1564 frame_fix_width(curwin);
1565 frame_fix_width(wp);
1566 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567
1568 (void)win_comp_pos(); /* recompute window positions */
1569
1570 win_enter(wp, TRUE);
1571 redraw_later(CLEAR);
1572}
1573
1574/*
1575 * rotate windows: if upwards TRUE the second window becomes the first one
1576 * if upwards FALSE the first window becomes the second one
1577 */
1578 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001579win_rotate(int upwards, int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580{
1581 win_T *wp1;
1582 win_T *wp2;
1583 frame_T *frp;
1584 int n;
1585
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01001586 if (ONE_WINDOW) /* nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587 {
1588 beep_flush();
1589 return;
1590 }
1591
1592#ifdef FEAT_GUI
1593 need_mouse_correct = TRUE;
1594#endif
1595
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 /* Check if all frames in this row/col have one window. */
1597 for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
1598 frp = frp->fr_next)
1599 if (frp->fr_win == NULL)
1600 {
1601 EMSG(_("E443: Cannot rotate when another window is split"));
1602 return;
1603 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604
1605 while (count--)
1606 {
1607 if (upwards) /* first window becomes last window */
1608 {
1609 /* remove first window/frame from the list */
1610 frp = curwin->w_frame->fr_parent->fr_child;
1611 wp1 = frp->fr_win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00001612 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001613 frame_remove(frp);
1614
1615 /* find last frame and append removed window/frame after it */
1616 for ( ; frp->fr_next != NULL; frp = frp->fr_next)
1617 ;
1618 win_append(frp->fr_win, wp1);
1619 frame_append(frp, wp1->w_frame);
1620
1621 wp2 = frp->fr_win; /* previously last window */
1622 }
1623 else /* last window becomes first window */
1624 {
1625 /* find last window/frame in the list and remove it */
1626 for (frp = curwin->w_frame; frp->fr_next != NULL;
1627 frp = frp->fr_next)
1628 ;
1629 wp1 = frp->fr_win;
1630 wp2 = wp1->w_prev; /* will become last window */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001631 win_remove(wp1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632 frame_remove(frp);
1633
1634 /* append the removed window/frame before the first in the list */
1635 win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
1636 frame_insert(frp->fr_parent->fr_child, frp);
1637 }
1638
1639 /* exchange status height and vsep width of old and new last window */
1640 n = wp2->w_status_height;
1641 wp2->w_status_height = wp1->w_status_height;
1642 wp1->w_status_height = n;
1643 frame_fix_height(wp1);
1644 frame_fix_height(wp2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 n = wp2->w_vsep_width;
1646 wp2->w_vsep_width = wp1->w_vsep_width;
1647 wp1->w_vsep_width = n;
1648 frame_fix_width(wp1);
1649 frame_fix_width(wp2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001651 /* recompute w_winrow and w_wincol for all windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001652 (void)win_comp_pos();
1653 }
1654
1655 redraw_later(CLEAR);
1656}
1657
1658/*
1659 * Move the current window to the very top/bottom/left/right of the screen.
1660 */
1661 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001662win_totop(int size, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663{
1664 int dir;
1665 int height = curwin->w_height;
1666
Bram Moolenaar459ca562016-11-10 18:16:33 +01001667 if (ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668 {
1669 beep_flush();
1670 return;
1671 }
1672
1673 /* Remove the window and frame from the tree of frames. */
Bram Moolenaarf740b292006-02-16 22:11:02 +00001674 (void)winframe_remove(curwin, &dir, NULL);
1675 win_remove(curwin, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676 last_status(FALSE); /* may need to remove last status line */
1677 (void)win_comp_pos(); /* recompute window positions */
1678
1679 /* Split a window on the desired side and put the window there. */
1680 (void)win_split_ins(size, flags, curwin, dir);
1681 if (!(flags & WSP_VERT))
1682 {
1683 win_setheight(height);
1684 if (p_ea)
1685 win_equal(curwin, TRUE, 'v');
1686 }
1687
Bram Moolenaar44a2f922016-03-19 22:11:51 +01001688#if defined(FEAT_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
1690 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00001691 gui_may_update_scrollbars();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001692#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693}
1694
1695/*
1696 * Move window "win1" to below/right of "win2" and make "win1" the current
1697 * window. Only works within the same frame!
1698 */
1699 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001700win_move_after(win_T *win1, win_T *win2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701{
1702 int height;
1703
1704 /* check if the arguments are reasonable */
1705 if (win1 == win2)
1706 return;
1707
1708 /* check if there is something to do */
1709 if (win2->w_next != win1)
1710 {
1711 /* may need move the status line/vertical separator of the last window
1712 * */
1713 if (win1 == lastwin)
1714 {
1715 height = win1->w_prev->w_status_height;
1716 win1->w_prev->w_status_height = win1->w_status_height;
1717 win1->w_status_height = height;
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001718 if (win1->w_prev->w_vsep_width == 1)
1719 {
1720 /* Remove the vertical separator from the last-but-one window,
1721 * add it to the last window. Adjust the frame widths. */
1722 win1->w_prev->w_vsep_width = 0;
1723 win1->w_prev->w_frame->fr_width -= 1;
1724 win1->w_vsep_width = 1;
1725 win1->w_frame->fr_width += 1;
1726 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 }
1728 else if (win2 == lastwin)
1729 {
1730 height = win1->w_status_height;
1731 win1->w_status_height = win2->w_status_height;
1732 win2->w_status_height = height;
Bram Moolenaar0396ab02007-02-19 23:14:18 +00001733 if (win1->w_vsep_width == 1)
1734 {
1735 /* Remove the vertical separator from win1, add it to the last
1736 * window, win2. Adjust the frame widths. */
1737 win2->w_vsep_width = 1;
1738 win2->w_frame->fr_width += 1;
1739 win1->w_vsep_width = 0;
1740 win1->w_frame->fr_width -= 1;
1741 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00001743 win_remove(win1, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 frame_remove(win1->w_frame);
1745 win_append(win2, win1);
1746 frame_append(win2->w_frame, win1->w_frame);
1747
1748 (void)win_comp_pos(); /* recompute w_winrow for all windows */
1749 redraw_later(NOT_VALID);
1750 }
1751 win_enter(win1, FALSE);
1752}
1753
1754/*
1755 * Make all windows the same height.
1756 * 'next_curwin' will soon be the current window, make sure it has enough
1757 * rows.
1758 */
1759 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001760win_equal(
1761 win_T *next_curwin, /* pointer to current window to be or NULL */
1762 int current, /* do only frame with current window */
1763 int dir) /* 'v' for vertically, 'h' for horizontally,
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 'b' for both, 0 for using p_ead */
1765{
1766 if (dir == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 dir = *p_ead;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
Bram Moolenaar32466aa2006-02-24 23:53:04 +00001769 topframe, dir, 0, tabline_height(),
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00001770 (int)Columns, topframe->fr_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001771}
1772
1773/*
1774 * Set a frame to a new position and height, spreading the available room
1775 * equally over contained frames.
1776 * The window "next_curwin" (if not NULL) should at least get the size from
1777 * 'winheight' and 'winwidth' if possible.
1778 */
1779 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01001780win_equal_rec(
1781 win_T *next_curwin, /* pointer to current window to be or NULL */
1782 int current, /* do only frame with current window */
1783 frame_T *topfr, /* frame to set size off */
1784 int dir, /* 'v', 'h' or 'b', see win_equal() */
1785 int col, /* horizontal position for frame */
1786 int row, /* vertical position for frame */
1787 int width, /* new width of frame */
1788 int height) /* new height of frame */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789{
1790 int n, m;
1791 int extra_sep = 0;
1792 int wincount, totwincount = 0;
1793 frame_T *fr;
1794 int next_curwin_size = 0;
1795 int room = 0;
1796 int new_size;
1797 int has_next_curwin = 0;
1798 int hnc;
1799
1800 if (topfr->fr_layout == FR_LEAF)
1801 {
1802 /* Set the width/height of this frame.
1803 * Redraw when size or position changes */
1804 if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
Bram Moolenaar071d4272004-06-13 20:20:40 +00001805 || topfr->fr_width != width || topfr->fr_win->w_wincol != col
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806 )
1807 {
1808 topfr->fr_win->w_winrow = row;
1809 frame_new_height(topfr, height, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810 topfr->fr_win->w_wincol = col;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001811 frame_new_width(topfr, width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 redraw_all_later(CLEAR);
1813 }
1814 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 else if (topfr->fr_layout == FR_ROW)
1816 {
1817 topfr->fr_width = width;
1818 topfr->fr_height = height;
1819
1820 if (dir != 'v') /* equalize frame widths */
1821 {
1822 /* Compute the maximum number of windows horizontally in this
1823 * frame. */
1824 n = frame_minwidth(topfr, NOWIN);
1825 /* add one for the rightmost window, it doesn't have a separator */
1826 if (col + width == Columns)
1827 extra_sep = 1;
1828 else
1829 extra_sep = 0;
1830 totwincount = (n + extra_sep) / (p_wmw + 1);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001831 has_next_curwin = frame_has_win(topfr, next_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001833 /*
1834 * Compute width for "next_curwin" window and room available for
1835 * other windows.
1836 * "m" is the minimal width when counting p_wiw for "next_curwin".
1837 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 m = frame_minwidth(topfr, next_curwin);
1839 room = width - m;
1840 if (room < 0)
1841 {
1842 next_curwin_size = p_wiw + room;
1843 room = 0;
1844 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 else
1846 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001847 next_curwin_size = -1;
1848 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1849 {
1850 /* If 'winfixwidth' set keep the window width if
1851 * possible.
1852 * Watch out for this window being the next_curwin. */
1853 if (frame_fixed_width(fr))
1854 {
1855 n = frame_minwidth(fr, NOWIN);
1856 new_size = fr->fr_width;
1857 if (frame_has_win(fr, next_curwin))
1858 {
1859 room += p_wiw - p_wmw;
1860 next_curwin_size = 0;
1861 if (new_size < p_wiw)
1862 new_size = p_wiw;
1863 }
1864 else
1865 /* These windows don't use up room. */
1866 totwincount -= (n + (fr->fr_next == NULL
1867 ? extra_sep : 0)) / (p_wmw + 1);
1868 room -= new_size - n;
1869 if (room < 0)
1870 {
1871 new_size += room;
1872 room = 0;
1873 }
1874 fr->fr_newwidth = new_size;
1875 }
1876 }
1877 if (next_curwin_size == -1)
1878 {
1879 if (!has_next_curwin)
1880 next_curwin_size = 0;
1881 else if (totwincount > 1
1882 && (room + (totwincount - 2))
1883 / (totwincount - 1) > p_wiw)
1884 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00001885 /* Can make all windows wider than 'winwidth', spread
1886 * the room equally. */
1887 next_curwin_size = (room + p_wiw
1888 + (totwincount - 1) * p_wmw
1889 + (totwincount - 1)) / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001890 room -= next_curwin_size - p_wiw;
1891 }
1892 else
1893 next_curwin_size = p_wiw;
1894 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001896
1897 if (has_next_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 --totwincount; /* don't count curwin */
1899 }
1900
1901 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1902 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903 wincount = 1;
1904 if (fr->fr_next == NULL)
1905 /* last frame gets all that remains (avoid roundoff error) */
1906 new_size = width;
1907 else if (dir == 'v')
1908 new_size = fr->fr_width;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001909 else if (frame_fixed_width(fr))
1910 {
1911 new_size = fr->fr_newwidth;
1912 wincount = 0; /* doesn't count as a sizeable window */
1913 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 else
1915 {
1916 /* Compute the maximum number of windows horiz. in "fr". */
1917 n = frame_minwidth(fr, NOWIN);
1918 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
1919 / (p_wmw + 1);
1920 m = frame_minwidth(fr, next_curwin);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001921 if (has_next_curwin)
1922 hnc = frame_has_win(fr, next_curwin);
1923 else
1924 hnc = FALSE;
1925 if (hnc) /* don't count next_curwin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001926 --wincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001927 if (totwincount == 0)
1928 new_size = room;
1929 else
1930 new_size = (wincount * room + ((unsigned)totwincount >> 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931 / totwincount;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001932 if (hnc) /* add next_curwin size */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 {
1934 next_curwin_size -= p_wiw - (m - n);
1935 new_size += next_curwin_size;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001936 room -= new_size - next_curwin_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001938 else
1939 room -= new_size;
1940 new_size += n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 }
1942
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001943 /* Skip frame that is full width when splitting or closing a
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 * window, unless equalizing all frames. */
1945 if (!current || dir != 'v' || topfr->fr_parent != NULL
1946 || (new_size != fr->fr_width)
1947 || frame_has_win(fr, next_curwin))
1948 win_equal_rec(next_curwin, current, fr, dir, col, row,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00001949 new_size, height);
1950 col += new_size;
1951 width -= new_size;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 totwincount -= wincount;
1953 }
1954 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 else /* topfr->fr_layout == FR_COL */
1956 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 topfr->fr_width = width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 topfr->fr_height = height;
1959
1960 if (dir != 'h') /* equalize frame heights */
1961 {
1962 /* Compute maximum number of windows vertically in this frame. */
1963 n = frame_minheight(topfr, NOWIN);
1964 /* add one for the bottom window if it doesn't have a statusline */
1965 if (row + height == cmdline_row && p_ls == 0)
1966 extra_sep = 1;
1967 else
1968 extra_sep = 0;
1969 totwincount = (n + extra_sep) / (p_wmh + 1);
1970 has_next_curwin = frame_has_win(topfr, next_curwin);
1971
1972 /*
1973 * Compute height for "next_curwin" window and room available for
1974 * other windows.
1975 * "m" is the minimal height when counting p_wh for "next_curwin".
1976 */
1977 m = frame_minheight(topfr, next_curwin);
1978 room = height - m;
1979 if (room < 0)
1980 {
1981 /* The room is less then 'winheight', use all space for the
1982 * current window. */
1983 next_curwin_size = p_wh + room;
1984 room = 0;
1985 }
1986 else
1987 {
1988 next_curwin_size = -1;
1989 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
1990 {
1991 /* If 'winfixheight' set keep the window height if
1992 * possible.
1993 * Watch out for this window being the next_curwin. */
1994 if (frame_fixed_height(fr))
1995 {
1996 n = frame_minheight(fr, NOWIN);
1997 new_size = fr->fr_height;
1998 if (frame_has_win(fr, next_curwin))
1999 {
2000 room += p_wh - p_wmh;
2001 next_curwin_size = 0;
2002 if (new_size < p_wh)
2003 new_size = p_wh;
2004 }
2005 else
2006 /* These windows don't use up room. */
2007 totwincount -= (n + (fr->fr_next == NULL
2008 ? extra_sep : 0)) / (p_wmh + 1);
2009 room -= new_size - n;
2010 if (room < 0)
2011 {
2012 new_size += room;
2013 room = 0;
2014 }
2015 fr->fr_newheight = new_size;
2016 }
2017 }
2018 if (next_curwin_size == -1)
2019 {
2020 if (!has_next_curwin)
2021 next_curwin_size = 0;
2022 else if (totwincount > 1
2023 && (room + (totwincount - 2))
2024 / (totwincount - 1) > p_wh)
2025 {
Bram Moolenaarb21e5842006-04-16 18:30:08 +00002026 /* can make all windows higher than 'winheight',
2027 * spread the room equally. */
2028 next_curwin_size = (room + p_wh
2029 + (totwincount - 1) * p_wmh
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030 + (totwincount - 1)) / totwincount;
2031 room -= next_curwin_size - p_wh;
2032 }
2033 else
2034 next_curwin_size = p_wh;
2035 }
2036 }
2037
2038 if (has_next_curwin)
2039 --totwincount; /* don't count curwin */
2040 }
2041
2042 for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next)
2043 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002044 wincount = 1;
2045 if (fr->fr_next == NULL)
2046 /* last frame gets all that remains (avoid roundoff error) */
2047 new_size = height;
2048 else if (dir == 'h')
2049 new_size = fr->fr_height;
2050 else if (frame_fixed_height(fr))
2051 {
2052 new_size = fr->fr_newheight;
2053 wincount = 0; /* doesn't count as a sizeable window */
2054 }
2055 else
2056 {
2057 /* Compute the maximum number of windows vert. in "fr". */
2058 n = frame_minheight(fr, NOWIN);
2059 wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
2060 / (p_wmh + 1);
2061 m = frame_minheight(fr, next_curwin);
2062 if (has_next_curwin)
2063 hnc = frame_has_win(fr, next_curwin);
2064 else
2065 hnc = FALSE;
2066 if (hnc) /* don't count next_curwin */
2067 --wincount;
2068 if (totwincount == 0)
2069 new_size = room;
2070 else
2071 new_size = (wincount * room + ((unsigned)totwincount >> 1))
2072 / totwincount;
2073 if (hnc) /* add next_curwin size */
2074 {
2075 next_curwin_size -= p_wh - (m - n);
2076 new_size += next_curwin_size;
2077 room -= new_size - next_curwin_size;
2078 }
2079 else
2080 room -= new_size;
2081 new_size += n;
2082 }
2083 /* Skip frame that is full width when splitting or closing a
2084 * window, unless equalizing all frames. */
2085 if (!current || dir != 'h' || topfr->fr_parent != NULL
2086 || (new_size != fr->fr_height)
2087 || frame_has_win(fr, next_curwin))
2088 win_equal_rec(next_curwin, current, fr, dir, col, row,
2089 width, new_size);
2090 row += new_size;
2091 height -= new_size;
2092 totwincount -= wincount;
2093 }
2094 }
2095}
2096
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002097#ifdef FEAT_JOB_CHANNEL
2098 static void
2099leaving_window(win_T *win)
2100{
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002101 // Only matters for a prompt window.
2102 if (!bt_prompt(win->w_buffer))
2103 return;
2104
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002105 // When leaving a prompt window stop Insert mode and perhaps restart
2106 // it when entering that window again.
2107 win->w_buffer->b_prompt_insert = restart_edit;
Bram Moolenaar942b4542018-06-17 16:23:34 +02002108 if (restart_edit != 0 && mode_displayed)
2109 clear_cmdline = TRUE; /* unshow mode later */
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002110 restart_edit = NUL;
2111
2112 // When leaving the window (or closing the window) was done from a
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002113 // callback we need to break out of the Insert mode loop and restart Insert
2114 // mode when entering the window again.
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002115 if (State & INSERT)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002116 {
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002117 stop_insert_mode = TRUE;
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002118 if (win->w_buffer->b_prompt_insert == NUL)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002119 win->w_buffer->b_prompt_insert = 'A';
2120 }
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002121}
2122
2123 static void
2124entering_window(win_T *win)
2125{
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002126 // Only matters for a prompt window.
2127 if (!bt_prompt(win->w_buffer))
2128 return;
2129
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002130 // When switching to a prompt buffer that was in Insert mode, don't stop
2131 // Insert mode, it may have been set in leaving_window().
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002132 if (win->w_buffer->b_prompt_insert != NUL)
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02002133 stop_insert_mode = FALSE;
2134
Bram Moolenaarf98b8452018-06-10 14:39:52 +02002135 // When entering the prompt window restart Insert mode if we were in Insert
2136 // mode when we left it.
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002137 restart_edit = win->w_buffer->b_prompt_insert;
2138}
2139#endif
2140
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141/*
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01002142 * Close all windows for buffer "buf".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 */
2144 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002145close_windows(
2146 buf_T *buf,
2147 int keep_curwin) /* don't close "curwin" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148{
Bram Moolenaarf740b292006-02-16 22:11:02 +00002149 win_T *wp;
2150 tabpage_T *tp, *nexttp;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002151 int h = tabline_height();
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002152 int count = tabpage_index(NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153
2154 ++RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002155
Bram Moolenaar459ca562016-11-10 18:16:33 +01002156 for (wp = firstwin; wp != NULL && !ONE_WINDOW; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 {
Bram Moolenaar362ce482012-06-06 19:02:45 +02002158 if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002159 && !(wp->w_closing || wp->w_buffer->b_locked > 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 {
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01002161 if (win_close(wp, FALSE) == FAIL)
2162 /* If closing the window fails give up, to avoid looping
2163 * forever. */
2164 break;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002165
2166 /* Start all over, autocommands may change the window layout. */
2167 wp = firstwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 }
2169 else
Bram Moolenaarf740b292006-02-16 22:11:02 +00002170 wp = wp->w_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171 }
Bram Moolenaarf740b292006-02-16 22:11:02 +00002172
2173 /* Also check windows in other tab pages. */
2174 for (tp = first_tabpage; tp != NULL; tp = nexttp)
2175 {
2176 nexttp = tp->tp_next;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002177 if (tp != curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002178 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002179 if (wp->w_buffer == buf
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002180 && !(wp->w_closing || wp->w_buffer->b_locked > 0))
Bram Moolenaarf740b292006-02-16 22:11:02 +00002181 {
2182 win_close_othertab(wp, FALSE, tp);
2183
2184 /* Start all over, the tab page may be closed and
2185 * autocommands may change the window layout. */
2186 nexttp = first_tabpage;
2187 break;
2188 }
2189 }
2190
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191 --RedrawingDisabled;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002192
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002193 if (count != tabpage_index(NULL))
2194 apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002195
Bram Moolenaar4c7e9db2013-04-15 15:55:19 +02002196 redraw_tabline = TRUE;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002197 if (h != tabline_height())
Bram Moolenaarf740b292006-02-16 22:11:02 +00002198 shell_new_rows();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199}
2200
2201/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002202 * Return TRUE if the current window is the only window that exists (ignoring
2203 * "aucmd_win").
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002204 * Returns FALSE if there is a window, possibly in another tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002205 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002206 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002207last_window(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002208{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002209 return (one_window() && first_tabpage->tp_next == NULL);
2210}
2211
2212/*
2213 * Return TRUE if there is only one window other than "aucmd_win" in the
2214 * current tab page.
2215 */
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002216 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002217one_window(void)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002218{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002219 win_T *wp;
2220 int seen_one = FALSE;
2221
2222 FOR_ALL_WINDOWS(wp)
2223 {
2224 if (wp != aucmd_win)
2225 {
2226 if (seen_one)
2227 return FALSE;
2228 seen_one = TRUE;
2229 }
2230 }
2231 return TRUE;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002232}
2233
2234/*
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002235 * Close the possibly last window in a tab page.
2236 * Returns TRUE when the window was closed already.
2237 */
2238 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002239close_last_window_tabpage(
2240 win_T *win,
2241 int free_buf,
2242 tabpage_T *prev_curtab)
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002243{
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002244 if (ONE_WINDOW)
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002245 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002246 buf_T *old_curbuf = curbuf;
2247
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002248 /*
2249 * Closing the last window in a tab page. First go to another tab
2250 * page and then close the window and the tab page. This avoids that
2251 * curwin and curtab are invalid while we are freeing memory, they may
2252 * be used in GUI events.
Bram Moolenaara8596c42012-06-13 14:28:20 +02002253 * Don't trigger autocommands yet, they may use wrong values, so do
2254 * that below.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002255 */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002256 goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002257 redraw_tabline = TRUE;
2258
2259 /* Safety check: Autocommands may have closed the window when jumping
2260 * to the other tab page. */
2261 if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win)
2262 {
2263 int h = tabline_height();
2264
2265 win_close_othertab(win, free_buf, prev_curtab);
2266 if (h != tabline_height())
2267 shell_new_rows();
2268 }
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002269#ifdef FEAT_JOB_CHANNEL
2270 entering_window(curwin);
2271#endif
Bram Moolenaara8596c42012-06-13 14:28:20 +02002272 /* Since goto_tabpage_tp above did not trigger *Enter autocommands, do
2273 * that now. */
Bram Moolenaar12c11d52016-07-19 23:13:03 +02002274 apply_autocmds(EVENT_TABCLOSED, NULL, NULL, FALSE, curbuf);
Bram Moolenaara8596c42012-06-13 14:28:20 +02002275 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002276 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
2277 if (old_curbuf != curbuf)
2278 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002279 return TRUE;
2280 }
2281 return FALSE;
2282}
2283
2284/*
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002285 * Close window "win". Only works for the current tab page.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 * If "free_buf" is TRUE related buffer may be unloaded.
2287 *
Bram Moolenaar42ec6562012-02-22 14:58:37 +01002288 * Called by :quit, :close, :xit, :wq and findtag().
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002289 * Returns FAIL when the window was not closed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 */
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002291 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002292win_close(win_T *win, int free_buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293{
2294 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295 int other_buffer = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 int close_curwin = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 int dir;
2298 int help_window = FALSE;
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002299 tabpage_T *prev_curtab = curtab;
Bram Moolenaar41cc0382017-06-26 09:59:35 +02002300 frame_T *win_frame = win->w_frame->fr_parent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002302 if (last_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 {
2304 EMSG(_("E444: Cannot close last window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002305 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 }
2307
Bram Moolenaare0ab94e2016-09-04 19:50:54 +02002308 if (win->w_closing || (win->w_buffer != NULL
2309 && win->w_buffer->b_locked > 0))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002310 return FAIL; /* window is already being closed */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002311 if (win == aucmd_win)
2312 {
2313 EMSG(_("E813: Cannot close autocmd window"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002314 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002315 }
2316 if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
2317 {
2318 EMSG(_("E814: Cannot close window, only autocmd window would remain"));
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002319 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002320 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002321
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002322 /* When closing the last window in a tab page first go to another tab page
2323 * and then close the window and the tab page to avoid that curwin and
2324 * curtab are invalid while we are freeing memory. */
2325 if (close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002326 return FAIL;
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002327
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 /* When closing the help window, try restoring a snapshot after closing
2329 * the window. Otherwise clear the snapshot, it's now invalid. */
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02002330 if (bt_help(win->w_buffer))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 help_window = TRUE;
2332 else
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002333 clear_snapshot(curtab, SNAP_HELP_IDX);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002334
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 if (win == curwin)
2336 {
Bram Moolenaar6d41c782018-06-06 09:11:12 +02002337#ifdef FEAT_JOB_CHANNEL
2338 leaving_window(curwin);
2339#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 /*
2341 * Guess which window is going to be the new current window.
2342 * This may change because of the autocommands (sigh).
2343 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002344 wp = frame2win(win_altframe(win, NULL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345
2346 /*
Bram Moolenaar362ce482012-06-06 19:02:45 +02002347 * Be careful: If autocommands delete the window or cause this window
2348 * to be the last one left, return now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 */
2350 if (wp->w_buffer != curbuf)
2351 {
2352 other_buffer = TRUE;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002353 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002355 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002356 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002357 win->w_closing = FALSE;
2358 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002359 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 }
Bram Moolenaar362ce482012-06-06 19:02:45 +02002361 win->w_closing = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002362 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002363 if (!win_valid(win))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002364 return FAIL;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002365 win->w_closing = FALSE;
2366 if (last_window())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002367 return FAIL;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002368#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 /* autocmds may abort script processing */
2370 if (aborting())
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002371 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01002373 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374
Bram Moolenaar053b9fa2007-04-26 14:09:42 +00002375#ifdef FEAT_GUI
2376 /* Avoid trouble with scrollbars that are going to be deleted in
2377 * win_free(). */
2378 if (gui.in_use)
2379 out_flush();
2380#endif
2381
Bram Moolenaara971b822011-09-14 14:43:25 +02002382#ifdef FEAT_SYN_HL
2383 /* Free independent synblock before the buffer is freed. */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002384 if (win->w_buffer != NULL)
2385 reset_synblock(win);
Bram Moolenaara971b822011-09-14 14:43:25 +02002386#endif
2387
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 /*
2389 * Close the link to the buffer.
2390 */
Bram Moolenaarfc573802011-12-30 15:01:59 +01002391 if (win->w_buffer != NULL)
Bram Moolenaar362ce482012-06-06 19:02:45 +02002392 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002393 bufref_T bufref;
2394
2395 set_bufref(&bufref, curbuf);
Bram Moolenaar362ce482012-06-06 19:02:45 +02002396 win->w_closing = TRUE;
Bram Moolenaar8f913992012-08-29 15:50:26 +02002397 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002398 if (win_valid_any_tab(win))
Bram Moolenaar362ce482012-06-06 19:02:45 +02002399 win->w_closing = FALSE;
Bram Moolenaar62ef7972016-01-19 14:51:54 +01002400 /* Make sure curbuf is valid. It can become invalid if 'bufhidden' is
2401 * "wipe". */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002402 if (!bufref_valid(&bufref))
Bram Moolenaar62ef7972016-01-19 14:51:54 +01002403 curbuf = firstbuf;
Bram Moolenaar362ce482012-06-06 19:02:45 +02002404 }
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002405
Bram Moolenaar802418d2013-01-17 14:00:11 +01002406 if (only_one_window() && win_valid(win) && win->w_buffer == NULL
2407 && (last_window() || curtab != prev_curtab
2408 || close_last_window_tabpage(win, free_buf, prev_curtab)))
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002409 {
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02002410 /* Autocommands have closed all windows, quit now. Restore
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002411 * curwin->w_buffer, otherwise writing viminfo may fail. */
2412 if (curwin->w_buffer == NULL)
2413 curwin->w_buffer = curbuf;
Bram Moolenaar802418d2013-01-17 14:00:11 +01002414 getout(0);
Bram Moolenaar2b90ed22013-07-24 16:02:36 +02002415 }
Bram Moolenaar802418d2013-01-17 14:00:11 +01002416
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002417 /* Autocommands may have moved to another tab page. */
2418 if (curtab != prev_curtab && win_valid_any_tab(win)
2419 && win->w_buffer == NULL)
2420 {
2421 /* Need to close the window anyway, since the buffer is NULL. */
2422 win_close_othertab(win, FALSE, prev_curtab);
2423 return FAIL;
2424 }
2425
2426 /* Autocommands may have closed the window already or closed the only
2427 * other window. */
2428 if (!win_valid(win) || last_window()
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002429 || close_last_window_tabpage(win, free_buf, prev_curtab))
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002430 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431
Bram Moolenaara971b822011-09-14 14:43:25 +02002432 /* Free the memory used for the window and get the window that received
2433 * the screen space. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002434 wp = win_free_mem(win, &dir, NULL);
2435
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 /* Make sure curwin isn't invalid. It can cause severe trouble when
2437 * printing an error message. For win_equal() curbuf needs to be valid
2438 * too. */
Bram Moolenaarc1b52862006-04-28 22:32:28 +00002439 if (win == curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 {
2441 curwin = wp;
2442#ifdef FEAT_QUICKFIX
2443 if (wp->w_p_pvw || bt_quickfix(wp->w_buffer))
2444 {
2445 /*
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002446 * If the cursor goes to the preview or the quickfix window, try
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447 * finding another window to go to.
2448 */
2449 for (;;)
2450 {
2451 if (wp->w_next == NULL)
2452 wp = firstwin;
2453 else
2454 wp = wp->w_next;
2455 if (wp == curwin)
2456 break;
2457 if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer))
2458 {
2459 curwin = wp;
2460 break;
2461 }
2462 }
2463 }
2464#endif
2465 curbuf = curwin->w_buffer;
2466 close_curwin = TRUE;
Bram Moolenaarf79225e2017-03-18 23:11:04 +01002467
2468 /* The cursor position may be invalid if the buffer changed after last
2469 * using the window. */
2470 check_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471 }
Bram Moolenaar44a2f922016-03-19 22:11:51 +01002472 if (p_ea && (*p_ead == 'b' || *p_ead == dir))
Bram Moolenaar8eeeba82017-06-25 22:45:39 +02002473 /* If the frame of the closed window contains the new current window,
2474 * only resize that frame. Otherwise resize all windows. */
Bram Moolenaar41cc0382017-06-26 09:59:35 +02002475 win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476 else
2477 win_comp_pos();
2478 if (close_curwin)
2479 {
Bram Moolenaarc917da42016-07-19 22:31:36 +02002480 win_enter_ext(wp, FALSE, TRUE, FALSE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 if (other_buffer)
2482 /* careful: after this wp and win may be invalid! */
2483 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484 }
2485
2486 /*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002487 * If last window has a status line now and we don't want one,
2488 * remove the status line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489 */
2490 last_status(FALSE);
2491
2492 /* After closing the help window, try restoring the window layout from
2493 * before it was opened. */
2494 if (help_window)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002495 restore_snapshot(SNAP_HELP_IDX, close_curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002496
Bram Moolenaar44a2f922016-03-19 22:11:51 +01002497#if defined(FEAT_GUI)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
2499 if (gui.in_use && !win_hasvertsplit())
2500 gui_init_which_components(NULL);
2501#endif
2502
2503 redraw_all_later(NOT_VALID);
Bram Moolenaarc93df6b2013-08-14 17:11:20 +02002504 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505}
2506
2507/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002508 * Close window "win" in tab page "tp", which is not the current tab page.
Bram Moolenaarbef1c362012-05-25 12:39:00 +02002509 * This may be the last window in that tab page and result in closing the tab,
Bram Moolenaarf740b292006-02-16 22:11:02 +00002510 * thus "tp" may become invalid!
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002511 * Caller must check if buffer is hidden and whether the tabline needs to be
2512 * updated.
Bram Moolenaarf740b292006-02-16 22:11:02 +00002513 */
2514 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002515win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002516{
2517 win_T *wp;
2518 int dir;
2519 tabpage_T *ptp = NULL;
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002520 int free_tp = FALSE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002521
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002522 /* Get here with win->w_buffer == NULL when win_close() detects the tab
2523 * page changed. */
Bram Moolenaare0ab94e2016-09-04 19:50:54 +02002524 if (win->w_closing || (win->w_buffer != NULL
2525 && win->w_buffer->b_locked > 0))
Bram Moolenaar362ce482012-06-06 19:02:45 +02002526 return; /* window is already being closed */
Bram Moolenaar362ce482012-06-06 19:02:45 +02002527
Bram Moolenaar11fbc282016-09-02 21:48:32 +02002528 if (win->w_buffer != NULL)
2529 /* Close the link to the buffer. */
2530 close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, FALSE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002531
2532 /* Careful: Autocommands may have closed the tab page or made it the
2533 * current tab page. */
2534 for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
2535 ;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002536 if (ptp == NULL || tp == curtab)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002537 return;
2538
2539 /* Autocommands may have closed the window already. */
2540 for (wp = tp->tp_firstwin; wp != NULL && wp != win; wp = wp->w_next)
2541 ;
2542 if (wp == NULL)
2543 return;
2544
Bram Moolenaarf740b292006-02-16 22:11:02 +00002545 /* When closing the last window in a tab page remove the tab page. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02002546 if (tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002547 {
2548 if (tp == first_tabpage)
2549 first_tabpage = tp->tp_next;
2550 else
2551 {
2552 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
2553 ptp = ptp->tp_next)
2554 ;
2555 if (ptp == NULL)
2556 {
Bram Moolenaar95f09602016-11-10 20:01:45 +01002557 internal_error("win_close_othertab()");
Bram Moolenaarf740b292006-02-16 22:11:02 +00002558 return;
2559 }
2560 ptp->tp_next = tp->tp_next;
2561 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002562 free_tp = TRUE;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002563 }
Bram Moolenaar4d770fb2010-07-12 21:38:19 +02002564
2565 /* Free the memory used for the window. */
2566 win_free_mem(win, &dir, tp);
2567
2568 if (free_tp)
2569 free_tabpage(tp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002570}
2571
2572/*
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002573 * Free the memory used for a window.
2574 * Returns a pointer to the window that got the freed up space.
2575 */
2576 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002577win_free_mem(
2578 win_T *win,
2579 int *dirp, /* set to 'v' or 'h' for direction if 'ea' */
2580 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002581{
2582 frame_T *frp;
2583 win_T *wp;
2584
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002585 /* Remove the window and its frame from the tree of frames. */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002586 frp = win->w_frame;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002587 wp = winframe_remove(win, dirp, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002588 vim_free(frp);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002589 win_free(win, tp);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002590
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002591 /* When deleting the current window of another tab page select a new
2592 * current window. */
2593 if (tp != NULL && win == tp->tp_curwin)
2594 tp->tp_curwin = wp;
2595
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002596 return wp;
2597}
2598
2599#if defined(EXITFREE) || defined(PROTO)
2600 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002601win_free_all(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002602{
2603 int dummy;
2604
Bram Moolenaarf740b292006-02-16 22:11:02 +00002605 while (first_tabpage->tp_next != NULL)
2606 tabpage_close(TRUE);
Bram Moolenaarf740b292006-02-16 22:11:02 +00002607
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002608 if (aucmd_win != NULL)
2609 {
2610 (void)win_free_mem(aucmd_win, &dummy, NULL);
2611 aucmd_win = NULL;
2612 }
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00002613
2614 while (firstwin != NULL)
2615 (void)win_free_mem(firstwin, &dummy, NULL);
Bram Moolenaar4e036c92014-07-16 16:30:28 +02002616
2617 /* No window should be used after this. Set curwin to NULL to crash
2618 * instead of using freed memory. */
2619 curwin = NULL;
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002620}
2621#endif
2622
2623/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 * Remove a window and its frame from the tree of frames.
2625 * Returns a pointer to the window that got the freed up space.
2626 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00002627 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002628winframe_remove(
2629 win_T *win,
2630 int *dirp UNUSED, /* set to 'v' or 'h' for direction if 'ea' */
2631 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632{
2633 frame_T *frp, *frp2, *frp3;
2634 frame_T *frp_close = win->w_frame;
2635 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636
2637 /*
Bram Moolenaarf740b292006-02-16 22:11:02 +00002638 * If there is only one window there is nothing to remove.
2639 */
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002640 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaarf740b292006-02-16 22:11:02 +00002641 return NULL;
2642
2643 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 * Remove the window from its frame.
2645 */
Bram Moolenaarf740b292006-02-16 22:11:02 +00002646 frp2 = win_altframe(win, tp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 wp = frame2win(frp2);
2648
2649 /* Remove this frame from the list of frames. */
2650 frame_remove(frp_close);
2651
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 if (frp_close->fr_parent->fr_layout == FR_COL)
2653 {
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002654 /* When 'winfixheight' is set, try to find another frame in the column
2655 * (as close to the closed frame as possible) to distribute the height
2656 * to. */
2657 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh)
2658 {
2659 frp = frp_close->fr_prev;
2660 frp3 = frp_close->fr_next;
2661 while (frp != NULL || frp3 != NULL)
2662 {
2663 if (frp != NULL)
2664 {
2665 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh)
2666 {
2667 frp2 = frp;
2668 wp = frp->fr_win;
2669 break;
2670 }
2671 frp = frp->fr_prev;
2672 }
2673 if (frp3 != NULL)
2674 {
2675 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh)
2676 {
2677 frp2 = frp3;
2678 wp = frp3->fr_win;
2679 break;
2680 }
2681 frp3 = frp3->fr_next;
2682 }
2683 }
2684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
2686 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002687 *dirp = 'v';
2688 }
2689 else
2690 {
Bram Moolenaar48cc5fe2007-08-11 11:39:45 +00002691 /* When 'winfixwidth' is set, try to find another frame in the column
2692 * (as close to the closed frame as possible) to distribute the width
2693 * to. */
2694 if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw)
2695 {
2696 frp = frp_close->fr_prev;
2697 frp3 = frp_close->fr_next;
2698 while (frp != NULL || frp3 != NULL)
2699 {
2700 if (frp != NULL)
2701 {
2702 if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw)
2703 {
2704 frp2 = frp;
2705 wp = frp->fr_win;
2706 break;
2707 }
2708 frp = frp->fr_prev;
2709 }
2710 if (frp3 != NULL)
2711 {
2712 if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw)
2713 {
2714 frp2 = frp3;
2715 wp = frp3->fr_win;
2716 break;
2717 }
2718 frp3 = frp3->fr_next;
2719 }
2720 }
2721 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002723 frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 *dirp = 'h';
2725 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
2727 /* If rows/columns go to a window below/right its positions need to be
2728 * updated. Can only be done after the sizes have been updated. */
2729 if (frp2 == frp_close->fr_next)
2730 {
2731 int row = win->w_winrow;
Bram Moolenaar53f81742017-09-22 14:35:51 +02002732 int col = win->w_wincol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733
2734 frame_comp_pos(frp2, &row, &col);
2735 }
2736
2737 if (frp2->fr_next == NULL && frp2->fr_prev == NULL)
2738 {
2739 /* There is no other frame in this list, move its info to the parent
2740 * and remove it. */
2741 frp2->fr_parent->fr_layout = frp2->fr_layout;
2742 frp2->fr_parent->fr_child = frp2->fr_child;
2743 for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
2744 frp->fr_parent = frp2->fr_parent;
2745 frp2->fr_parent->fr_win = frp2->fr_win;
2746 if (frp2->fr_win != NULL)
2747 frp2->fr_win->w_frame = frp2->fr_parent;
2748 frp = frp2->fr_parent;
Bram Moolenaar6f361c92018-01-31 19:06:50 +01002749 if (topframe->fr_child == frp2)
2750 topframe->fr_child = frp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 vim_free(frp2);
2752
2753 frp2 = frp->fr_parent;
2754 if (frp2 != NULL && frp2->fr_layout == frp->fr_layout)
2755 {
2756 /* The frame above the parent has the same layout, have to merge
2757 * the frames into this list. */
2758 if (frp2->fr_child == frp)
2759 frp2->fr_child = frp->fr_child;
2760 frp->fr_child->fr_prev = frp->fr_prev;
2761 if (frp->fr_prev != NULL)
2762 frp->fr_prev->fr_next = frp->fr_child;
2763 for (frp3 = frp->fr_child; ; frp3 = frp3->fr_next)
2764 {
2765 frp3->fr_parent = frp2;
2766 if (frp3->fr_next == NULL)
2767 {
2768 frp3->fr_next = frp->fr_next;
2769 if (frp->fr_next != NULL)
2770 frp->fr_next->fr_prev = frp3;
2771 break;
2772 }
2773 }
Bram Moolenaar6f361c92018-01-31 19:06:50 +01002774 if (topframe->fr_child == frp)
2775 topframe->fr_child = frp2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 vim_free(frp);
2777 }
2778 }
2779
2780 return wp;
2781}
2782
2783/*
Bram Moolenaarc136af22018-05-04 20:15:38 +02002784 * Return a pointer to the frame that will receive the empty screen space that
2785 * is left over after "win" is closed.
2786 *
2787 * If 'splitbelow' or 'splitright' is set, the space goes above or to the left
2788 * by default. Otherwise, the free space goes below or to the right. The
2789 * result is that opening a window and then immediately closing it will
2790 * preserve the initial window layout. The 'wfh' and 'wfw' settings are
2791 * respected when possible.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 */
2793 static frame_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002794win_altframe(
2795 win_T *win,
2796 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797{
2798 frame_T *frp;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002799 frame_T *other_fr, *target_fr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800
Bram Moolenaara1f4cb92016-11-06 15:25:42 +01002801 if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002802 return alt_tabpage()->tp_curwin->w_frame;
2803
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804 frp = win->w_frame;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002805
2806 if (frp->fr_prev == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 return frp->fr_next;
Bram Moolenaarc136af22018-05-04 20:15:38 +02002808 if (frp->fr_next == NULL)
2809 return frp->fr_prev;
2810
2811 target_fr = frp->fr_next;
2812 other_fr = frp->fr_prev;
2813 if (p_spr || p_sb)
2814 {
2815 target_fr = frp->fr_prev;
2816 other_fr = frp->fr_next;
2817 }
2818
2819 /* If 'wfh' or 'wfw' is set for the target and not for the alternate
2820 * window, reverse the selection. */
2821 if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW)
2822 {
2823 if (frame_fixed_width(target_fr) && !frame_fixed_width(other_fr))
2824 target_fr = other_fr;
2825 }
2826 else
2827 {
2828 if (frame_fixed_height(target_fr) && !frame_fixed_height(other_fr))
2829 target_fr = other_fr;
2830 }
2831
2832 return target_fr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002833}
2834
2835/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002836 * Return the tabpage that will be used if the current one is closed.
2837 */
2838 static tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002839alt_tabpage(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002840{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002841 tabpage_T *tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002842
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002843 /* Use the next tab page if possible. */
2844 if (curtab->tp_next != NULL)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00002845 return curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002846
Bram Moolenaar80a94a52006-02-23 21:26:58 +00002847 /* Find the last but one tab page. */
2848 for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
2849 ;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00002850 return tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002851}
2852
2853/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002854 * Find the left-upper window in frame "frp".
2855 */
2856 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002857frame2win(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858{
2859 while (frp->fr_win == NULL)
2860 frp = frp->fr_child;
2861 return frp->fr_win;
2862}
2863
2864/*
2865 * Return TRUE if frame "frp" contains window "wp".
2866 */
2867 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002868frame_has_win(frame_T *frp, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869{
2870 frame_T *p;
2871
2872 if (frp->fr_layout == FR_LEAF)
2873 return frp->fr_win == wp;
2874
2875 for (p = frp->fr_child; p != NULL; p = p->fr_next)
2876 if (frame_has_win(p, wp))
2877 return TRUE;
2878 return FALSE;
2879}
2880
2881/*
2882 * Set a new height for a frame. Recursively sets the height for contained
2883 * frames and windows. Caller must take care of positions.
2884 */
2885 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002886frame_new_height(
2887 frame_T *topfrp,
2888 int height,
2889 int topfirst, /* resize topmost contained frame first */
2890 int wfh) /* obey 'winfixheight' when there is a choice;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891 may cause the height not to be set */
2892{
2893 frame_T *frp;
2894 int extra_lines;
2895 int h;
2896
2897 if (topfrp->fr_win != NULL)
2898 {
2899 /* Simple case: just one window. */
2900 win_new_height(topfrp->fr_win,
Bram Moolenaard326ad62017-09-18 20:31:41 +02002901 height - topfrp->fr_win->w_status_height
Bram Moolenaar3167c3e2017-11-25 14:19:43 +01002902 - WINBAR_HEIGHT(topfrp->fr_win));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002904 else if (topfrp->fr_layout == FR_ROW)
2905 {
2906 do
2907 {
2908 /* All frames in this row get the same new height. */
2909 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
2910 {
2911 frame_new_height(frp, height, topfirst, wfh);
2912 if (frp->fr_height > height)
2913 {
2914 /* Could not fit the windows, make the whole row higher. */
2915 height = frp->fr_height;
2916 break;
2917 }
2918 }
2919 }
2920 while (frp != NULL);
2921 }
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00002922 else /* fr_layout == FR_COL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 {
2924 /* Complicated case: Resize a column of frames. Resize the bottom
2925 * frame first, frames above that when needed. */
2926
2927 frp = topfrp->fr_child;
2928 if (wfh)
2929 /* Advance past frames with one window with 'wfh' set. */
2930 while (frame_fixed_height(frp))
2931 {
2932 frp = frp->fr_next;
2933 if (frp == NULL)
2934 return; /* no frame without 'wfh', give up */
2935 }
2936 if (!topfirst)
2937 {
2938 /* Find the bottom frame of this column */
2939 while (frp->fr_next != NULL)
2940 frp = frp->fr_next;
2941 if (wfh)
2942 /* Advance back for frames with one window with 'wfh' set. */
2943 while (frame_fixed_height(frp))
2944 frp = frp->fr_prev;
2945 }
2946
2947 extra_lines = height - topfrp->fr_height;
2948 if (extra_lines < 0)
2949 {
2950 /* reduce height of contained frames, bottom or top frame first */
2951 while (frp != NULL)
2952 {
2953 h = frame_minheight(frp, NULL);
2954 if (frp->fr_height + extra_lines < h)
2955 {
2956 extra_lines += frp->fr_height - h;
2957 frame_new_height(frp, h, topfirst, wfh);
2958 }
2959 else
2960 {
2961 frame_new_height(frp, frp->fr_height + extra_lines,
2962 topfirst, wfh);
2963 break;
2964 }
2965 if (topfirst)
2966 {
2967 do
2968 frp = frp->fr_next;
2969 while (wfh && frp != NULL && frame_fixed_height(frp));
2970 }
2971 else
2972 {
2973 do
2974 frp = frp->fr_prev;
2975 while (wfh && frp != NULL && frame_fixed_height(frp));
2976 }
2977 /* Increase "height" if we could not reduce enough frames. */
2978 if (frp == NULL)
2979 height -= extra_lines;
2980 }
2981 }
2982 else if (extra_lines > 0)
2983 {
2984 /* increase height of bottom or top frame */
2985 frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
2986 }
2987 }
2988 topfrp->fr_height = height;
2989}
2990
2991/*
2992 * Return TRUE if height of frame "frp" should not be changed because of
2993 * the 'winfixheight' option.
2994 */
2995 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01002996frame_fixed_height(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002997{
2998 /* frame with one window: fixed height if 'winfixheight' set. */
2999 if (frp->fr_win != NULL)
3000 return frp->fr_win->w_p_wfh;
3001
3002 if (frp->fr_layout == FR_ROW)
3003 {
3004 /* The frame is fixed height if one of the frames in the row is fixed
3005 * height. */
3006 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3007 if (frame_fixed_height(frp))
3008 return TRUE;
3009 return FALSE;
3010 }
3011
3012 /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
3013 * frames in the row are fixed height. */
3014 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3015 if (!frame_fixed_height(frp))
3016 return FALSE;
3017 return TRUE;
3018}
3019
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020/*
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003021 * Return TRUE if width of frame "frp" should not be changed because of
3022 * the 'winfixwidth' option.
3023 */
3024 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003025frame_fixed_width(frame_T *frp)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003026{
3027 /* frame with one window: fixed width if 'winfixwidth' set. */
3028 if (frp->fr_win != NULL)
3029 return frp->fr_win->w_p_wfw;
3030
3031 if (frp->fr_layout == FR_COL)
3032 {
3033 /* The frame is fixed width if one of the frames in the row is fixed
3034 * width. */
3035 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3036 if (frame_fixed_width(frp))
3037 return TRUE;
3038 return FALSE;
3039 }
3040
3041 /* frp->fr_layout == FR_ROW: The frame is fixed width if all of the
3042 * frames in the row are fixed width. */
3043 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3044 if (!frame_fixed_width(frp))
3045 return FALSE;
3046 return TRUE;
3047}
3048
3049/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 * Add a status line to windows at the bottom of "frp".
3051 * Note: Does not check if there is room!
3052 */
3053 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003054frame_add_statusline(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055{
3056 win_T *wp;
3057
3058 if (frp->fr_layout == FR_LEAF)
3059 {
3060 wp = frp->fr_win;
3061 if (wp->w_status_height == 0)
3062 {
3063 if (wp->w_height > 0) /* don't make it negative */
3064 --wp->w_height;
3065 wp->w_status_height = STATUS_HEIGHT;
3066 }
3067 }
3068 else if (frp->fr_layout == FR_ROW)
3069 {
3070 /* Handle all the frames in the row. */
3071 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3072 frame_add_statusline(frp);
3073 }
3074 else /* frp->fr_layout == FR_COL */
3075 {
3076 /* Only need to handle the last frame in the column. */
3077 for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
3078 ;
3079 frame_add_statusline(frp);
3080 }
3081}
3082
3083/*
3084 * Set width of a frame. Handles recursively going through contained frames.
3085 * May remove separator line for windows at the right side (for win_close()).
3086 */
3087 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003088frame_new_width(
3089 frame_T *topfrp,
3090 int width,
3091 int leftfirst, /* resize leftmost contained frame first */
3092 int wfw) /* obey 'winfixwidth' when there is a choice;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003093 may cause the width not to be set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094{
3095 frame_T *frp;
3096 int extra_cols;
3097 int w;
3098 win_T *wp;
3099
3100 if (topfrp->fr_layout == FR_LEAF)
3101 {
3102 /* Simple case: just one window. */
3103 wp = topfrp->fr_win;
3104 /* Find out if there are any windows right of this one. */
3105 for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
3106 if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
3107 break;
3108 if (frp->fr_parent == NULL)
3109 wp->w_vsep_width = 0;
3110 win_new_width(wp, width - wp->w_vsep_width);
3111 }
3112 else if (topfrp->fr_layout == FR_COL)
3113 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003114 do
3115 {
3116 /* All frames in this column get the same new width. */
3117 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3118 {
3119 frame_new_width(frp, width, leftfirst, wfw);
3120 if (frp->fr_width > width)
3121 {
3122 /* Could not fit the windows, make whole column wider. */
3123 width = frp->fr_width;
3124 break;
3125 }
3126 }
3127 } while (frp != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 }
3129 else /* fr_layout == FR_ROW */
3130 {
3131 /* Complicated case: Resize a row of frames. Resize the rightmost
3132 * frame first, frames left of it when needed. */
3133
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 frp = topfrp->fr_child;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003135 if (wfw)
3136 /* Advance past frames with one window with 'wfw' set. */
3137 while (frame_fixed_width(frp))
3138 {
3139 frp = frp->fr_next;
3140 if (frp == NULL)
3141 return; /* no frame without 'wfw', give up */
3142 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 if (!leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003144 {
3145 /* Find the rightmost frame of this row */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146 while (frp->fr_next != NULL)
3147 frp = frp->fr_next;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003148 if (wfw)
3149 /* Advance back for frames with one window with 'wfw' set. */
3150 while (frame_fixed_width(frp))
3151 frp = frp->fr_prev;
3152 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153
3154 extra_cols = width - topfrp->fr_width;
3155 if (extra_cols < 0)
3156 {
3157 /* reduce frame width, rightmost frame first */
3158 while (frp != NULL)
3159 {
3160 w = frame_minwidth(frp, NULL);
3161 if (frp->fr_width + extra_cols < w)
3162 {
3163 extra_cols += frp->fr_width - w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003164 frame_new_width(frp, w, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 }
3166 else
3167 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003168 frame_new_width(frp, frp->fr_width + extra_cols,
3169 leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003170 break;
3171 }
3172 if (leftfirst)
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003173 {
3174 do
3175 frp = frp->fr_next;
3176 while (wfw && frp != NULL && frame_fixed_width(frp));
3177 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003178 else
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003179 {
3180 do
3181 frp = frp->fr_prev;
3182 while (wfw && frp != NULL && frame_fixed_width(frp));
3183 }
3184 /* Increase "width" if we could not reduce enough frames. */
3185 if (frp == NULL)
3186 width -= extra_cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 }
3188 }
3189 else if (extra_cols > 0)
3190 {
3191 /* increase width of rightmost frame */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00003192 frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193 }
3194 }
3195 topfrp->fr_width = width;
3196}
3197
3198/*
3199 * Add the vertical separator to windows at the right side of "frp".
3200 * Note: Does not check if there is room!
3201 */
3202 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003203frame_add_vsep(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204{
3205 win_T *wp;
3206
3207 if (frp->fr_layout == FR_LEAF)
3208 {
3209 wp = frp->fr_win;
3210 if (wp->w_vsep_width == 0)
3211 {
3212 if (wp->w_width > 0) /* don't make it negative */
3213 --wp->w_width;
3214 wp->w_vsep_width = 1;
3215 }
3216 }
3217 else if (frp->fr_layout == FR_COL)
3218 {
3219 /* Handle all the frames in the column. */
3220 for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
3221 frame_add_vsep(frp);
3222 }
3223 else /* frp->fr_layout == FR_ROW */
3224 {
3225 /* Only need to handle the last frame in the row. */
3226 frp = frp->fr_child;
3227 while (frp->fr_next != NULL)
3228 frp = frp->fr_next;
3229 frame_add_vsep(frp);
3230 }
3231}
3232
3233/*
3234 * Set frame width from the window it contains.
3235 */
3236 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003237frame_fix_width(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238{
3239 wp->w_frame->fr_width = wp->w_width + wp->w_vsep_width;
3240}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241
3242/*
3243 * Set frame height from the window it contains.
3244 */
3245 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003246frame_fix_height(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247{
Bram Moolenaar415a6932017-12-05 20:31:07 +01003248 wp->w_frame->fr_height = VISIBLE_HEIGHT(wp) + wp->w_status_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249}
3250
3251/*
3252 * Compute the minimal height for frame "topfrp".
3253 * Uses the 'winminheight' option.
3254 * When "next_curwin" isn't NULL, use p_wh for this window.
3255 * When "next_curwin" is NOWIN, don't use at least one line for the current
3256 * window.
3257 */
3258 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003259frame_minheight(frame_T *topfrp, win_T *next_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260{
3261 frame_T *frp;
3262 int m;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003264
3265 if (topfrp->fr_win != NULL)
3266 {
3267 if (topfrp->fr_win == next_curwin)
3268 m = p_wh + topfrp->fr_win->w_status_height;
3269 else
3270 {
3271 /* window: minimal height of the window plus status line */
3272 m = p_wmh + topfrp->fr_win->w_status_height;
Bram Moolenaar415a6932017-12-05 20:31:07 +01003273 if (topfrp->fr_win == curwin && next_curwin == NULL)
3274 {
3275 /* Current window is minimal one line high and WinBar is
3276 * visible. */
3277 if (p_wmh == 0)
3278 ++m;
3279 m += WINBAR_HEIGHT(curwin);
3280 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281 }
3282 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283 else if (topfrp->fr_layout == FR_ROW)
3284 {
3285 /* get the minimal height from each frame in this row */
3286 m = 0;
3287 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3288 {
3289 n = frame_minheight(frp, next_curwin);
3290 if (n > m)
3291 m = n;
3292 }
3293 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294 else
3295 {
3296 /* Add up the minimal heights for all frames in this column. */
3297 m = 0;
3298 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3299 m += frame_minheight(frp, next_curwin);
3300 }
3301
3302 return m;
3303}
3304
Bram Moolenaar071d4272004-06-13 20:20:40 +00003305/*
3306 * Compute the minimal width for frame "topfrp".
3307 * When "next_curwin" isn't NULL, use p_wiw for this window.
3308 * When "next_curwin" is NOWIN, don't use at least one column for the current
3309 * window.
3310 */
3311 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003312frame_minwidth(
3313 frame_T *topfrp,
3314 win_T *next_curwin) /* use p_wh and p_wiw for next_curwin */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315{
3316 frame_T *frp;
3317 int m, n;
3318
3319 if (topfrp->fr_win != NULL)
3320 {
3321 if (topfrp->fr_win == next_curwin)
3322 m = p_wiw + topfrp->fr_win->w_vsep_width;
3323 else
3324 {
3325 /* window: minimal width of the window plus separator column */
3326 m = p_wmw + topfrp->fr_win->w_vsep_width;
3327 /* Current window is minimal one column wide */
3328 if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
3329 ++m;
3330 }
3331 }
3332 else if (topfrp->fr_layout == FR_COL)
3333 {
3334 /* get the minimal width from each frame in this column */
3335 m = 0;
3336 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3337 {
3338 n = frame_minwidth(frp, next_curwin);
3339 if (n > m)
3340 m = n;
3341 }
3342 }
3343 else
3344 {
3345 /* Add up the minimal widths for all frames in this row. */
3346 m = 0;
3347 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
3348 m += frame_minwidth(frp, next_curwin);
3349 }
3350
3351 return m;
3352}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353
3354
3355/*
3356 * Try to close all windows except current one.
3357 * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
3358 * used and the buffer was modified.
3359 *
3360 * Used by ":bdel" and ":only".
3361 */
3362 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003363close_others(
3364 int message,
3365 int forceit) /* always hide all other windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366{
3367 win_T *wp;
3368 win_T *nextwp;
3369 int r;
3370
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003371 if (one_window())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01003373 if (message && !autocmd_busy)
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00003374 MSG(_(m_onlyone));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 return;
3376 }
3377
3378 /* Be very careful here: autocommands may change the window layout. */
3379 for (wp = firstwin; win_valid(wp); wp = nextwp)
3380 {
3381 nextwp = wp->w_next;
3382 if (wp != curwin) /* don't close current window */
3383 {
3384
3385 /* Check if it's allowed to abandon this window */
3386 r = can_abandon(wp->w_buffer, forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 if (!win_valid(wp)) /* autocommands messed wp up */
3388 {
3389 nextwp = firstwin;
3390 continue;
3391 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 if (!r)
3393 {
3394#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3395 if (message && (p_confirm || cmdmod.confirm) && p_write)
3396 {
3397 dialog_changed(wp->w_buffer, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 if (!win_valid(wp)) /* autocommands messed wp up */
3399 {
3400 nextwp = firstwin;
3401 continue;
3402 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403 }
3404 if (bufIsChanged(wp->w_buffer))
3405#endif
3406 continue;
3407 }
Bram Moolenaareb44a682017-08-03 22:44:55 +02003408 win_close(wp, !buf_hide(wp->w_buffer)
3409 && !bufIsChanged(wp->w_buffer));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410 }
3411 }
3412
Bram Moolenaar459ca562016-11-10 18:16:33 +01003413 if (message && !ONE_WINDOW)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414 EMSG(_("E445: Other window contains changes"));
3415}
3416
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003418 * Init the current window "curwin".
3419 * Called when a new file is being edited.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420 */
3421 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003422curwin_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003423{
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003424 win_init_empty(curwin);
3425}
3426
3427 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003428win_init_empty(win_T *wp)
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003429{
3430 redraw_win_later(wp, NOT_VALID);
3431 wp->w_lines_valid = 0;
3432 wp->w_cursor.lnum = 1;
3433 wp->w_curswant = wp->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434#ifdef FEAT_VIRTUALEDIT
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003435 wp->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003436#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003437 wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
3438 wp->w_pcmark.col = 0;
3439 wp->w_prev_pcmark.lnum = 0;
3440 wp->w_prev_pcmark.col = 0;
3441 wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003442#ifdef FEAT_DIFF
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003443 wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003444#endif
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003445 wp->w_botline = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446#ifdef FEAT_FKMAP
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003447 if (wp->w_p_rl)
3448 wp->w_farsi = W_CONV + W_R_L;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449 else
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00003450 wp->w_farsi = W_CONV;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003451#endif
Bram Moolenaara971b822011-09-14 14:43:25 +02003452#ifdef FEAT_SYN_HL
3453 wp->w_s = &wp->w_buffer->b_s;
3454#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455}
3456
3457/*
3458 * Allocate the first window and put an empty buffer in it.
3459 * Called from main().
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003460 * Return FAIL when something goes wrong (out of memory).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003462 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003463win_alloc_first(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464{
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003465 if (win_alloc_firstwin(NULL) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003466 return FAIL;
3467
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003468 first_tabpage = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003469 if (first_tabpage == NULL)
3470 return FAIL;
3471 first_tabpage->tp_topframe = topframe;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003472 curtab = first_tabpage;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003473
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003474 return OK;
3475}
3476
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003477/*
3478 * Init "aucmd_win". This can only be done after the first
3479 * window is fully initialized, thus it can't be in win_alloc_first().
3480 */
3481 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003482win_alloc_aucmd_win(void)
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003483{
3484 aucmd_win = win_alloc(NULL, TRUE);
3485 if (aucmd_win != NULL)
3486 {
3487 win_init_some(aucmd_win, curwin);
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003488 RESET_BINDING(aucmd_win);
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003489 new_frame(aucmd_win);
3490 }
3491}
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003492
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003493/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003494 * Allocate the first window or the first window in a new tab page.
3495 * When "oldwin" is NULL create an empty buffer for it.
Bram Moolenaar4033c552017-09-16 20:54:51 +02003496 * When "oldwin" is not NULL copy info from it to the new window.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003497 * Return FAIL when something goes wrong (out of memory).
3498 */
3499 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003500win_alloc_firstwin(win_T *oldwin)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003501{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003502 curwin = win_alloc(NULL, FALSE);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003503 if (oldwin == NULL)
3504 {
3505 /* Very first window, need to create an empty buffer for it and
3506 * initialize from scratch. */
3507 curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED);
3508 if (curwin == NULL || curbuf == NULL)
3509 return FAIL;
3510 curwin->w_buffer = curbuf;
Bram Moolenaar860cae12010-06-05 23:22:07 +02003511#ifdef FEAT_SYN_HL
3512 curwin->w_s = &(curbuf->b_s);
3513#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003514 curbuf->b_nwindows = 1; /* there is one window */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003515 curwin->w_alist = &global_alist;
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003516 curwin_init(); /* init current window */
3517 }
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003518 else
3519 {
3520 /* First window in new tab page, initialize it from "oldwin". */
Bram Moolenaar884ae642009-02-22 01:37:59 +00003521 win_init(curwin, oldwin, 0);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003522
Bram Moolenaar3368ea22010-09-21 16:56:35 +02003523 /* We don't want cursor- and scroll-binding in the first window. */
3524 RESET_BINDING(curwin);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003525 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003527 new_frame(curwin);
3528 if (curwin->w_frame == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003529 return FAIL;
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003530 topframe = curwin->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 topframe->fr_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 topframe->fr_height = Rows - p_ch;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003533
3534 return OK;
3535}
3536
3537/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003538 * Create a frame for window "wp".
3539 */
3540 static void
3541new_frame(win_T *wp)
3542{
3543 frame_T *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
3544
3545 wp->w_frame = frp;
3546 if (frp != NULL)
3547 {
3548 frp->fr_layout = FR_LEAF;
3549 frp->fr_win = wp;
3550 }
3551}
3552
3553/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003554 * Initialize the window and frame size to the maximum.
3555 */
3556 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003557win_init_size(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003558{
3559 firstwin->w_height = ROWS_AVAIL;
3560 topframe->fr_height = ROWS_AVAIL;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003561 firstwin->w_width = Columns;
3562 topframe->fr_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003563}
3564
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003565/*
3566 * Allocate a new tabpage_T and init the values.
3567 * Returns NULL when out of memory.
3568 */
3569 static tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003570alloc_tabpage(void)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003571{
3572 tabpage_T *tp;
Bram Moolenaar429fa852013-04-15 12:27:36 +02003573# ifdef FEAT_GUI
3574 int i;
3575# endif
3576
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003577
3578 tp = (tabpage_T *)alloc_clear((unsigned)sizeof(tabpage_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02003579 if (tp == NULL)
3580 return NULL;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003581
Bram Moolenaar429fa852013-04-15 12:27:36 +02003582# ifdef FEAT_EVAL
3583 /* init t: variables */
3584 tp->tp_vars = dict_alloc();
3585 if (tp->tp_vars == NULL)
3586 {
3587 vim_free(tp);
3588 return NULL;
3589 }
3590 init_var_dict(tp->tp_vars, &tp->tp_winvar, VAR_SCOPE);
3591# endif
3592
3593# ifdef FEAT_GUI
3594 for (i = 0; i < 3; i++)
3595 tp->tp_prev_which_scrollbars[i] = -1;
Bram Moolenaar371d5402006-03-20 21:47:49 +00003596# endif
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003597# ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02003598 tp->tp_diff_invalid = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003599# endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02003600 tp->tp_ch_used = p_ch;
3601
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003602 return tp;
3603}
3604
Bram Moolenaard8fc5c02006-04-29 21:55:22 +00003605 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003606free_tabpage(tabpage_T *tp)
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003607{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003608 int idx;
3609
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003610# ifdef FEAT_DIFF
3611 diff_clear(tp);
3612# endif
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003613 for (idx = 0; idx < SNAP_COUNT; ++idx)
3614 clear_snapshot(tp, idx);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003615#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02003616 vars_clear(&tp->tp_vars->dv_hashtab); /* free all t: variables */
3617 hash_init(&tp->tp_vars->dv_hashtab);
3618 unref_var_dict(tp->tp_vars);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003619#endif
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02003620
3621#ifdef FEAT_PYTHON
3622 python_tabpage_free(tp);
3623#endif
3624
3625#ifdef FEAT_PYTHON3
3626 python3_tabpage_free(tp);
3627#endif
3628
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003629 vim_free(tp);
3630}
3631
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003632/*
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003633 * Create a new Tab page with one window.
3634 * It will edit the current buffer, like after ":split".
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003635 * When "after" is 0 put it just after the current Tab page.
3636 * Otherwise put it just before tab page "after".
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003637 * Return FAIL or OK.
3638 */
3639 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003640win_new_tabpage(int after)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003641{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003642 tabpage_T *tp = curtab;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003643 tabpage_T *newtp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003644 int n;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003645
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003646 newtp = alloc_tabpage();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003647 if (newtp == NULL)
3648 return FAIL;
3649
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003650 /* Remember the current windows in this Tab page. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003651 if (leave_tabpage(curbuf, TRUE) == FAIL)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003652 {
3653 vim_free(newtp);
3654 return FAIL;
3655 }
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003656 curtab = newtp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003657
3658 /* Create a new empty window. */
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003659 if (win_alloc_firstwin(tp->tp_curwin) == OK)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003660 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003661 /* Make the new Tab page the new topframe. */
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003662 if (after == 1)
3663 {
3664 /* New tab page becomes the first one. */
3665 newtp->tp_next = first_tabpage;
3666 first_tabpage = newtp;
3667 }
3668 else
3669 {
3670 if (after > 0)
3671 {
3672 /* Put new tab page before tab page "after". */
3673 n = 2;
3674 for (tp = first_tabpage; tp->tp_next != NULL
3675 && n < after; tp = tp->tp_next)
3676 ++n;
3677 }
3678 newtp->tp_next = tp->tp_next;
3679 tp->tp_next = newtp;
3680 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003681 win_init_size();
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003682 firstwin->w_winrow = tabline_height();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003683 win_comp_scroll(curwin);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003684
3685 newtp->tp_topframe = topframe;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003686 last_status(FALSE);
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003687
3688#if defined(FEAT_GUI)
3689 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3690 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003691 gui_may_update_scrollbars();
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003692#endif
Bram Moolenaar6d41c782018-06-06 09:11:12 +02003693#ifdef FEAT_JOB_CHANNEL
3694 entering_window(curwin);
3695#endif
Bram Moolenaar607a95ed2006-03-28 20:57:42 +00003696
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003697 redraw_all_later(CLEAR);
Bram Moolenaarc917da42016-07-19 22:31:36 +02003698 apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003699 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaarc917da42016-07-19 22:31:36 +02003700 apply_autocmds(EVENT_TABNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003701 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003702 return OK;
3703 }
3704
3705 /* Failed, get back the previous Tab page */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003706 enter_tabpage(curtab, curbuf, TRUE, TRUE);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003707 return FAIL;
3708}
3709
3710/*
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003711 * Open a new tab page if ":tab cmd" was used. It will edit the same buffer,
3712 * like with ":split".
3713 * Returns OK if a new tab page was created, FAIL otherwise.
3714 */
3715 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003716may_open_tabpage(void)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003717{
Bram Moolenaard326ce82007-03-11 14:48:29 +00003718 int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003719
Bram Moolenaard326ce82007-03-11 14:48:29 +00003720 if (n != 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003721 {
3722 cmdmod.tab = 0; /* reset it to avoid doing it twice */
Bram Moolenaard326ce82007-03-11 14:48:29 +00003723 postponed_split_tab = 0;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003724 return win_new_tabpage(n);
3725 }
3726 return FAIL;
3727}
3728
3729/*
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003730 * Create up to "maxcount" tabpages with empty windows.
3731 * Returns the number of resulting tab pages.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003732 */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003733 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003734make_tabpages(int maxcount)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003735{
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003736 int count = maxcount;
3737 int todo;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003738
Bram Moolenaare1438bb2006-03-01 22:01:55 +00003739 /* Limit to 'tabpagemax' tabs. */
3740 if (count > p_tpm)
3741 count = p_tpm;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003742
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003743 /*
3744 * Don't execute autocommands while creating the tab pages. Must do that
3745 * when putting the buffers in the windows.
3746 */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003747 block_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003748
3749 for (todo = count - 1; todo > 0; --todo)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003750 if (win_new_tabpage(0) == FAIL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003751 break;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003752
Bram Moolenaar78ab3312007-09-29 12:16:41 +00003753 unblock_autocmds();
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003754
3755 /* return actual number of tab pages */
3756 return (count - todo);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003757}
3758
3759/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003760 * Return TRUE when "tpc" points to a valid tab page.
3761 */
3762 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003763valid_tabpage(tabpage_T *tpc)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003764{
3765 tabpage_T *tp;
3766
Bram Moolenaar29323592016-07-24 22:04:11 +02003767 FOR_ALL_TABPAGES(tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003768 if (tp == tpc)
3769 return TRUE;
3770 return FALSE;
3771}
3772
3773/*
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01003774 * Return TRUE when "tpc" points to a valid tab page and at least one window is
3775 * valid.
3776 */
3777 int
3778valid_tabpage_win(tabpage_T *tpc)
3779{
3780 tabpage_T *tp;
3781 win_T *wp;
3782
3783 FOR_ALL_TABPAGES(tp)
3784 {
3785 if (tp == tpc)
3786 {
3787 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
3788 {
3789 if (win_valid_any_tab(wp))
3790 return TRUE;
3791 }
3792 return FALSE;
3793 }
3794 }
3795 /* shouldn't happen */
3796 return FALSE;
3797}
3798
3799/*
3800 * Close tabpage "tab", assuming it has no windows in it.
3801 * There must be another tabpage or this will crash.
3802 */
3803 void
3804close_tabpage(tabpage_T *tab)
3805{
3806 tabpage_T *ptp;
3807
3808 if (tab == first_tabpage)
3809 {
3810 first_tabpage = tab->tp_next;
3811 ptp = first_tabpage;
3812 }
3813 else
3814 {
3815 for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
3816 ptp = ptp->tp_next)
3817 ;
Bram Moolenaara37ffaa2017-03-21 21:58:00 +01003818 assert(ptp != NULL);
Bram Moolenaar8c752bd2017-03-19 17:09:56 +01003819 ptp->tp_next = tab->tp_next;
3820 }
3821
3822 goto_tabpage_tp(ptp, FALSE, FALSE);
3823 free_tabpage(tab);
3824}
3825
3826/*
Bram Moolenaarf740b292006-02-16 22:11:02 +00003827 * Find tab page "n" (first one is 1). Returns NULL when not found.
3828 */
3829 tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003830find_tabpage(int n)
Bram Moolenaarf740b292006-02-16 22:11:02 +00003831{
3832 tabpage_T *tp;
3833 int i = 1;
3834
3835 for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
3836 ++i;
3837 return tp;
3838}
3839
3840/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003841 * Get index of tab page "tp". First one has index 1.
Bram Moolenaarba6c0522006-02-25 21:45:02 +00003842 * When not found returns number of tab pages plus one.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003843 */
3844 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003845tabpage_index(tabpage_T *ftp)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003846{
3847 int i = 1;
3848 tabpage_T *tp;
3849
3850 for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
3851 ++i;
3852 return i;
3853}
3854
3855/*
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003856 * Prepare for leaving the current tab page.
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003857 * When autocommands change "curtab" we don't leave the tab page and return
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003858 * FAIL.
3859 * Careful: When OK is returned need to get a new tab page very very soon!
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003860 */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003861 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003862leave_tabpage(
3863 buf_T *new_curbuf UNUSED, /* what is going to be the new curbuf,
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003864 NULL if unknown */
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003865 int trigger_leave_autocmds UNUSED)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003866{
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003867 tabpage_T *tp = curtab;
3868
Bram Moolenaar6d41c782018-06-06 09:11:12 +02003869#ifdef FEAT_JOB_CHANNEL
3870 leaving_window(curwin);
3871#endif
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003872 reset_VIsual_and_resel(); /* stop Visual mode */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003873 if (trigger_leave_autocmds)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003874 {
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003875 if (new_curbuf != curbuf)
3876 {
3877 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
3878 if (curtab != tp)
3879 return FAIL;
3880 }
3881 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
3882 if (curtab != tp)
3883 return FAIL;
3884 apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003885 if (curtab != tp)
3886 return FAIL;
3887 }
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003888#if defined(FEAT_GUI)
3889 /* Remove the scrollbars. They may be added back later. */
3890 if (gui.in_use)
3891 gui_remove_scrollbars();
3892#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003893 tp->tp_curwin = curwin;
Bram Moolenaarf740b292006-02-16 22:11:02 +00003894 tp->tp_prevwin = prevwin;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003895 tp->tp_firstwin = firstwin;
3896 tp->tp_lastwin = lastwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003897 tp->tp_old_Rows = Rows;
3898 tp->tp_old_Columns = Columns;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003899 firstwin = NULL;
3900 lastwin = NULL;
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003901 return OK;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003902}
3903
3904/*
3905 * Start using tab page "tp".
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003906 * Only to be used after leave_tabpage() or freeing the current tab page.
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003907 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
3908 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003909 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003910 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003911enter_tabpage(
3912 tabpage_T *tp,
3913 buf_T *old_curbuf UNUSED,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01003914 int trigger_enter_autocmds,
3915 int trigger_leave_autocmds)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003916{
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003917 int old_off = tp->tp_firstwin->w_winrow;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003918 win_T *next_prevwin = tp->tp_prevwin;
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003919
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003920 curtab = tp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003921 firstwin = tp->tp_firstwin;
3922 lastwin = tp->tp_lastwin;
3923 topframe = tp->tp_topframe;
Bram Moolenaar773560b2006-05-06 21:38:18 +00003924
3925 /* We would like doing the TabEnter event first, but we don't have a
3926 * valid current window yet, which may break some commands.
3927 * This triggers autocommands, thus may make "tp" invalid. */
Bram Moolenaarc917da42016-07-19 22:31:36 +02003928 win_enter_ext(tp->tp_curwin, FALSE, TRUE, FALSE,
Bram Moolenaard6949742013-06-16 14:18:28 +02003929 trigger_enter_autocmds, trigger_leave_autocmds);
Bram Moolenaar773560b2006-05-06 21:38:18 +00003930 prevwin = next_prevwin;
3931
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003932 last_status(FALSE); /* status line may appear or disappear */
3933 (void)win_comp_pos(); /* recompute w_winrow for all windows */
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00003934 must_redraw = CLEAR; /* need to redraw everything */
3935#ifdef FEAT_DIFF
3936 diff_need_scrollbind = TRUE;
3937#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003938
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003939 /* The tabpage line may have appeared or disappeared, may need to resize
3940 * the frames for that. When the Vim window was resized need to update
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00003941 * frame sizes too. Use the stored value of p_ch, so that it can be
3942 * different for each tab page. */
3943 p_ch = curtab->tp_ch_used;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003944 if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow
3945#ifdef FEAT_GUI_TABLINE
3946 && !gui_use_tabline()
3947#endif
3948 ))
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003949 shell_new_rows();
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00003950 if (curtab->tp_old_Columns != Columns && starting == 0)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003951 shell_new_columns(); /* update window widths */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00003952
3953#if defined(FEAT_GUI)
3954 /* When 'guioptions' includes 'L' or 'R' may have to remove or add
3955 * scrollbars. Have to update them anyway. */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00003956 gui_may_update_scrollbars();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003957#endif
3958
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003959 /* Apply autocommands after updating the display, when 'rows' and
3960 * 'columns' have been set correctly. */
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003961 if (trigger_enter_autocmds)
Bram Moolenaara8596c42012-06-13 14:28:20 +02003962 {
3963 apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
3964 if (old_curbuf != curbuf)
3965 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
3966 }
Bram Moolenaar5ad15df2012-03-16 19:07:58 +01003967
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003968 redraw_all_later(CLEAR);
3969}
3970
3971/*
3972 * Go to tab page "n". For ":tab N" and "Ngt".
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003973 * When "n" is 9999 go to the last tab page.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003974 */
3975 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01003976goto_tabpage(int n)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003977{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003978 tabpage_T *tp;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00003979 tabpage_T *ttp;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003980 int i;
3981
Bram Moolenaard68071d2006-05-02 22:08:30 +00003982 if (text_locked())
3983 {
3984 /* Not allowed when editing the command line. */
Bram Moolenaar5a497892016-09-03 16:29:04 +02003985 text_locked_msg();
Bram Moolenaard68071d2006-05-02 22:08:30 +00003986 return;
3987 }
3988
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00003989 /* If there is only one it can't work. */
3990 if (first_tabpage->tp_next == NULL)
3991 {
3992 if (n > 1)
3993 beep_flush();
3994 return;
3995 }
3996
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00003997 if (n == 0)
3998 {
3999 /* No count, go to next tab page, wrap around end. */
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004000 if (curtab->tp_next == NULL)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004001 tp = first_tabpage;
4002 else
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004003 tp = curtab->tp_next;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004004 }
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004005 else if (n < 0)
4006 {
4007 /* "gT": go to previous tab page, wrap around end. "N gT" repeats
4008 * this N times. */
4009 ttp = curtab;
4010 for (i = n; i < 0; ++i)
4011 {
4012 for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
4013 tp = tp->tp_next)
4014 ;
4015 ttp = tp;
4016 }
4017 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004018 else if (n == 9999)
4019 {
4020 /* Go to last tab page. */
4021 for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
4022 ;
4023 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004024 else
4025 {
4026 /* Go to tab page "n". */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004027 tp = find_tabpage(n);
Bram Moolenaarf740b292006-02-16 22:11:02 +00004028 if (tp == NULL)
4029 {
4030 beep_flush();
4031 return;
4032 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004033 }
4034
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004035 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004036
4037#ifdef FEAT_GUI_TABLINE
4038 if (gui_use_tabline())
Bram Moolenaara226a6d2006-02-26 23:59:20 +00004039 gui_mch_set_curtab(tabpage_index(curtab));
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004040#endif
4041}
4042
4043/*
4044 * Go to tabpage "tp".
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004045 * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
4046 * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004047 * Note: doesn't update the GUI tab.
4048 */
4049 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004050goto_tabpage_tp(
4051 tabpage_T *tp,
4052 int trigger_enter_autocmds,
4053 int trigger_leave_autocmds)
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004054{
Bram Moolenaarc6af8122010-05-21 12:04:55 +02004055 /* Don't repeat a message in another tab page. */
4056 set_keep_msg(NULL, 0);
4057
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004058 if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
4059 trigger_leave_autocmds) == OK)
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004060 {
4061 if (valid_tabpage(tp))
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004062 enter_tabpage(tp, curbuf, trigger_enter_autocmds,
4063 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004064 else
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004065 enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
4066 trigger_leave_autocmds);
Bram Moolenaar7e8fd632006-02-18 22:14:51 +00004067 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004068}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069
4070/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004071 * Enter window "wp" in tab page "tp".
4072 * Also updates the GUI tab.
4073 */
4074 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004075goto_tabpage_win(tabpage_T *tp, win_T *wp)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004076{
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004077 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004078 if (curtab == tp && win_valid(wp))
4079 {
4080 win_enter(wp, TRUE);
4081# ifdef FEAT_GUI_TABLINE
4082 if (gui_use_tabline())
4083 gui_mch_set_curtab(tabpage_index(curtab));
4084# endif
4085 }
4086}
4087
4088/*
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004089 * Move the current tab page to after tab page "nr".
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004090 */
4091 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004092tabpage_move(int nr)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004093{
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004094 int n = 1;
4095 tabpage_T *tp, *tp_dst;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004096
4097 if (first_tabpage->tp_next == NULL)
4098 return;
4099
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004100 for (tp = first_tabpage; tp->tp_next != NULL && n < nr; tp = tp->tp_next)
4101 ++n;
4102
4103 if (tp == curtab || (nr > 0 && tp->tp_next != NULL
4104 && tp->tp_next == curtab))
4105 return;
4106
4107 tp_dst = tp;
4108
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004109 /* Remove the current tab page from the list of tab pages. */
4110 if (curtab == first_tabpage)
4111 first_tabpage = curtab->tp_next;
4112 else
4113 {
Bram Moolenaar29323592016-07-24 22:04:11 +02004114 FOR_ALL_TABPAGES(tp)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004115 if (tp->tp_next == curtab)
4116 break;
4117 if (tp == NULL) /* "cannot happen" */
4118 return;
4119 tp->tp_next = curtab->tp_next;
4120 }
4121
4122 /* Re-insert it at the specified position. */
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004123 if (nr <= 0)
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004124 {
4125 curtab->tp_next = first_tabpage;
4126 first_tabpage = curtab;
4127 }
4128 else
4129 {
Bram Moolenaar40ce3a42015-04-21 18:08:39 +02004130 curtab->tp_next = tp_dst->tp_next;
4131 tp_dst->tp_next = curtab;
Bram Moolenaar80a94a52006-02-23 21:26:58 +00004132 }
4133
4134 /* Need to redraw the tabline. Tab page contents doesn't change. */
4135 redraw_tabline = TRUE;
4136}
4137
4138
4139/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 * Go to another window.
4141 * When jumping to another buffer, stop Visual mode. Do this before
4142 * changing windows so we can yank the selection into the '*' register.
4143 * When jumping to another window on the same buffer, adjust its cursor
4144 * position to keep the same Visual area.
4145 */
4146 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004147win_goto(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148{
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004149#ifdef FEAT_CONCEAL
4150 win_T *owp = curwin;
4151#endif
4152
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004153 if (text_locked())
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
4155 beep_flush();
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00004156 text_locked_msg();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 return;
4158 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004159 if (curbuf_locked())
4160 return;
Bram Moolenaar05a7bb32006-01-19 22:09:32 +00004161
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 if (wp->w_buffer != curbuf)
4163 reset_VIsual_and_resel();
4164 else if (VIsual_active)
4165 wp->w_cursor = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166
4167#ifdef FEAT_GUI
4168 need_mouse_correct = TRUE;
4169#endif
4170 win_enter(wp, TRUE);
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004171
4172#ifdef FEAT_CONCEAL
4173 /* Conceal cursor line in previous window, unconceal in current window. */
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004174 if (win_valid(owp) && owp->w_p_cole > 0 && !msg_scrolled)
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004175 update_single_line(owp, owp->w_cursor.lnum);
Bram Moolenaar530e7df2013-02-06 13:38:02 +01004176 if (curwin->w_p_cole > 0 && !msg_scrolled)
4177 need_cursor_line_redraw = TRUE;
Bram Moolenaar23c347c2010-07-14 20:57:00 +02004178#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179}
4180
4181#if defined(FEAT_PERL) || defined(PROTO)
4182/*
4183 * Find window number "winnr" (counting top to bottom).
4184 */
4185 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004186win_find_nr(int winnr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187{
4188 win_T *wp;
4189
Bram Moolenaar29323592016-07-24 22:04:11 +02004190 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 if (--winnr == 0)
4192 break;
4193 return wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194}
4195#endif
4196
Bram Moolenaar4033c552017-09-16 20:54:51 +02004197#if ((defined(FEAT_PYTHON) || defined(FEAT_PYTHON3))) || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004198/*
4199 * Find the tabpage for window "win".
4200 */
4201 tabpage_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004202win_find_tabpage(win_T *win)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004203{
4204 win_T *wp;
4205 tabpage_T *tp;
4206
Bram Moolenaar29323592016-07-24 22:04:11 +02004207 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar105bc352013-05-17 16:03:57 +02004208 if (wp == win)
4209 return tp;
4210 return NULL;
4211}
4212#endif
4213
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214/*
4215 * Move to window above or below "count" times.
4216 */
4217 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004218win_goto_ver(
4219 int up, /* TRUE to go to win above */
4220 long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221{
4222 frame_T *fr;
4223 frame_T *nfr;
4224 frame_T *foundfr;
4225
4226 foundfr = curwin->w_frame;
4227 while (count--)
4228 {
4229 /*
4230 * First go upwards in the tree of frames until we find a upwards or
4231 * downwards neighbor.
4232 */
4233 fr = foundfr;
4234 for (;;)
4235 {
4236 if (fr == topframe)
4237 goto end;
4238 if (up)
4239 nfr = fr->fr_prev;
4240 else
4241 nfr = fr->fr_next;
4242 if (fr->fr_parent->fr_layout == FR_COL && nfr != NULL)
4243 break;
4244 fr = fr->fr_parent;
4245 }
4246
4247 /*
4248 * Now go downwards to find the bottom or top frame in it.
4249 */
4250 for (;;)
4251 {
4252 if (nfr->fr_layout == FR_LEAF)
4253 {
4254 foundfr = nfr;
4255 break;
4256 }
4257 fr = nfr->fr_child;
4258 if (nfr->fr_layout == FR_ROW)
4259 {
4260 /* Find the frame at the cursor row. */
4261 while (fr->fr_next != NULL
4262 && frame2win(fr)->w_wincol + fr->fr_width
4263 <= curwin->w_wincol + curwin->w_wcol)
4264 fr = fr->fr_next;
4265 }
4266 if (nfr->fr_layout == FR_COL && up)
4267 while (fr->fr_next != NULL)
4268 fr = fr->fr_next;
4269 nfr = fr;
4270 }
4271 }
4272end:
4273 if (foundfr != NULL)
4274 win_goto(foundfr->fr_win);
4275}
4276
4277/*
4278 * Move to left or right window.
4279 */
4280 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004281win_goto_hor(
4282 int left, /* TRUE to go to left win */
4283 long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004284{
4285 frame_T *fr;
4286 frame_T *nfr;
4287 frame_T *foundfr;
4288
4289 foundfr = curwin->w_frame;
4290 while (count--)
4291 {
4292 /*
4293 * First go upwards in the tree of frames until we find a left or
4294 * right neighbor.
4295 */
4296 fr = foundfr;
4297 for (;;)
4298 {
4299 if (fr == topframe)
4300 goto end;
4301 if (left)
4302 nfr = fr->fr_prev;
4303 else
4304 nfr = fr->fr_next;
4305 if (fr->fr_parent->fr_layout == FR_ROW && nfr != NULL)
4306 break;
4307 fr = fr->fr_parent;
4308 }
4309
4310 /*
4311 * Now go downwards to find the leftmost or rightmost frame in it.
4312 */
4313 for (;;)
4314 {
4315 if (nfr->fr_layout == FR_LEAF)
4316 {
4317 foundfr = nfr;
4318 break;
4319 }
4320 fr = nfr->fr_child;
4321 if (nfr->fr_layout == FR_COL)
4322 {
4323 /* Find the frame at the cursor row. */
4324 while (fr->fr_next != NULL
4325 && frame2win(fr)->w_winrow + fr->fr_height
4326 <= curwin->w_winrow + curwin->w_wrow)
4327 fr = fr->fr_next;
4328 }
4329 if (nfr->fr_layout == FR_ROW && left)
4330 while (fr->fr_next != NULL)
4331 fr = fr->fr_next;
4332 nfr = fr;
4333 }
4334 }
4335end:
4336 if (foundfr != NULL)
4337 win_goto(foundfr->fr_win);
4338}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004339
4340/*
4341 * Make window "wp" the current window.
4342 */
4343 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004344win_enter(win_T *wp, int undo_sync)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345{
Bram Moolenaarc917da42016-07-19 22:31:36 +02004346 win_enter_ext(wp, undo_sync, FALSE, FALSE, TRUE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347}
4348
4349/*
4350 * Make window wp the current window.
4351 * Can be called with "curwin_invalid" TRUE, which means that curwin has just
4352 * been closed and isn't valid.
4353 */
4354 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004355win_enter_ext(
4356 win_T *wp,
4357 int undo_sync,
4358 int curwin_invalid,
Bram Moolenaar6f470022018-04-10 18:47:20 +02004359 int trigger_new_autocmds,
4360 int trigger_enter_autocmds,
4361 int trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362{
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 int other_buffer = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364
4365 if (wp == curwin && !curwin_invalid) /* nothing to do */
4366 return;
4367
Bram Moolenaar6d41c782018-06-06 09:11:12 +02004368#ifdef FEAT_JOB_CHANNEL
4369 if (!curwin_invalid)
4370 leaving_window(curwin);
4371#endif
4372
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004373 if (!curwin_invalid && trigger_leave_autocmds)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 {
4375 /*
4376 * Be careful: If autocommands delete the window, return now.
4377 */
4378 if (wp->w_buffer != curbuf)
4379 {
4380 apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
4381 other_buffer = TRUE;
4382 if (!win_valid(wp))
4383 return;
4384 }
4385 apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
4386 if (!win_valid(wp))
4387 return;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004388#ifdef FEAT_EVAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 /* autocmds may abort script processing */
4390 if (aborting())
4391 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004393 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394
4395 /* sync undo before leaving the current buffer */
4396 if (undo_sync && curbuf != wp->w_buffer)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004397 u_sync(FALSE);
Bram Moolenaarec1561c2014-06-17 13:52:40 +02004398
4399 /* Might need to scroll the old window before switching, e.g., when the
4400 * cursor was moved. */
4401 update_topline();
4402
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403 /* may have to copy the buffer options when 'cpo' contains 'S' */
4404 if (wp->w_buffer != curbuf)
4405 buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
4406 if (!curwin_invalid)
4407 {
4408 prevwin = curwin; /* remember for CTRL-W p */
4409 curwin->w_redr_status = TRUE;
4410 }
4411 curwin = wp;
4412 curbuf = wp->w_buffer;
4413 check_cursor();
4414#ifdef FEAT_VIRTUALEDIT
4415 if (!virtual_active())
4416 curwin->w_cursor.coladd = 0;
4417#endif
4418 changed_line_abv_curs(); /* assume cursor position needs updating */
4419
4420 if (curwin->w_localdir != NULL)
4421 {
4422 /* Window has a local directory: Save current directory as global
4423 * directory (unless that was done already) and change to the local
4424 * directory. */
4425 if (globaldir == NULL)
4426 {
4427 char_u cwd[MAXPATHL];
4428
4429 if (mch_dirname(cwd, MAXPATHL) == OK)
4430 globaldir = vim_strsave(cwd);
4431 }
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004432 if (mch_chdir((char *)curwin->w_localdir) == 0)
4433 shorten_fnames(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 }
4435 else if (globaldir != NULL)
4436 {
4437 /* Window doesn't have a local directory and we are not in the global
4438 * directory: Change to the global directory. */
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004439 ignored = mch_chdir((char *)globaldir);
Bram Moolenaard23a8232018-02-10 18:45:26 +01004440 VIM_CLEAR(globaldir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441 shorten_fnames(TRUE);
4442 }
4443
Bram Moolenaar6d41c782018-06-06 09:11:12 +02004444#ifdef FEAT_JOB_CHANNEL
4445 entering_window(curwin);
4446#endif
Bram Moolenaarc917da42016-07-19 22:31:36 +02004447 if (trigger_new_autocmds)
4448 apply_autocmds(EVENT_WINNEW, NULL, NULL, FALSE, curbuf);
Bram Moolenaar49e649f2013-05-06 04:50:35 +02004449 if (trigger_enter_autocmds)
4450 {
4451 apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
4452 if (other_buffer)
4453 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
4454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004455
4456#ifdef FEAT_TITLE
4457 maketitle();
4458#endif
4459 curwin->w_redr_status = TRUE;
Bram Moolenaar49d7bf12006-02-17 21:45:41 +00004460 redraw_tabline = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461 if (restart_edit)
4462 redraw_later(VALID); /* causes status line redraw */
4463
4464 /* set window height to desired minimal value */
4465 if (curwin->w_height < p_wh && !curwin->w_p_wfh)
4466 win_setheight((int)p_wh);
4467 else if (curwin->w_height == 0)
4468 win_setheight(1);
4469
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 /* set window width to desired minimal value */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004471 if (curwin->w_width < p_wiw && !curwin->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 win_setwidth((int)p_wiw);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473
4474#ifdef FEAT_MOUSE
4475 setmouse(); /* in case jumped to/from help buffer */
4476#endif
4477
Bram Moolenaar498efdb2006-09-05 14:31:54 +00004478 /* Change directories when the 'acd' option is set. */
Bram Moolenaar6f470022018-04-10 18:47:20 +02004479 DO_AUTOCHDIR;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480}
4481
Bram Moolenaar071d4272004-06-13 20:20:40 +00004482
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483/*
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004484 * Jump to the first open window that contains buffer "buf", if one exists.
4485 * Returns a pointer to the window found, otherwise NULL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 */
4487 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004488buf_jump_open_win(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489{
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004490 win_T *wp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004492 if (curwin->w_buffer == buf)
4493 wp = curwin;
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004494 else
Bram Moolenaar29323592016-07-24 22:04:11 +02004495 FOR_ALL_WINDOWS(wp)
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004496 if (wp->w_buffer == buf)
4497 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004498 if (wp != NULL)
4499 win_enter(wp, FALSE);
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004500 return wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501}
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004502
4503/*
4504 * Jump to the first open window in any tab page that contains buffer "buf",
4505 * if one exists.
4506 * Returns a pointer to the window found, otherwise NULL.
4507 */
4508 win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004509buf_jump_open_tab(buf_T *buf)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004510{
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004511 win_T *wp = buf_jump_open_win(buf);
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004512 tabpage_T *tp;
4513
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004514 if (wp != NULL)
4515 return wp;
4516
Bram Moolenaar29323592016-07-24 22:04:11 +02004517 FOR_ALL_TABPAGES(tp)
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004518 if (tp != curtab)
4519 {
4520 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
4521 if (wp->w_buffer == buf)
4522 break;
4523 if (wp != NULL)
4524 {
4525 goto_tabpage_win(tp, wp);
4526 if (curwin != wp)
4527 wp = NULL; /* something went wrong */
4528 break;
4529 }
4530 }
Bram Moolenaar482a2b52014-10-21 20:57:15 +02004531 return wp;
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004532}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533
Bram Moolenaar888ccac2016-06-04 18:49:36 +02004534static int last_win_id = LOWEST_WIN_ID - 1;
Bram Moolenaar86edef62016-03-13 18:07:30 +01004535
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536/*
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004537 * Allocate a window structure and link it in the window list when "hidden" is
4538 * FALSE.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004541win_alloc(win_T *after UNUSED, int hidden UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542{
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004543 win_T *new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544
4545 /*
4546 * allocate window structure and linesizes arrays
4547 */
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004548 new_wp = (win_T *)alloc_clear((unsigned)sizeof(win_T));
Bram Moolenaar429fa852013-04-15 12:27:36 +02004549 if (new_wp == NULL)
4550 return NULL;
4551
4552 if (win_alloc_lines(new_wp) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004554 vim_free(new_wp);
Bram Moolenaar429fa852013-04-15 12:27:36 +02004555 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 }
4557
Bram Moolenaar86edef62016-03-13 18:07:30 +01004558 new_wp->w_id = ++last_win_id;
4559
Bram Moolenaar429fa852013-04-15 12:27:36 +02004560#ifdef FEAT_EVAL
4561 /* init w: variables */
4562 new_wp->w_vars = dict_alloc();
4563 if (new_wp->w_vars == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564 {
Bram Moolenaar429fa852013-04-15 12:27:36 +02004565 win_free_lsize(new_wp);
4566 vim_free(new_wp);
4567 return NULL;
4568 }
4569 init_var_dict(new_wp->w_vars, &new_wp->w_winvar, VAR_SCOPE);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004570#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004571
Bram Moolenaar429fa852013-04-15 12:27:36 +02004572 /* Don't execute autocommands while the window is not properly
4573 * initialized yet. gui_create_scrollbar() may trigger a FocusGained
4574 * event. */
4575 block_autocmds();
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004576
Bram Moolenaar429fa852013-04-15 12:27:36 +02004577 /*
4578 * link the window in the window list
4579 */
Bram Moolenaar429fa852013-04-15 12:27:36 +02004580 if (!hidden)
4581 win_append(after, new_wp);
Bram Moolenaar429fa852013-04-15 12:27:36 +02004582 new_wp->w_wincol = 0;
4583 new_wp->w_width = Columns;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584
Bram Moolenaar429fa852013-04-15 12:27:36 +02004585 /* position the display and the cursor at the top of the file. */
4586 new_wp->w_topline = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587#ifdef FEAT_DIFF
Bram Moolenaar429fa852013-04-15 12:27:36 +02004588 new_wp->w_topfill = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004590 new_wp->w_botline = 2;
4591 new_wp->w_cursor.lnum = 1;
Bram Moolenaar429fa852013-04-15 12:27:36 +02004592 new_wp->w_scbind_pos = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004593
Bram Moolenaar429fa852013-04-15 12:27:36 +02004594 /* We won't calculate w_fraction until resizing the window */
4595 new_wp->w_fraction = 0;
4596 new_wp->w_prev_fraction_row = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004597
4598#ifdef FEAT_GUI
Bram Moolenaar429fa852013-04-15 12:27:36 +02004599 if (gui.in_use)
4600 {
4601 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_LEFT],
4602 SBAR_LEFT, new_wp);
4603 gui_create_scrollbar(&new_wp->w_scrollbars[SBAR_RIGHT],
4604 SBAR_RIGHT, new_wp);
4605 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606#endif
4607#ifdef FEAT_FOLDING
Bram Moolenaar429fa852013-04-15 12:27:36 +02004608 foldInitWin(new_wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609#endif
Bram Moolenaar429fa852013-04-15 12:27:36 +02004610 unblock_autocmds();
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004611#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar429fa852013-04-15 12:27:36 +02004612 new_wp->w_match_head = NULL;
4613 new_wp->w_next_match_id = 4;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004614#endif
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004615 return new_wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616}
4617
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618/*
Bram Moolenaarff18df02013-07-24 17:51:57 +02004619 * Remove window 'wp' from the window list and free the structure.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 */
4621 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004622win_free(
4623 win_T *wp,
4624 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625{
4626 int i;
Bram Moolenaarff18df02013-07-24 17:51:57 +02004627 buf_T *buf;
4628 wininfo_T *wip;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004630#ifdef FEAT_FOLDING
4631 clearFolding(wp);
4632#endif
4633
4634 /* reduce the reference count to the argument list. */
4635 alist_unlink(wp->w_alist);
4636
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004637 /* Don't execute autocommands while the window is halfway being deleted.
4638 * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004639 block_autocmds();
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004640
Bram Moolenaar0ba04292010-07-14 23:23:17 +02004641#ifdef FEAT_LUA
4642 lua_window_free(wp);
4643#endif
4644
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004645#ifdef FEAT_MZSCHEME
4646 mzscheme_window_free(wp);
4647#endif
4648
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649#ifdef FEAT_PERL
4650 perl_win_free(wp);
4651#endif
4652
4653#ifdef FEAT_PYTHON
4654 python_window_free(wp);
4655#endif
4656
Bram Moolenaarbd5e15f2010-07-17 21:19:38 +02004657#ifdef FEAT_PYTHON3
4658 python3_window_free(wp);
4659#endif
4660
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661#ifdef FEAT_TCL
4662 tcl_window_free(wp);
4663#endif
4664
4665#ifdef FEAT_RUBY
4666 ruby_window_free(wp);
4667#endif
4668
4669 clear_winopt(&wp->w_onebuf_opt);
4670 clear_winopt(&wp->w_allbuf_opt);
4671
4672#ifdef FEAT_EVAL
Bram Moolenaar429fa852013-04-15 12:27:36 +02004673 vars_clear(&wp->w_vars->dv_hashtab); /* free all w: variables */
4674 hash_init(&wp->w_vars->dv_hashtab);
4675 unref_var_dict(wp->w_vars);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676#endif
4677
Bram Moolenaar3dda7db2016-04-03 21:22:58 +02004678 {
4679 tabpage_T *ttp;
4680
4681 if (prevwin == wp)
4682 prevwin = NULL;
Bram Moolenaar29323592016-07-24 22:04:11 +02004683 FOR_ALL_TABPAGES(ttp)
Bram Moolenaar3dda7db2016-04-03 21:22:58 +02004684 if (ttp->tp_prevwin == wp)
4685 ttp->tp_prevwin = NULL;
4686 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687 win_free_lsize(wp);
4688
4689 for (i = 0; i < wp->w_tagstacklen; ++i)
4690 vim_free(wp->w_tagstack[i].tagname);
4691
4692 vim_free(wp->w_localdir);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004693
Bram Moolenaarff18df02013-07-24 17:51:57 +02004694 /* Remove the window from the b_wininfo lists, it may happen that the
4695 * freed memory is re-used for another window. */
Bram Moolenaar29323592016-07-24 22:04:11 +02004696 FOR_ALL_BUFFERS(buf)
Bram Moolenaarff18df02013-07-24 17:51:57 +02004697 for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next)
4698 if (wip->wi_win == wp)
4699 wip->wi_win = NULL;
4700
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004702 clear_matches(wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00004704
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705#ifdef FEAT_JUMPLIST
4706 free_jumplist(wp);
4707#endif
4708
Bram Moolenaar28c258f2006-01-25 22:02:51 +00004709#ifdef FEAT_QUICKFIX
4710 qf_free_all(wp);
4711#endif
4712
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713#ifdef FEAT_GUI
4714 if (gui.in_use)
4715 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
4717 gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
4718 }
4719#endif /* FEAT_GUI */
4720
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004721#ifdef FEAT_MENU
4722 remove_winbar(wp);
4723#endif
4724
Bram Moolenaar860cae12010-06-05 23:22:07 +02004725#ifdef FEAT_SYN_HL
Bram Moolenaar1a384422010-07-14 19:53:30 +02004726 vim_free(wp->w_p_cc_cols);
Bram Moolenaar860cae12010-06-05 23:22:07 +02004727#endif
4728
Bram Moolenaarf061e0b2009-06-24 15:32:01 +00004729 if (wp != aucmd_win)
Bram Moolenaarfd29f462010-06-06 16:11:09 +02004730 win_remove(wp, tp);
Bram Moolenaar3be85852014-06-12 14:01:31 +02004731 if (autocmd_busy)
4732 {
4733 wp->w_next = au_pending_free_win;
4734 au_pending_free_win = wp;
4735 }
4736 else
4737 vim_free(wp);
Bram Moolenaaree79cbc2007-05-02 19:50:14 +00004738
Bram Moolenaar78ab3312007-09-29 12:16:41 +00004739 unblock_autocmds();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740}
4741
4742/*
4743 * Append window "wp" in the window list after window "after".
4744 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004745 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004746win_append(win_T *after, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747{
4748 win_T *before;
4749
4750 if (after == NULL) /* after NULL is in front of the first */
4751 before = firstwin;
4752 else
4753 before = after->w_next;
4754
4755 wp->w_next = before;
4756 wp->w_prev = after;
4757 if (after == NULL)
4758 firstwin = wp;
4759 else
4760 after->w_next = wp;
4761 if (before == NULL)
4762 lastwin = wp;
4763 else
4764 before->w_prev = wp;
4765}
4766
4767/*
4768 * Remove a window from the window list.
4769 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00004770 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004771win_remove(
4772 win_T *wp,
4773 tabpage_T *tp) /* tab page "win" is in, NULL for current */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774{
4775 if (wp->w_prev != NULL)
4776 wp->w_prev->w_next = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004777 else if (tp == NULL)
Bram Moolenaar816968d2017-09-29 21:29:18 +02004778 firstwin = curtab->tp_firstwin = wp->w_next;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004779 else
4780 tp->tp_firstwin = wp->w_next;
Bram Moolenaar816968d2017-09-29 21:29:18 +02004781
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782 if (wp->w_next != NULL)
4783 wp->w_next->w_prev = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004784 else if (tp == NULL)
Bram Moolenaar816968d2017-09-29 21:29:18 +02004785 lastwin = curtab->tp_lastwin = wp->w_prev;
Bram Moolenaarf740b292006-02-16 22:11:02 +00004786 else
4787 tp->tp_lastwin = wp->w_prev;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788}
4789
4790/*
4791 * Append frame "frp" in a frame list after frame "after".
4792 */
4793 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004794frame_append(frame_T *after, frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795{
4796 frp->fr_next = after->fr_next;
4797 after->fr_next = frp;
4798 if (frp->fr_next != NULL)
4799 frp->fr_next->fr_prev = frp;
4800 frp->fr_prev = after;
4801}
4802
4803/*
4804 * Insert frame "frp" in a frame list before frame "before".
4805 */
4806 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004807frame_insert(frame_T *before, frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808{
4809 frp->fr_next = before;
4810 frp->fr_prev = before->fr_prev;
4811 before->fr_prev = frp;
4812 if (frp->fr_prev != NULL)
4813 frp->fr_prev->fr_next = frp;
4814 else
4815 frp->fr_parent->fr_child = frp;
4816}
4817
4818/*
4819 * Remove a frame from a frame list.
4820 */
4821 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004822frame_remove(frame_T *frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823{
4824 if (frp->fr_prev != NULL)
4825 frp->fr_prev->fr_next = frp->fr_next;
4826 else
Bram Moolenaar6f361c92018-01-31 19:06:50 +01004827 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 frp->fr_parent->fr_child = frp->fr_next;
Bram Moolenaar6f361c92018-01-31 19:06:50 +01004829 /* special case: topframe->fr_child == frp */
4830 if (topframe->fr_child == frp)
4831 topframe->fr_child = frp->fr_next;
4832 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 if (frp->fr_next != NULL)
4834 frp->fr_next->fr_prev = frp->fr_prev;
4835}
4836
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837/*
4838 * Allocate w_lines[] for window "wp".
4839 * Return FAIL for failure, OK for success.
4840 */
4841 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004842win_alloc_lines(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843{
4844 wp->w_lines_valid = 0;
Bram Moolenaar9334c342006-11-21 19:57:30 +00004845 wp->w_lines = (wline_T *)alloc_clear((unsigned)(Rows * sizeof(wline_T)));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 if (wp->w_lines == NULL)
4847 return FAIL;
4848 return OK;
4849}
4850
4851/*
4852 * free lsize arrays for a window
4853 */
4854 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004855win_free_lsize(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856{
Bram Moolenaar06e4a6d2014-06-12 11:49:46 +02004857 /* TODO: why would wp be NULL here? */
4858 if (wp != NULL)
Bram Moolenaard23a8232018-02-10 18:45:26 +01004859 VIM_CLEAR(wp->w_lines);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860}
4861
4862/*
4863 * Called from win_new_shellsize() after Rows changed.
Bram Moolenaarf740b292006-02-16 22:11:02 +00004864 * This only does the current tab page, others must be done when made active.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865 */
4866 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004867shell_new_rows(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868{
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00004869 int h = (int)ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870
4871 if (firstwin == NULL) /* not initialized yet */
4872 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 if (h < frame_minheight(topframe, NULL))
4874 h = frame_minheight(topframe, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004875
4876 /* First try setting the heights of windows with 'winfixheight'. If
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 * that doesn't result in the right height, forget about that option. */
4878 frame_new_height(topframe, h, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004879 if (!frame_check_height(topframe, h))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004880 frame_new_height(topframe, h, FALSE, FALSE);
4881
4882 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004883 compute_cmdrow();
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00004884 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004885
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886#if 0
4887 /* Disabled: don't want making the screen smaller make a window larger. */
4888 if (p_ea)
4889 win_equal(curwin, FALSE, 'v');
4890#endif
4891}
4892
Bram Moolenaar071d4272004-06-13 20:20:40 +00004893/*
4894 * Called from win_new_shellsize() after Columns changed.
4895 */
4896 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004897shell_new_columns(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898{
4899 if (firstwin == NULL) /* not initialized yet */
4900 return;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004901
4902 /* First try setting the widths of windows with 'winfixwidth'. If that
4903 * doesn't result in the right width, forget about that option. */
4904 frame_new_width(topframe, (int)Columns, FALSE, TRUE);
Bram Moolenaarb893ac22013-06-26 14:04:47 +02004905 if (!frame_check_width(topframe, Columns))
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00004906 frame_new_width(topframe, (int)Columns, FALSE, FALSE);
4907
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908 (void)win_comp_pos(); /* recompute w_winrow and w_wincol */
4909#if 0
4910 /* Disabled: don't want making the screen smaller make a window larger. */
4911 if (p_ea)
4912 win_equal(curwin, FALSE, 'h');
4913#endif
4914}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915
4916#if defined(FEAT_CMDWIN) || defined(PROTO)
4917/*
4918 * Save the size of all windows in "gap".
4919 */
4920 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004921win_size_save(garray_T *gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922
4923{
4924 win_T *wp;
4925
4926 ga_init2(gap, (int)sizeof(int), 1);
4927 if (ga_grow(gap, win_count() * 2) == OK)
Bram Moolenaar29323592016-07-24 22:04:11 +02004928 FOR_ALL_WINDOWS(wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004929 {
4930 ((int *)gap->ga_data)[gap->ga_len++] =
4931 wp->w_width + wp->w_vsep_width;
4932 ((int *)gap->ga_data)[gap->ga_len++] = wp->w_height;
4933 }
4934}
4935
4936/*
4937 * Restore window sizes, but only if the number of windows is still the same.
4938 * Does not free the growarray.
4939 */
4940 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004941win_size_restore(garray_T *gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942{
4943 win_T *wp;
Bram Moolenaarb643e772014-07-16 15:18:26 +02004944 int i, j;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945
4946 if (win_count() * 2 == gap->ga_len)
4947 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004948 /* The order matters, because frames contain other frames, but it's
4949 * difficult to get right. The easy way out is to do it twice. */
4950 for (j = 0; j < 2; ++j)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 {
Bram Moolenaarb643e772014-07-16 15:18:26 +02004952 i = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +02004953 FOR_ALL_WINDOWS(wp)
Bram Moolenaarb643e772014-07-16 15:18:26 +02004954 {
4955 frame_setwidth(wp->w_frame, ((int *)gap->ga_data)[i++]);
4956 win_setheight_win(((int *)gap->ga_data)[i++], wp);
4957 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004958 }
4959 /* recompute the window positions */
4960 (void)win_comp_pos();
4961 }
4962}
4963#endif /* FEAT_CMDWIN */
4964
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965/*
4966 * Update the position for all windows, using the width and height of the
4967 * frames.
4968 * Returns the row just after the last window.
4969 */
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00004970 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004971win_comp_pos(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004972{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00004973 int row = tabline_height();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974 int col = 0;
4975
4976 frame_comp_pos(topframe, &row, &col);
4977 return row;
4978}
4979
4980/*
4981 * Update the position of the windows in frame "topfrp", using the width and
4982 * height of the frames.
4983 * "*row" and "*col" are the top-left position of the frame. They are updated
4984 * to the bottom-right position plus one.
4985 */
4986 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01004987frame_comp_pos(frame_T *topfrp, int *row, int *col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988{
4989 win_T *wp;
4990 frame_T *frp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004991 int startcol;
4992 int startrow;
Bram Moolenaar415a6932017-12-05 20:31:07 +01004993 int h;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994
4995 wp = topfrp->fr_win;
4996 if (wp != NULL)
4997 {
Bram Moolenaar44a2f922016-03-19 22:11:51 +01004998 if (wp->w_winrow != *row || wp->w_wincol != *col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 {
5000 /* position changed, redraw */
5001 wp->w_winrow = *row;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005002 wp->w_wincol = *col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 redraw_win_later(wp, NOT_VALID);
5004 wp->w_redr_status = TRUE;
5005 }
Bram Moolenaar415a6932017-12-05 20:31:07 +01005006 /* WinBar will not show if the window height is zero */
5007 h = VISIBLE_HEIGHT(wp) + wp->w_status_height;
5008 *row += h > topfrp->fr_height ? topfrp->fr_height : h;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009 *col += wp->w_width + wp->w_vsep_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 }
5011 else
5012 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 startrow = *row;
5014 startcol = *col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005015 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
5016 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005017 if (topfrp->fr_layout == FR_ROW)
5018 *row = startrow; /* all frames are at the same row */
5019 else
5020 *col = startcol; /* all frames are at the same col */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005021 frame_comp_pos(frp, row, col);
5022 }
5023 }
5024}
5025
Bram Moolenaar071d4272004-06-13 20:20:40 +00005026/*
5027 * Set current window height and take care of repositioning other windows to
5028 * fit around it.
5029 */
5030 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005031win_setheight(int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032{
5033 win_setheight_win(height, curwin);
5034}
5035
5036/*
5037 * Set the window height of window "win" and take care of repositioning other
5038 * windows to fit around it.
5039 */
5040 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005041win_setheight_win(int height, win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005042{
5043 int row;
5044
5045 if (win == curwin)
5046 {
5047 /* Always keep current window at least one line high, even when
5048 * 'winminheight' is zero. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 if (height < p_wmh)
5050 height = p_wmh;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 if (height == 0)
5052 height = 1;
Bram Moolenaar415a6932017-12-05 20:31:07 +01005053 height += WINBAR_HEIGHT(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 }
5055
Bram Moolenaar071d4272004-06-13 20:20:40 +00005056 frame_setheight(win->w_frame, height + win->w_status_height);
5057
5058 /* recompute the window positions */
5059 row = win_comp_pos();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060
5061 /*
5062 * If there is extra space created between the last window and the command
5063 * line, clear it.
5064 */
5065 if (full_screen && msg_scrolled == 0 && row < cmdline_row)
5066 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5067 cmdline_row = row;
5068 msg_row = row;
5069 msg_col = 0;
5070
5071 redraw_all_later(NOT_VALID);
5072}
5073
Bram Moolenaar071d4272004-06-13 20:20:40 +00005074/*
5075 * Set the height of a frame to "height" and take care that all frames and
5076 * windows inside it are resized. Also resize frames on the left and right if
5077 * the are in the same FR_ROW frame.
5078 *
5079 * Strategy:
5080 * If the frame is part of a FR_COL frame, try fitting the frame in that
5081 * frame. If that doesn't work (the FR_COL frame is too small), recursively
5082 * go to containing frames to resize them and make room.
5083 * If the frame is part of a FR_ROW frame, all frames must be resized as well.
5084 * Check for the minimal height of the FR_ROW frame.
5085 * At the top level we can also use change the command line height.
5086 */
5087 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005088frame_setheight(frame_T *curfrp, int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089{
5090 int room; /* total number of lines available */
5091 int take; /* number of lines taken from other windows */
5092 int room_cmdline; /* lines available from cmdline */
5093 int run;
5094 frame_T *frp;
5095 int h;
5096 int room_reserved;
5097
5098 /* If the height already is the desired value, nothing to do. */
5099 if (curfrp->fr_height == height)
5100 return;
5101
5102 if (curfrp->fr_parent == NULL)
5103 {
5104 /* topframe: can only change the command line */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005105 if (height > ROWS_AVAIL)
5106 height = ROWS_AVAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107 if (height > 0)
5108 frame_new_height(curfrp, height, FALSE, FALSE);
5109 }
5110 else if (curfrp->fr_parent->fr_layout == FR_ROW)
5111 {
5112 /* Row of frames: Also need to resize frames left and right of this
5113 * one. First check for the minimal height of these. */
5114 h = frame_minheight(curfrp->fr_parent, NULL);
5115 if (height < h)
5116 height = h;
5117 frame_setheight(curfrp->fr_parent, height);
5118 }
5119 else
5120 {
5121 /*
5122 * Column of frames: try to change only frames in this column.
5123 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124 /*
5125 * Do this twice:
5126 * 1: compute room available, if it's not enough try resizing the
5127 * containing frame.
5128 * 2: compute the room available and adjust the height to it.
5129 * Try not to reduce the height of a window with 'winfixheight' set.
5130 */
5131 for (run = 1; run <= 2; ++run)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 {
5133 room = 0;
5134 room_reserved = 0;
5135 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
5136 frp = frp->fr_next)
5137 {
5138 if (frp != curfrp
5139 && frp->fr_win != NULL
5140 && frp->fr_win->w_p_wfh)
5141 room_reserved += frp->fr_height;
5142 room += frp->fr_height;
5143 if (frp != curfrp)
5144 room -= frame_minheight(frp, NULL);
5145 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005146 if (curfrp->fr_width != Columns)
5147 room_cmdline = 0;
5148 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 {
5150 room_cmdline = Rows - p_ch - (lastwin->w_winrow
Bram Moolenaar415a6932017-12-05 20:31:07 +01005151 + VISIBLE_HEIGHT(lastwin)
5152 + lastwin->w_status_height);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153 if (room_cmdline < 0)
5154 room_cmdline = 0;
5155 }
5156
5157 if (height <= room + room_cmdline)
5158 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005159 if (run == 2 || curfrp->fr_width == Columns)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005160 {
5161 if (height > room + room_cmdline)
5162 height = room + room_cmdline;
5163 break;
5164 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005165 frame_setheight(curfrp->fr_parent, height
5166 + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005167 }
5168
5169 /*
5170 * Compute the number of lines we will take from others frames (can be
5171 * negative!).
5172 */
5173 take = height - curfrp->fr_height;
5174
5175 /* If there is not enough room, also reduce the height of a window
5176 * with 'winfixheight' set. */
5177 if (height > room + room_cmdline - room_reserved)
5178 room_reserved = room + room_cmdline - height;
5179 /* If there is only a 'winfixheight' window and making the
5180 * window smaller, need to make the other window taller. */
5181 if (take < 0 && room - curfrp->fr_height < room_reserved)
5182 room_reserved = 0;
5183
5184 if (take > 0 && room_cmdline > 0)
5185 {
5186 /* use lines from cmdline first */
5187 if (take < room_cmdline)
5188 room_cmdline = take;
5189 take -= room_cmdline;
5190 topframe->fr_height += room_cmdline;
5191 }
5192
5193 /*
5194 * set the current frame to the new height
5195 */
5196 frame_new_height(curfrp, height, FALSE, FALSE);
5197
5198 /*
5199 * First take lines from the frames after the current frame. If
5200 * that is not enough, takes lines from frames above the current
5201 * frame.
5202 */
5203 for (run = 0; run < 2; ++run)
5204 {
5205 if (run == 0)
5206 frp = curfrp->fr_next; /* 1st run: start with next window */
5207 else
5208 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5209 while (frp != NULL && take != 0)
5210 {
5211 h = frame_minheight(frp, NULL);
5212 if (room_reserved > 0
5213 && frp->fr_win != NULL
5214 && frp->fr_win->w_p_wfh)
5215 {
5216 if (room_reserved >= frp->fr_height)
5217 room_reserved -= frp->fr_height;
5218 else
5219 {
5220 if (frp->fr_height - room_reserved > take)
5221 room_reserved = frp->fr_height - take;
5222 take -= frp->fr_height - room_reserved;
5223 frame_new_height(frp, room_reserved, FALSE, FALSE);
5224 room_reserved = 0;
5225 }
5226 }
5227 else
5228 {
5229 if (frp->fr_height - take < h)
5230 {
5231 take -= frp->fr_height - h;
5232 frame_new_height(frp, h, FALSE, FALSE);
5233 }
5234 else
5235 {
5236 frame_new_height(frp, frp->fr_height - take,
5237 FALSE, FALSE);
5238 take = 0;
5239 }
5240 }
5241 if (run == 0)
5242 frp = frp->fr_next;
5243 else
5244 frp = frp->fr_prev;
5245 }
5246 }
5247 }
5248}
5249
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250/*
5251 * Set current window width and take care of repositioning other windows to
5252 * fit around it.
5253 */
5254 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005255win_setwidth(int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256{
5257 win_setwidth_win(width, curwin);
5258}
5259
5260 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005261win_setwidth_win(int width, win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005262{
5263 /* Always keep current window at least one column wide, even when
5264 * 'winminwidth' is zero. */
5265 if (wp == curwin)
5266 {
5267 if (width < p_wmw)
5268 width = p_wmw;
5269 if (width == 0)
5270 width = 1;
5271 }
5272
5273 frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
5274
5275 /* recompute the window positions */
5276 (void)win_comp_pos();
5277
5278 redraw_all_later(NOT_VALID);
5279}
5280
5281/*
5282 * Set the width of a frame to "width" and take care that all frames and
5283 * windows inside it are resized. Also resize frames above and below if the
5284 * are in the same FR_ROW frame.
5285 *
5286 * Strategy is similar to frame_setheight().
5287 */
5288 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005289frame_setwidth(frame_T *curfrp, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005290{
5291 int room; /* total number of lines available */
5292 int take; /* number of lines taken from other windows */
5293 int run;
5294 frame_T *frp;
5295 int w;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005296 int room_reserved;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297
5298 /* If the width already is the desired value, nothing to do. */
5299 if (curfrp->fr_width == width)
5300 return;
5301
5302 if (curfrp->fr_parent == NULL)
5303 /* topframe: can't change width */
5304 return;
5305
5306 if (curfrp->fr_parent->fr_layout == FR_COL)
5307 {
5308 /* Column of frames: Also need to resize frames above and below of
5309 * this one. First check for the minimal width of these. */
5310 w = frame_minwidth(curfrp->fr_parent, NULL);
5311 if (width < w)
5312 width = w;
5313 frame_setwidth(curfrp->fr_parent, width);
5314 }
5315 else
5316 {
5317 /*
5318 * Row of frames: try to change only frames in this row.
5319 *
5320 * Do this twice:
5321 * 1: compute room available, if it's not enough try resizing the
5322 * containing frame.
5323 * 2: compute the room available and adjust the width to it.
5324 */
5325 for (run = 1; run <= 2; ++run)
5326 {
5327 room = 0;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005328 room_reserved = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005329 for (frp = curfrp->fr_parent->fr_child; frp != NULL;
5330 frp = frp->fr_next)
5331 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005332 if (frp != curfrp
5333 && frp->fr_win != NULL
5334 && frp->fr_win->w_p_wfw)
5335 room_reserved += frp->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005336 room += frp->fr_width;
5337 if (frp != curfrp)
5338 room -= frame_minwidth(frp, NULL);
5339 }
5340
5341 if (width <= room)
5342 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00005343 if (run == 2 || curfrp->fr_height >= ROWS_AVAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344 {
5345 if (width > room)
5346 width = room;
5347 break;
5348 }
5349 frame_setwidth(curfrp->fr_parent, width
5350 + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
5351 }
5352
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353 /*
5354 * Compute the number of lines we will take from others frames (can be
5355 * negative!).
5356 */
5357 take = width - curfrp->fr_width;
5358
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005359 /* If there is not enough room, also reduce the width of a window
5360 * with 'winfixwidth' set. */
5361 if (width > room - room_reserved)
5362 room_reserved = room - width;
5363 /* If there is only a 'winfixwidth' window and making the
5364 * window smaller, need to make the other window narrower. */
5365 if (take < 0 && room - curfrp->fr_width < room_reserved)
5366 room_reserved = 0;
5367
Bram Moolenaar071d4272004-06-13 20:20:40 +00005368 /*
5369 * set the current frame to the new width
5370 */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005371 frame_new_width(curfrp, width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372
5373 /*
5374 * First take lines from the frames right of the current frame. If
5375 * that is not enough, takes lines from frames left of the current
5376 * frame.
5377 */
5378 for (run = 0; run < 2; ++run)
5379 {
5380 if (run == 0)
5381 frp = curfrp->fr_next; /* 1st run: start with next window */
5382 else
5383 frp = curfrp->fr_prev; /* 2nd run: start with prev window */
5384 while (frp != NULL && take != 0)
5385 {
5386 w = frame_minwidth(frp, NULL);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005387 if (room_reserved > 0
5388 && frp->fr_win != NULL
5389 && frp->fr_win->w_p_wfw)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005391 if (room_reserved >= frp->fr_width)
5392 room_reserved -= frp->fr_width;
5393 else
5394 {
5395 if (frp->fr_width - room_reserved > take)
5396 room_reserved = frp->fr_width - take;
5397 take -= frp->fr_width - room_reserved;
5398 frame_new_width(frp, room_reserved, FALSE, FALSE);
5399 room_reserved = 0;
5400 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005401 }
5402 else
5403 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005404 if (frp->fr_width - take < w)
5405 {
5406 take -= frp->fr_width - w;
5407 frame_new_width(frp, w, FALSE, FALSE);
5408 }
5409 else
5410 {
5411 frame_new_width(frp, frp->fr_width - take,
5412 FALSE, FALSE);
5413 take = 0;
5414 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005415 }
5416 if (run == 0)
5417 frp = frp->fr_next;
5418 else
5419 frp = frp->fr_prev;
5420 }
5421 }
5422 }
5423}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005424
5425/*
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005426 * Check 'winminheight' for a valid value and reduce it if needed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005427 */
5428 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005429win_setminheight(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005430{
5431 int room;
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005432 int needed;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005433 int first = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005434
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005435 // loop until there is a 'winminheight' that is possible
Bram Moolenaar071d4272004-06-13 20:20:40 +00005436 while (p_wmh > 0)
5437 {
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005438 room = Rows - p_ch;
5439 needed = frame_minheight(topframe, NULL);
5440 if (room >= needed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441 break;
5442 --p_wmh;
5443 if (first)
5444 {
5445 EMSG(_(e_noroom));
5446 first = FALSE;
5447 }
5448 }
5449}
5450
Bram Moolenaar1c3c1042018-06-12 16:49:30 +02005451/*
5452 * Check 'winminwidth' for a valid value and reduce it if needed.
5453 */
5454 void
5455win_setminwidth(void)
5456{
5457 int room;
5458 int needed;
5459 int first = TRUE;
5460
5461 // loop until there is a 'winminheight' that is possible
5462 while (p_wmw > 0)
5463 {
5464 room = Columns;
5465 needed = frame_minwidth(topframe, NULL);
5466 if (room >= needed)
5467 break;
5468 --p_wmw;
5469 if (first)
5470 {
5471 EMSG(_(e_noroom));
5472 first = FALSE;
5473 }
5474 }
5475}
5476
Bram Moolenaar6a2697f2015-11-19 13:14:30 +01005477#if defined(FEAT_MOUSE) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005478
5479/*
5480 * Status line of dragwin is dragged "offset" lines down (negative is up).
5481 */
5482 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005483win_drag_status_line(win_T *dragwin, int offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484{
5485 frame_T *curfr;
5486 frame_T *fr;
5487 int room;
5488 int row;
5489 int up; /* if TRUE, drag status line up, otherwise down */
5490 int n;
5491
5492 fr = dragwin->w_frame;
5493 curfr = fr;
5494 if (fr != topframe) /* more than one window */
5495 {
5496 fr = fr->fr_parent;
5497 /* When the parent frame is not a column of frames, its parent should
5498 * be. */
5499 if (fr->fr_layout != FR_COL)
5500 {
5501 curfr = fr;
5502 if (fr != topframe) /* only a row of windows, may drag statusline */
5503 fr = fr->fr_parent;
5504 }
5505 }
5506
5507 /* If this is the last frame in a column, may want to resize the parent
5508 * frame instead (go two up to skip a row of frames). */
5509 while (curfr != topframe && curfr->fr_next == NULL)
5510 {
5511 if (fr != topframe)
5512 fr = fr->fr_parent;
5513 curfr = fr;
5514 if (fr != topframe)
5515 fr = fr->fr_parent;
5516 }
5517
5518 if (offset < 0) /* drag up */
5519 {
5520 up = TRUE;
5521 offset = -offset;
5522 /* sum up the room of the current frame and above it */
5523 if (fr == curfr)
5524 {
5525 /* only one window */
5526 room = fr->fr_height - frame_minheight(fr, NULL);
5527 }
5528 else
5529 {
5530 room = 0;
5531 for (fr = fr->fr_child; ; fr = fr->fr_next)
5532 {
5533 room += fr->fr_height - frame_minheight(fr, NULL);
5534 if (fr == curfr)
5535 break;
5536 }
5537 }
5538 fr = curfr->fr_next; /* put fr at frame that grows */
5539 }
5540 else /* drag down */
5541 {
5542 up = FALSE;
5543 /*
5544 * Only dragging the last status line can reduce p_ch.
5545 */
5546 room = Rows - cmdline_row;
5547 if (curfr->fr_next == NULL)
5548 room -= 1;
5549 else
5550 room -= p_ch;
5551 if (room < 0)
5552 room = 0;
5553 /* sum up the room of frames below of the current one */
5554 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
5555 room += fr->fr_height - frame_minheight(fr, NULL);
5556 fr = curfr; /* put fr at window that grows */
5557 }
5558
5559 if (room < offset) /* Not enough room */
5560 offset = room; /* Move as far as we can */
5561 if (offset <= 0)
5562 return;
5563
5564 /*
5565 * Grow frame fr by "offset" lines.
5566 * Doesn't happen when dragging the last status line up.
5567 */
5568 if (fr != NULL)
5569 frame_new_height(fr, fr->fr_height + offset, up, FALSE);
5570
5571 if (up)
5572 fr = curfr; /* current frame gets smaller */
5573 else
5574 fr = curfr->fr_next; /* next frame gets smaller */
5575
5576 /*
5577 * Now make the other frames smaller.
5578 */
5579 while (fr != NULL && offset > 0)
5580 {
5581 n = frame_minheight(fr, NULL);
5582 if (fr->fr_height - offset <= n)
5583 {
5584 offset -= fr->fr_height - n;
5585 frame_new_height(fr, n, !up, FALSE);
5586 }
5587 else
5588 {
5589 frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
5590 break;
5591 }
5592 if (up)
5593 fr = fr->fr_prev;
5594 else
5595 fr = fr->fr_next;
5596 }
5597 row = win_comp_pos();
5598 screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
5599 cmdline_row = row;
5600 p_ch = Rows - cmdline_row;
5601 if (p_ch < 1)
5602 p_ch = 1;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005603 curtab->tp_ch_used = p_ch;
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005604 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605 showmode();
5606}
5607
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608/*
5609 * Separator line of dragwin is dragged "offset" lines right (negative is left).
5610 */
5611 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005612win_drag_vsep_line(win_T *dragwin, int offset)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005613{
5614 frame_T *curfr;
5615 frame_T *fr;
5616 int room;
5617 int left; /* if TRUE, drag separator line left, otherwise right */
5618 int n;
5619
5620 fr = dragwin->w_frame;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005621 if (fr == topframe) /* only one window (cannot happen?) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005622 return;
5623 curfr = fr;
5624 fr = fr->fr_parent;
5625 /* When the parent frame is not a row of frames, its parent should be. */
5626 if (fr->fr_layout != FR_ROW)
5627 {
5628 if (fr == topframe) /* only a column of windows (cannot happen?) */
5629 return;
5630 curfr = fr;
5631 fr = fr->fr_parent;
5632 }
5633
5634 /* If this is the last frame in a row, may want to resize a parent
5635 * frame instead. */
5636 while (curfr->fr_next == NULL)
5637 {
5638 if (fr == topframe)
5639 break;
5640 curfr = fr;
5641 fr = fr->fr_parent;
5642 if (fr != topframe)
5643 {
5644 curfr = fr;
5645 fr = fr->fr_parent;
5646 }
5647 }
5648
5649 if (offset < 0) /* drag left */
5650 {
5651 left = TRUE;
5652 offset = -offset;
5653 /* sum up the room of the current frame and left of it */
5654 room = 0;
5655 for (fr = fr->fr_child; ; fr = fr->fr_next)
5656 {
5657 room += fr->fr_width - frame_minwidth(fr, NULL);
5658 if (fr == curfr)
5659 break;
5660 }
5661 fr = curfr->fr_next; /* put fr at frame that grows */
5662 }
5663 else /* drag right */
5664 {
5665 left = FALSE;
5666 /* sum up the room of frames right of the current one */
5667 room = 0;
5668 for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
5669 room += fr->fr_width - frame_minwidth(fr, NULL);
5670 fr = curfr; /* put fr at window that grows */
5671 }
5672
5673 if (room < offset) /* Not enough room */
5674 offset = room; /* Move as far as we can */
5675 if (offset <= 0) /* No room at all, quit. */
5676 return;
Bram Moolenaar294a7e52015-11-22 19:39:38 +01005677 if (fr == NULL)
5678 return; /* Safety check, should not happen. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005679
5680 /* grow frame fr by offset lines */
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005681 frame_new_width(fr, fr->fr_width + offset, left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005682
5683 /* shrink other frames: current and at the left or at the right */
5684 if (left)
5685 fr = curfr; /* current frame gets smaller */
5686 else
5687 fr = curfr->fr_next; /* next frame gets smaller */
5688
5689 while (fr != NULL && offset > 0)
5690 {
5691 n = frame_minwidth(fr, NULL);
5692 if (fr->fr_width - offset <= n)
5693 {
5694 offset -= fr->fr_width - n;
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005695 frame_new_width(fr, n, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696 }
5697 else
5698 {
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00005699 frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700 break;
5701 }
5702 if (left)
5703 fr = fr->fr_prev;
5704 else
5705 fr = fr->fr_next;
5706 }
5707 (void)win_comp_pos();
5708 redraw_all_later(NOT_VALID);
5709}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710#endif /* FEAT_MOUSE */
5711
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005712#define FRACTION_MULT 16384L
5713
5714/*
5715 * Set wp->w_fraction for the current w_wrow and w_height.
Bram Moolenaar3679c172017-11-22 22:22:11 +01005716 * Has no effect when the window is less than two lines.
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005717 */
Bram Moolenaar9dc2ce32015-12-05 19:47:04 +01005718 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005719set_fraction(win_T *wp)
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005720{
Bram Moolenaar3679c172017-11-22 22:22:11 +01005721 if (wp->w_height > 1)
5722 wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005723 + wp->w_height / 2) / (long)wp->w_height;
Bram Moolenaar0215e8e2010-12-17 17:35:10 +01005724}
5725
Bram Moolenaar071d4272004-06-13 20:20:40 +00005726/*
5727 * Set the height of a window.
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005728 * "height" excludes any window toolbar.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729 * This takes care of the things inside the window, not what happens to the
5730 * window position, the frame or to other windows.
5731 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005732 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005733win_new_height(win_T *wp, int height)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005734{
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005735 int prev_height = wp->w_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736
5737 /* Don't want a negative height. Happens when splitting a tiny window.
5738 * Will equalize heights soon to fix it. */
5739 if (height < 0)
5740 height = 0;
Bram Moolenaar4c3f5362006-04-11 21:38:50 +00005741 if (wp->w_height == height)
5742 return; /* nothing to do */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005743
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005744 if (wp->w_height > 0)
5745 {
5746 if (wp == curwin)
Bram Moolenaar0ae36a52014-06-13 20:08:45 +02005747 /* w_wrow needs to be valid. When setting 'laststatus' this may
5748 * call win_new_height() recursively. */
5749 validate_cursor();
5750 if (wp->w_height != prev_height)
5751 return; /* Recursive call already changed the size, bail out here
5752 to avoid the following to mess things up. */
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005753 if (wp->w_wrow != wp->w_prev_fraction_row)
5754 set_fraction(wp);
5755 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005756
5757 wp->w_height = height;
5758 wp->w_skipcol = 0;
5759
Bram Moolenaar955f1982017-02-05 15:10:51 +01005760 /* There is no point in adjusting the scroll position when exiting. Some
5761 * values might be invalid. */
5762 if (!exiting)
5763 scroll_to_fraction(wp, prev_height);
Bram Moolenaar46328f92016-08-28 15:39:57 +02005764}
5765
5766 void
5767scroll_to_fraction(win_T *wp, int prev_height)
5768{
5769 linenr_T lnum;
5770 int sline, line_size;
5771 int height = wp->w_height;
5772
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773 /* Don't change w_topline when height is zero. Don't set w_topline when
5774 * 'scrollbind' is set and this isn't the current window. */
Bram Moolenaar8a3bb562018-03-04 20:14:14 +01005775 if (height > 0 && (!wp->w_p_scb || wp == curwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776 {
Bram Moolenaar34114692005-01-02 11:28:13 +00005777 /*
5778 * Find a value for w_topline that shows the cursor at the same
5779 * relative position in the window as before (more or less).
5780 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 lnum = wp->w_cursor.lnum;
5782 if (lnum < 1) /* can happen when starting up */
5783 lnum = 1;
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005784 wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L
5785 + FRACTION_MULT / 2) / FRACTION_MULT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786 line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
5787 sline = wp->w_wrow - line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005788
5789 if (sline >= 0)
5790 {
5791 /* Make sure the whole cursor line is visible, if possible. */
5792 int rows = plines_win(wp, lnum, FALSE);
5793
5794 if (sline > wp->w_height - rows)
5795 {
5796 sline = wp->w_height - rows;
5797 wp->w_wrow -= rows - line_size;
5798 }
5799 }
5800
Bram Moolenaar071d4272004-06-13 20:20:40 +00005801 if (sline < 0)
5802 {
5803 /*
5804 * Cursor line would go off top of screen if w_wrow was this high.
Bram Moolenaar26470632006-10-24 19:12:40 +00005805 * Make cursor line the first line in the window. If not enough
5806 * room use w_skipcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005807 */
5808 wp->w_wrow = line_size;
Bram Moolenaar26470632006-10-24 19:12:40 +00005809 if (wp->w_wrow >= wp->w_height
Bram Moolenaar02631462017-09-22 15:20:32 +02005810 && (wp->w_width - win_col_off(wp)) > 0)
Bram Moolenaar26470632006-10-24 19:12:40 +00005811 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005812 wp->w_skipcol += wp->w_width - win_col_off(wp);
Bram Moolenaar26470632006-10-24 19:12:40 +00005813 --wp->w_wrow;
5814 while (wp->w_wrow >= wp->w_height)
5815 {
Bram Moolenaar02631462017-09-22 15:20:32 +02005816 wp->w_skipcol += wp->w_width - win_col_off(wp)
Bram Moolenaar26470632006-10-24 19:12:40 +00005817 + win_col_off2(wp);
5818 --wp->w_wrow;
5819 }
5820 }
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005821 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005822 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005823 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005824 {
Bram Moolenaar26470632006-10-24 19:12:40 +00005825 while (sline > 0 && lnum > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826 {
5827#ifdef FEAT_FOLDING
5828 hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
5829 if (lnum == 1)
5830 {
5831 /* first line in buffer is folded */
5832 line_size = 1;
5833 --sline;
5834 break;
5835 }
5836#endif
5837 --lnum;
5838#ifdef FEAT_DIFF
5839 if (lnum == wp->w_topline)
5840 line_size = plines_win_nofill(wp, lnum, TRUE)
5841 + wp->w_topfill;
5842 else
5843#endif
5844 line_size = plines_win(wp, lnum, TRUE);
5845 sline -= line_size;
5846 }
Bram Moolenaar34114692005-01-02 11:28:13 +00005847
Bram Moolenaar071d4272004-06-13 20:20:40 +00005848 if (sline < 0)
5849 {
5850 /*
5851 * Line we want at top would go off top of screen. Use next
5852 * line instead.
5853 */
5854#ifdef FEAT_FOLDING
5855 hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
5856#endif
5857 lnum++;
5858 wp->w_wrow -= line_size + sline;
5859 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005860 else if (sline > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861 {
5862 /* First line of file reached, use that as topline. */
5863 lnum = 1;
5864 wp->w_wrow -= sline;
5865 }
Bram Moolenaardd0402a2014-05-28 13:43:04 +02005866
Bram Moolenaarb4d21352014-07-16 14:16:46 +02005867 set_topline(wp, lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005869 }
5870
5871 if (wp == curwin)
5872 {
5873 if (p_so)
5874 update_topline();
5875 curs_columns(FALSE); /* validate w_wrow */
5876 }
Bram Moolenaar56b3bf82014-05-07 20:25:35 +02005877 if (prev_height > 0)
5878 wp->w_prev_fraction_row = wp->w_wrow;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879
5880 win_comp_scroll(wp);
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00005881 redraw_win_later(wp, SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882 wp->w_redr_status = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 invalidate_botline_win(wp);
5884}
5885
Bram Moolenaar071d4272004-06-13 20:20:40 +00005886/*
5887 * Set the width of a window.
5888 */
Bram Moolenaar6763c142012-07-19 18:05:44 +02005889 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005890win_new_width(win_T *wp, int width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891{
5892 wp->w_width = width;
5893 wp->w_lines_valid = 0;
5894 changed_line_abv_curs_win(wp);
5895 invalidate_botline_win(wp);
5896 if (wp == curwin)
5897 {
5898 update_topline();
5899 curs_columns(TRUE); /* validate w_wrow */
5900 }
5901 redraw_win_later(wp, NOT_VALID);
5902 wp->w_redr_status = TRUE;
5903}
Bram Moolenaar071d4272004-06-13 20:20:40 +00005904
5905 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005906win_comp_scroll(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005907{
5908 wp->w_p_scr = ((unsigned)wp->w_height >> 1);
5909 if (wp->w_p_scr == 0)
5910 wp->w_p_scr = 1;
5911}
5912
5913/*
5914 * command_height: called whenever p_ch has been changed
5915 */
5916 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005917command_height(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005918{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 int h;
5920 frame_T *frp;
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005921 int old_p_ch = curtab->tp_ch_used;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922
Bram Moolenaarc6fe9192006-04-09 21:54:49 +00005923 /* Use the value of p_ch that we remembered. This is needed for when the
5924 * GUI starts up, we can't be sure in what order things happen. And when
5925 * p_ch was changed in another tab page. */
5926 curtab->tp_ch_used = p_ch;
Bram Moolenaar05159a02005-02-26 23:04:13 +00005927
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928 /* Find bottom frame with width of screen. */
5929 frp = lastwin->w_frame;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930 while (frp->fr_width != Columns && frp->fr_parent != NULL)
5931 frp = frp->fr_parent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932
5933 /* Avoid changing the height of a window with 'winfixheight' set. */
5934 while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
5935 && frp->fr_win->w_p_wfh)
5936 frp = frp->fr_prev;
5937
5938 if (starting != NO_SCREEN)
5939 {
5940 cmdline_row = Rows - p_ch;
5941
5942 if (p_ch > old_p_ch) /* p_ch got bigger */
5943 {
5944 while (p_ch > old_p_ch)
5945 {
5946 if (frp == NULL)
5947 {
5948 EMSG(_(e_noroom));
5949 p_ch = old_p_ch;
Bram Moolenaar719939c2007-09-25 12:51:28 +00005950 curtab->tp_ch_used = p_ch;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951 cmdline_row = Rows - p_ch;
5952 break;
5953 }
5954 h = frp->fr_height - frame_minheight(frp, NULL);
5955 if (h > p_ch - old_p_ch)
5956 h = p_ch - old_p_ch;
5957 old_p_ch += h;
5958 frame_add_height(frp, -h);
5959 frp = frp->fr_prev;
5960 }
5961
5962 /* Recompute window positions. */
5963 (void)win_comp_pos();
5964
5965 /* clear the lines added to cmdline */
5966 if (full_screen)
5967 screen_fill((int)(cmdline_row), (int)Rows, 0,
5968 (int)Columns, ' ', ' ', 0);
5969 msg_row = cmdline_row;
5970 redraw_cmdline = TRUE;
5971 return;
5972 }
5973
5974 if (msg_row < cmdline_row)
5975 msg_row = cmdline_row;
5976 redraw_cmdline = TRUE;
5977 }
5978 frame_add_height(frp, (int)(old_p_ch - p_ch));
5979
5980 /* Recompute window positions. */
5981 if (frp != lastwin->w_frame)
5982 (void)win_comp_pos();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005983}
5984
Bram Moolenaar071d4272004-06-13 20:20:40 +00005985/*
5986 * Resize frame "frp" to be "n" lines higher (negative for less high).
5987 * Also resize the frames it is contained in.
5988 */
5989 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01005990frame_add_height(frame_T *frp, int n)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005991{
5992 frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
5993 for (;;)
5994 {
5995 frp = frp->fr_parent;
5996 if (frp == NULL)
5997 break;
5998 frp->fr_height += n;
5999 }
6000}
6001
6002/*
6003 * Add or remove a status line for the bottom window(s), according to the
6004 * value of 'laststatus'.
6005 */
6006 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006007last_status(
6008 int morewin) /* pretend there are two or more windows */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006009{
6010 /* Don't make a difference between horizontal or vertical split. */
6011 last_status_rec(topframe, (p_ls == 2
Bram Moolenaar459ca562016-11-10 18:16:33 +01006012 || (p_ls == 1 && (morewin || !ONE_WINDOW))));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006013}
6014
6015 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006016last_status_rec(frame_T *fr, int statusline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017{
6018 frame_T *fp;
6019 win_T *wp;
6020
6021 if (fr->fr_layout == FR_LEAF)
6022 {
6023 wp = fr->fr_win;
6024 if (wp->w_status_height != 0 && !statusline)
6025 {
6026 /* remove status line */
6027 win_new_height(wp, wp->w_height + 1);
6028 wp->w_status_height = 0;
6029 comp_col();
6030 }
6031 else if (wp->w_status_height == 0 && statusline)
6032 {
6033 /* Find a frame to take a line from. */
6034 fp = fr;
6035 while (fp->fr_height <= frame_minheight(fp, NULL))
6036 {
6037 if (fp == topframe)
6038 {
6039 EMSG(_(e_noroom));
6040 return;
6041 }
6042 /* In a column of frames: go to frame above. If already at
6043 * the top or in a row of frames: go to parent. */
6044 if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
6045 fp = fp->fr_prev;
6046 else
6047 fp = fp->fr_parent;
6048 }
6049 wp->w_status_height = 1;
6050 if (fp != fr)
6051 {
6052 frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
6053 frame_fix_height(wp);
6054 (void)win_comp_pos();
6055 }
6056 else
6057 win_new_height(wp, wp->w_height - 1);
6058 comp_col();
Bram Moolenaarf71a3db2006-03-12 21:50:18 +00006059 redraw_all_later(SOME_VALID);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060 }
6061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062 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 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068 else
6069 {
6070 /* horizontally split window, set status line for last one */
6071 for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
6072 ;
6073 last_status_rec(fp, statusline);
6074 }
6075}
6076
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006077/*
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006078 * Return the number of lines used by the tab page line.
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006079 */
6080 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006081tabline_height(void)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006082{
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006083#ifdef FEAT_GUI_TABLINE
6084 /* When the GUI has the tabline then this always returns zero. */
6085 if (gui_use_tabline())
6086 return 0;
6087#endif
Bram Moolenaar2a0449d2006-02-20 21:27:21 +00006088 switch (p_stal)
Bram Moolenaar98ea5de2006-02-15 22:11:25 +00006089 {
6090 case 0: return 0;
6091 case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
6092 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006093 return 1;
6094}
6095
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096#if defined(FEAT_SEARCHPATH) || defined(PROTO)
6097/*
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006098 * Get the file name at the cursor.
6099 * If Visual mode is active, use the selected text if it's in one line.
6100 * Returns the name in allocated memory, NULL for failure.
6101 */
6102 char_u *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006103grab_file_name(long count, linenr_T *file_lnum)
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006104{
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006105 int options = FNAME_MESS|FNAME_EXP|FNAME_REL|FNAME_UNESC;
6106
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006107 if (VIsual_active)
6108 {
6109 int len;
6110 char_u *ptr;
6111
6112 if (get_visual_text(NULL, &ptr, &len) == FAIL)
6113 return NULL;
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006114 return find_file_name_in_path(ptr, len, options,
6115 count, curbuf->b_ffname);
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006116 }
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006117 return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
Bram Moolenaard857f0e2005-06-21 22:37:39 +00006118}
6119
6120/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121 * Return the file name under or after the cursor.
6122 *
6123 * The 'path' option is searched if the file name is not absolute.
6124 * The string returned has been alloc'ed and should be freed by the caller.
6125 * NULL is returned if the file name or file is not found.
6126 *
6127 * options:
6128 * FNAME_MESS give error messages
6129 * FNAME_EXP expand to path
6130 * FNAME_HYP check for hypertext link
6131 * FNAME_INCL apply "includeexpr"
6132 */
6133 char_u *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006134file_name_at_cursor(int options, long count, linenr_T *file_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006135{
6136 return file_name_in_line(ml_get_curline(),
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006137 curwin->w_cursor.col, options, count, curbuf->b_ffname,
6138 file_lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139}
6140
6141/*
6142 * Return the name of the file under or after ptr[col].
6143 * Otherwise like file_name_at_cursor().
6144 */
6145 char_u *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006146file_name_in_line(
6147 char_u *line,
6148 int col,
6149 int options,
6150 long count,
6151 char_u *rel_fname, /* file we are searching relative to */
6152 linenr_T *file_lnum) /* line number after the file name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006153{
6154 char_u *ptr;
6155 int len;
Bram Moolenaar9e3dfc62017-12-25 14:29:18 +01006156 int in_type = TRUE;
6157 int is_url = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158
6159 /*
6160 * search forward for what could be the start of a file name
6161 */
6162 ptr = line + col;
6163 while (*ptr != NUL && !vim_isfilec(*ptr))
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006164 MB_PTR_ADV(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165 if (*ptr == NUL) /* nothing found */
6166 {
6167 if (options & FNAME_MESS)
6168 EMSG(_("E446: No file name under cursor"));
6169 return NULL;
6170 }
6171
6172 /*
6173 * Search backward for first char of the file name.
6174 * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
6175 */
6176 while (ptr > line)
6177 {
6178#ifdef FEAT_MBYTE
6179 if (has_mbyte && (len = (*mb_head_off)(line, ptr - 1)) > 0)
6180 ptr -= len + 1;
6181 else
6182#endif
6183 if (vim_isfilec(ptr[-1])
6184 || ((options & FNAME_HYP) && path_is_url(ptr - 1)))
6185 --ptr;
6186 else
6187 break;
6188 }
6189
6190 /*
6191 * Search forward for the last char of the file name.
6192 * Also allow "://" when ':' is not in 'isfname'.
6193 */
6194 len = 0;
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006195 while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
Bram Moolenaar9e3dfc62017-12-25 14:29:18 +01006196 || ((options & FNAME_HYP) && path_is_url(ptr + len))
6197 || (is_url && vim_strchr((char_u *)"?&=", ptr[len]) != NULL))
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006198 {
Bram Moolenaar9e3dfc62017-12-25 14:29:18 +01006199 /* After type:// we also include ?, & and = as valid characters, so that
6200 * http://google.com?q=this&that=ok works. */
6201 if ((ptr[len] >= 'A' && ptr[len] <= 'Z') || (ptr[len] >= 'a' && ptr[len] <= 'z'))
6202 {
6203 if (in_type && path_is_url(ptr + len + 1))
6204 is_url = TRUE;
6205 }
6206 else
6207 in_type = FALSE;
6208
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006209 if (ptr[len] == '\\')
6210 /* Skip over the "\" in "\ ". */
6211 ++len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006212#ifdef FEAT_MBYTE
6213 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00006214 len += (*mb_ptr2len)(ptr + len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006215 else
6216#endif
6217 ++len;
Bram Moolenaard45c07a2015-02-27 17:19:10 +01006218 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006219
6220 /*
6221 * If there is trailing punctuation, remove it.
6222 * But don't remove "..", could be a directory name.
6223 */
6224 if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
6225 && ptr[len - 2] != '.')
6226 --len;
6227
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006228 if (file_lnum != NULL)
6229 {
6230 char_u *p;
6231
6232 /* Get the number after the file name and a separator character */
6233 p = ptr + len;
6234 p = skipwhite(p);
6235 if (*p != NUL)
6236 {
6237 if (!isdigit(*p))
6238 ++p; /* skip the separator */
6239 p = skipwhite(p);
6240 if (isdigit(*p))
6241 *file_lnum = (int)getdigits(&p);
6242 }
6243 }
6244
Bram Moolenaar071d4272004-06-13 20:20:40 +00006245 return find_file_name_in_path(ptr, len, options, count, rel_fname);
6246}
6247
6248# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01006249static char_u *eval_includeexpr(char_u *ptr, int len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006250
6251 static char_u *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006252eval_includeexpr(char_u *ptr, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253{
6254 char_u *res;
6255
6256 set_vim_var_string(VV_FNAME, ptr, len);
Bram Moolenaar2d3f4892006-01-20 23:02:51 +00006257 res = eval_to_string_safe(curbuf->b_p_inex, NULL,
Bram Moolenaard1f56e62006-02-22 21:25:37 +00006258 was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006259 set_vim_var_string(VV_FNAME, NULL, 0);
6260 return res;
6261}
6262#endif
6263
6264/*
6265 * Return the name of the file ptr[len] in 'path'.
6266 * Otherwise like file_name_at_cursor().
6267 */
6268 char_u *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006269find_file_name_in_path(
6270 char_u *ptr,
6271 int len,
6272 int options,
6273 long count,
6274 char_u *rel_fname) /* file we are searching relative to */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275{
6276 char_u *file_name;
6277 int c;
6278# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6279 char_u *tofree = NULL;
6280
6281 if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
6282 {
6283 tofree = eval_includeexpr(ptr, len);
6284 if (tofree != NULL)
6285 {
6286 ptr = tofree;
6287 len = (int)STRLEN(ptr);
6288 }
6289 }
6290# endif
6291
6292 if (options & FNAME_EXP)
6293 {
6294 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
6295 TRUE, rel_fname);
6296
6297# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6298 /*
6299 * If the file could not be found in a normal way, try applying
6300 * 'includeexpr' (unless done already).
6301 */
6302 if (file_name == NULL
6303 && !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL)
6304 {
6305 tofree = eval_includeexpr(ptr, len);
6306 if (tofree != NULL)
6307 {
6308 ptr = tofree;
6309 len = (int)STRLEN(ptr);
6310 file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
6311 TRUE, rel_fname);
6312 }
6313 }
6314# endif
6315 if (file_name == NULL && (options & FNAME_MESS))
6316 {
6317 c = ptr[len];
6318 ptr[len] = NUL;
6319 EMSG2(_("E447: Can't find file \"%s\" in path"), ptr);
6320 ptr[len] = c;
6321 }
6322
6323 /* Repeat finding the file "count" times. This matters when it
6324 * appears several times in the path. */
6325 while (file_name != NULL && --count > 0)
6326 {
6327 vim_free(file_name);
6328 file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
6329 }
6330 }
6331 else
6332 file_name = vim_strnsave(ptr, len);
6333
6334# if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
6335 vim_free(tofree);
6336# endif
6337
6338 return file_name;
6339}
6340#endif /* FEAT_SEARCHPATH */
6341
6342/*
6343 * Check if the "://" of a URL is at the pointer, return URL_SLASH.
6344 * Also check for ":\\", which MS Internet Explorer accepts, return
6345 * URL_BACKSLASH.
6346 */
6347 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006348path_is_url(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006349{
6350 if (STRNCMP(p, "://", (size_t)3) == 0)
6351 return URL_SLASH;
6352 else if (STRNCMP(p, ":\\\\", (size_t)3) == 0)
6353 return URL_BACKSLASH;
6354 return 0;
6355}
6356
6357/*
6358 * Check if "fname" starts with "name://". Return URL_SLASH if it does.
6359 * Return URL_BACKSLASH for "name:\\".
6360 * Return zero otherwise.
6361 */
6362 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006363path_with_url(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006364{
6365 char_u *p;
6366
6367 for (p = fname; isalpha(*p); ++p)
6368 ;
6369 return path_is_url(p);
6370}
6371
6372/*
6373 * Return TRUE if "name" is a full (absolute) path name or URL.
6374 */
6375 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006376vim_isAbsName(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006377{
6378 return (path_with_url(name) != 0 || mch_isFullName(name));
6379}
6380
6381/*
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00006382 * Get absolute file name into buffer "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006383 *
6384 * return FAIL for failure, OK otherwise
6385 */
6386 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006387vim_FullName(
6388 char_u *fname,
6389 char_u *buf,
6390 int len,
6391 int force) /* force expansion even when already absolute */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006392{
6393 int retval = OK;
6394 int url;
6395
6396 *buf = NUL;
6397 if (fname == NULL)
6398 return FAIL;
6399
6400 url = path_with_url(fname);
6401 if (!url)
6402 retval = mch_FullName(fname, buf, len, force);
6403 if (url || retval == FAIL)
6404 {
6405 /* something failed; use the file name (truncate when too long) */
Bram Moolenaarb6356332005-07-18 21:40:44 +00006406 vim_strncpy(buf, fname, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006407 }
Bram Moolenaard0573012017-10-28 21:11:06 +02006408#if defined(MSWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006409 slash_adjust(buf);
6410#endif
6411 return retval;
6412}
6413
6414/*
6415 * Return the minimal number of rows that is needed on the screen to display
6416 * the current number of windows.
6417 */
6418 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006419min_rows(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006420{
6421 int total;
Bram Moolenaarf740b292006-02-16 22:11:02 +00006422 tabpage_T *tp;
6423 int n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424
6425 if (firstwin == NULL) /* not initialized yet */
6426 return MIN_LINES;
6427
Bram Moolenaarf740b292006-02-16 22:11:02 +00006428 total = 0;
Bram Moolenaar29323592016-07-24 22:04:11 +02006429 FOR_ALL_TABPAGES(tp)
Bram Moolenaarf740b292006-02-16 22:11:02 +00006430 {
6431 n = frame_minheight(tp->tp_topframe, NULL);
6432 if (total < n)
6433 total = n;
6434 }
Bram Moolenaar32466aa2006-02-24 23:53:04 +00006435 total += tabline_height();
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
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006446only_one_window(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006447{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448 int count = 0;
6449 win_T *wp;
6450
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00006451 /* If there is another tab page there always is another window. */
6452 if (first_tabpage->tp_next != NULL)
6453 return FALSE;
6454
Bram Moolenaar29323592016-07-24 22:04:11 +02006455 FOR_ALL_WINDOWS(wp)
Bram Moolenaar802418d2013-01-17 14:00:11 +01006456 if (wp->w_buffer != NULL
Bram Moolenaard28cc3f2017-07-27 22:03:50 +02006457 && (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006458# ifdef FEAT_QUICKFIX
6459 || wp->w_p_pvw
6460# endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006461 ) || wp == curwin) && wp != aucmd_win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006462 ++count;
6463 return (count <= 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006464}
6465
Bram Moolenaar071d4272004-06-13 20:20:40 +00006466/*
6467 * Correct the cursor line number in other windows. Used after changing the
6468 * current buffer, and before applying autocommands.
6469 * When "do_curwin" is TRUE, also check current window.
6470 */
6471 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006472check_lnums(int do_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006473{
6474 win_T *wp;
Bram Moolenaarf740b292006-02-16 22:11:02 +00006475 tabpage_T *tp;
6476
6477 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006478 if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006479 {
6480 if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
6481 wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6482 if (wp->w_topline > curbuf->b_ml.ml_line_count)
6483 wp->w_topline = curbuf->b_ml.ml_line_count;
6484 }
6485}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006486
6487/*
6488 * A snapshot of the window sizes, to restore them after closing the help
6489 * window.
6490 * Only these fields are used:
6491 * fr_layout
6492 * fr_width
6493 * fr_height
6494 * fr_next
6495 * fr_child
6496 * fr_win (only valid for the old curwin, NULL otherwise)
6497 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006498
6499/*
6500 * Create a snapshot of the current frame sizes.
6501 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006502 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006503make_snapshot(int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006505 clear_snapshot(curtab, idx);
6506 make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006507}
6508
6509 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006510make_snapshot_rec(frame_T *fr, frame_T **frp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006511{
6512 *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
6513 if (*frp == NULL)
6514 return;
6515 (*frp)->fr_layout = fr->fr_layout;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006516 (*frp)->fr_width = fr->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517 (*frp)->fr_height = fr->fr_height;
6518 if (fr->fr_next != NULL)
6519 make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
6520 if (fr->fr_child != NULL)
6521 make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
6522 if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
6523 (*frp)->fr_win = curwin;
6524}
6525
6526/*
6527 * Remove any existing snapshot.
6528 */
6529 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006530clear_snapshot(tabpage_T *tp, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006531{
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006532 clear_snapshot_rec(tp->tp_snapshot[idx]);
6533 tp->tp_snapshot[idx] = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006534}
6535
6536 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006537clear_snapshot_rec(frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538{
6539 if (fr != NULL)
6540 {
6541 clear_snapshot_rec(fr->fr_next);
6542 clear_snapshot_rec(fr->fr_child);
6543 vim_free(fr);
6544 }
6545}
6546
6547/*
6548 * Restore a previously created snapshot, if there is any.
6549 * This is only done if the screen size didn't change and the window layout is
6550 * still the same.
6551 */
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006552 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006553restore_snapshot(
6554 int idx,
6555 int close_curwin) /* closing current window */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006556{
6557 win_T *wp;
6558
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006559 if (curtab->tp_snapshot[idx] != NULL
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006560 && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006561 && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
6562 && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006563 {
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006564 wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565 win_comp_pos();
6566 if (wp != NULL && close_curwin)
6567 win_goto(wp);
6568 redraw_all_later(CLEAR);
6569 }
Bram Moolenaar746ebd32009-06-16 14:01:43 +00006570 clear_snapshot(curtab, idx);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006571}
6572
6573/*
6574 * Check if frames "sn" and "fr" have the same layout, same following frames
Bram Moolenaar343b8c02017-02-17 12:04:56 +01006575 * and same children. And the window pointer is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576 */
6577 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006578check_snapshot_rec(frame_T *sn, frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006579{
6580 if (sn->fr_layout != fr->fr_layout
6581 || (sn->fr_next == NULL) != (fr->fr_next == NULL)
6582 || (sn->fr_child == NULL) != (fr->fr_child == NULL)
6583 || (sn->fr_next != NULL
6584 && check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
6585 || (sn->fr_child != NULL
Bram Moolenaar343b8c02017-02-17 12:04:56 +01006586 && check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
Bram Moolenaar2c90d512017-03-18 22:35:30 +01006587 || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006588 return FAIL;
6589 return OK;
6590}
6591
6592/*
6593 * Copy the size of snapshot frame "sn" to frame "fr". Do the same for all
6594 * following frames and children.
6595 * Returns a pointer to the old current window, or NULL.
6596 */
6597 static win_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006598restore_snapshot_rec(frame_T *sn, frame_T *fr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599{
6600 win_T *wp = NULL;
6601 win_T *wp2;
6602
6603 fr->fr_height = sn->fr_height;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006604 fr->fr_width = sn->fr_width;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605 if (fr->fr_layout == FR_LEAF)
6606 {
6607 frame_new_height(fr, fr->fr_height, FALSE, FALSE);
Bram Moolenaarbe4d5062006-03-18 21:30:13 +00006608 frame_new_width(fr, fr->fr_width, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006609 wp = sn->fr_win;
6610 }
6611 if (sn->fr_next != NULL)
6612 {
6613 wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
6614 if (wp2 != NULL)
6615 wp = wp2;
6616 }
6617 if (sn->fr_child != NULL)
6618 {
6619 wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
6620 if (wp2 != NULL)
6621 wp = wp2;
6622 }
6623 return wp;
6624}
6625
Bram Moolenaar95064ec2013-07-17 17:15:25 +02006626#if defined(FEAT_EVAL) || defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) \
6627 || defined(PROTO)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006628/*
6629 * Set "win" to be the curwin and "tp" to be the current tab page.
Bram Moolenaar5d2bae82014-09-19 14:26:36 +02006630 * restore_win() MUST be called to undo, also when FAIL is returned.
6631 * No autocommands will be executed until restore_win() is called.
Bram Moolenaard6949742013-06-16 14:18:28 +02006632 * When "no_display" is TRUE the display won't be affected, no redraw is
6633 * triggered, another tabpage access is limited.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006634 * Returns FAIL if switching to "win" failed.
6635 */
6636 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006637switch_win(
Bram Moolenaar816968d2017-09-29 21:29:18 +02006638 win_T **save_curwin,
6639 tabpage_T **save_curtab,
6640 win_T *win,
6641 tabpage_T *tp,
6642 int no_display)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006643{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006644 block_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006645 *save_curwin = curwin;
6646 if (tp != NULL)
6647 {
6648 *save_curtab = curtab;
Bram Moolenaard6949742013-06-16 14:18:28 +02006649 if (no_display)
6650 {
6651 curtab->tp_firstwin = firstwin;
6652 curtab->tp_lastwin = lastwin;
6653 curtab = tp;
6654 firstwin = curtab->tp_firstwin;
6655 lastwin = curtab->tp_lastwin;
6656 }
6657 else
6658 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar105bc352013-05-17 16:03:57 +02006659 }
6660 if (!win_valid(win))
Bram Moolenaar105bc352013-05-17 16:03:57 +02006661 return FAIL;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006662 curwin = win;
6663 curbuf = curwin->w_buffer;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006664 return OK;
6665}
6666
6667/*
6668 * Restore current tabpage and window saved by switch_win(), if still valid.
Bram Moolenaard6949742013-06-16 14:18:28 +02006669 * When "no_display" is TRUE the display won't be affected, no redraw is
6670 * triggered.
Bram Moolenaar105bc352013-05-17 16:03:57 +02006671 */
6672 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006673restore_win(
6674 win_T *save_curwin UNUSED,
6675 tabpage_T *save_curtab UNUSED,
6676 int no_display UNUSED)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006677{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006678 if (save_curtab != NULL && valid_tabpage(save_curtab))
Bram Moolenaard6949742013-06-16 14:18:28 +02006679 {
6680 if (no_display)
6681 {
6682 curtab->tp_firstwin = firstwin;
6683 curtab->tp_lastwin = lastwin;
6684 curtab = save_curtab;
6685 firstwin = curtab->tp_firstwin;
6686 lastwin = curtab->tp_lastwin;
6687 }
6688 else
6689 goto_tabpage_tp(save_curtab, FALSE, FALSE);
6690 }
Bram Moolenaar105bc352013-05-17 16:03:57 +02006691 if (win_valid(save_curwin))
6692 {
6693 curwin = save_curwin;
6694 curbuf = curwin->w_buffer;
6695 }
Bram Moolenaar105bc352013-05-17 16:03:57 +02006696 unblock_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006697}
6698
6699/*
6700 * Make "buf" the current buffer. restore_buffer() MUST be called to undo.
6701 * No autocommands will be executed. Use aucmd_prepbuf() if there are any.
6702 */
6703 void
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006704switch_buffer(bufref_T *save_curbuf, buf_T *buf)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006705{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006706 block_autocmds();
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006707 set_bufref(save_curbuf, curbuf);
Bram Moolenaar105bc352013-05-17 16:03:57 +02006708 --curbuf->b_nwindows;
6709 curbuf = buf;
6710 curwin->w_buffer = buf;
6711 ++curbuf->b_nwindows;
6712}
6713
6714/*
6715 * Restore the current buffer after using switch_buffer().
6716 */
6717 void
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006718restore_buffer(bufref_T *save_curbuf)
Bram Moolenaar105bc352013-05-17 16:03:57 +02006719{
Bram Moolenaar105bc352013-05-17 16:03:57 +02006720 unblock_autocmds();
Bram Moolenaar105bc352013-05-17 16:03:57 +02006721 /* Check for valid buffer, just in case. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006722 if (bufref_valid(save_curbuf))
Bram Moolenaar105bc352013-05-17 16:03:57 +02006723 {
6724 --curbuf->b_nwindows;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02006725 curwin->w_buffer = save_curbuf->br_buf;
6726 curbuf = save_curbuf->br_buf;
Bram Moolenaar105bc352013-05-17 16:03:57 +02006727 ++curbuf->b_nwindows;
6728 }
6729}
6730#endif
6731
Bram Moolenaar4033c552017-09-16 20:54:51 +02006732#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006733/*
6734 * Return TRUE if there is any vertically split window.
6735 */
6736 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006737win_hasvertsplit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006738{
6739 frame_T *fr;
6740
6741 if (topframe->fr_layout == FR_ROW)
6742 return TRUE;
6743
6744 if (topframe->fr_layout == FR_COL)
6745 for (fr = topframe->fr_child; fr != NULL; fr = fr->fr_next)
6746 if (fr->fr_layout == FR_ROW)
6747 return TRUE;
6748
6749 return FALSE;
6750}
6751#endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006752
6753#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
6754/*
6755 * Add match to the match list of window 'wp'. The pattern 'pat' will be
Bram Moolenaare37d50a2008-08-06 17:06:04 +00006756 * highlighted with the group 'grp' with priority 'prio'.
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006757 * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
6758 * If no particular ID is desired, -1 must be specified for 'id'.
6759 * Return ID of added match, -1 on failure.
6760 */
6761 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006762match_add(
6763 win_T *wp,
6764 char_u *grp,
6765 char_u *pat,
6766 int prio,
6767 int id,
6768 list_T *pos_list,
6769 char_u *conceal_char UNUSED) /* pointer to conceal replacement char */
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006770{
Bram Moolenaarb3414592014-06-17 17:48:32 +02006771 matchitem_T *cur;
6772 matchitem_T *prev;
6773 matchitem_T *m;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006774 int hlg_id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006775 regprog_T *regprog = NULL;
6776 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006777
Bram Moolenaarb3414592014-06-17 17:48:32 +02006778 if (*grp == NUL || (pat != NULL && *pat == NUL))
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006779 return -1;
6780 if (id < -1 || id == 0)
6781 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02006782 EMSGN(_("E799: Invalid ID: %ld (must be greater than or equal to 1)"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006783 return -1;
6784 }
6785 if (id != -1)
6786 {
6787 cur = wp->w_match_head;
6788 while (cur != NULL)
6789 {
6790 if (cur->id == id)
6791 {
Bram Moolenaar5b302912016-08-24 22:11:55 +02006792 EMSGN(_("E801: ID already taken: %ld"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006793 return -1;
6794 }
6795 cur = cur->next;
6796 }
6797 }
Bram Moolenaarcb4cef22008-03-16 15:04:34 +00006798 if ((hlg_id = syn_namen2id(grp, (int)STRLEN(grp))) == 0)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006799 {
6800 EMSG2(_(e_nogroup), grp);
6801 return -1;
6802 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006803 if (pat != NULL && (regprog = vim_regcomp(pat, RE_MAGIC)) == NULL)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006804 {
6805 EMSG2(_(e_invarg2), pat);
6806 return -1;
6807 }
6808
6809 /* Find available match ID. */
6810 while (id == -1)
6811 {
6812 cur = wp->w_match_head;
6813 while (cur != NULL && cur->id != wp->w_next_match_id)
6814 cur = cur->next;
6815 if (cur == NULL)
6816 id = wp->w_next_match_id;
6817 wp->w_next_match_id++;
6818 }
6819
6820 /* Build new match. */
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006821 m = (matchitem_T *)alloc_clear(sizeof(matchitem_T));
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006822 m->id = id;
6823 m->priority = prio;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006824 m->pattern = pat == NULL ? NULL : vim_strsave(pat);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006825 m->hlg_id = hlg_id;
Bram Moolenaar0963cd92007-08-05 16:49:43 +00006826 m->match.regprog = regprog;
6827 m->match.rmm_ic = FALSE;
6828 m->match.rmm_maxcol = 0;
Bram Moolenaar42356152016-03-31 22:27:40 +02006829# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
Bram Moolenaar6561d522015-07-21 15:48:27 +02006830 m->conceal_char = 0;
6831 if (conceal_char != NULL)
6832 m->conceal_char = (*mb_ptr2char)(conceal_char);
Bram Moolenaar42356152016-03-31 22:27:40 +02006833# endif
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006834
Bram Moolenaarb3414592014-06-17 17:48:32 +02006835 /* Set up position matches */
6836 if (pos_list != NULL)
6837 {
6838 linenr_T toplnum = 0;
6839 linenr_T botlnum = 0;
6840 listitem_T *li;
6841 int i;
6842
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006843 for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006844 i++, li = li->li_next)
6845 {
6846 linenr_T lnum = 0;
6847 colnr_T col = 0;
6848 int len = 1;
6849 list_T *subl;
6850 listitem_T *subli;
Bram Moolenaardeae0f22014-06-18 21:20:11 +02006851 int error = FALSE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006852
Bram Moolenaarb3414592014-06-17 17:48:32 +02006853 if (li->li_tv.v_type == VAR_LIST)
6854 {
6855 subl = li->li_tv.vval.v_list;
6856 if (subl == NULL)
6857 goto fail;
6858 subli = subl->lv_first;
6859 if (subli == NULL)
6860 goto fail;
6861 lnum = get_tv_number_chk(&subli->li_tv, &error);
6862 if (error == TRUE)
6863 goto fail;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006864 if (lnum == 0)
6865 {
6866 --i;
6867 continue;
6868 }
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006869 m->pos.pos[i].lnum = lnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006870 subli = subli->li_next;
6871 if (subli != NULL)
6872 {
6873 col = get_tv_number_chk(&subli->li_tv, &error);
6874 if (error == TRUE)
6875 goto fail;
6876 subli = subli->li_next;
6877 if (subli != NULL)
6878 {
6879 len = get_tv_number_chk(&subli->li_tv, &error);
6880 if (error == TRUE)
6881 goto fail;
6882 }
6883 }
6884 m->pos.pos[i].col = col;
6885 m->pos.pos[i].len = len;
6886 }
6887 else if (li->li_tv.v_type == VAR_NUMBER)
6888 {
6889 if (li->li_tv.vval.v_number == 0)
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006890 {
6891 --i;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006892 continue;
Bram Moolenaarb6da44a2014-06-25 18:15:22 +02006893 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02006894 m->pos.pos[i].lnum = li->li_tv.vval.v_number;
6895 m->pos.pos[i].col = 0;
6896 m->pos.pos[i].len = 0;
6897 }
6898 else
6899 {
6900 EMSG(_("List or number required"));
6901 goto fail;
6902 }
6903 if (toplnum == 0 || lnum < toplnum)
6904 toplnum = lnum;
Bram Moolenaar41d75232014-06-25 17:58:11 +02006905 if (botlnum == 0 || lnum >= botlnum)
6906 botlnum = lnum + 1;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006907 }
6908
6909 /* Calculate top and bottom lines for redrawing area */
6910 if (toplnum != 0)
6911 {
6912 if (wp->w_buffer->b_mod_set)
6913 {
6914 if (wp->w_buffer->b_mod_top > toplnum)
6915 wp->w_buffer->b_mod_top = toplnum;
6916 if (wp->w_buffer->b_mod_bot < botlnum)
6917 wp->w_buffer->b_mod_bot = botlnum;
6918 }
6919 else
6920 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02006921 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006922 wp->w_buffer->b_mod_top = toplnum;
6923 wp->w_buffer->b_mod_bot = botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02006924 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006925 }
6926 m->pos.toplnum = toplnum;
6927 m->pos.botlnum = botlnum;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006928 rtype = VALID;
6929 }
6930 }
6931
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006932 /* Insert new match. The match list is in ascending order with regard to
6933 * the match priorities. */
6934 cur = wp->w_match_head;
6935 prev = cur;
6936 while (cur != NULL && prio >= cur->priority)
6937 {
6938 prev = cur;
6939 cur = cur->next;
6940 }
6941 if (cur == prev)
6942 wp->w_match_head = m;
6943 else
6944 prev->next = m;
6945 m->next = cur;
6946
Bram Moolenaarb3414592014-06-17 17:48:32 +02006947 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006948 return id;
Bram Moolenaarb3414592014-06-17 17:48:32 +02006949
6950fail:
6951 vim_free(m);
6952 return -1;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006953}
6954
6955/*
6956 * Delete match with ID 'id' in the match list of window 'wp'.
6957 * Print error messages if 'perr' is TRUE.
6958 */
6959 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01006960match_delete(win_T *wp, int id, int perr)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006961{
Bram Moolenaarb3414592014-06-17 17:48:32 +02006962 matchitem_T *cur = wp->w_match_head;
6963 matchitem_T *prev = cur;
6964 int rtype = SOME_VALID;
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006965
6966 if (id < 1)
6967 {
6968 if (perr == TRUE)
Bram Moolenaar5b302912016-08-24 22:11:55 +02006969 EMSGN(_("E802: Invalid ID: %ld (must be greater than or equal to 1)"),
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006970 id);
6971 return -1;
6972 }
6973 while (cur != NULL && cur->id != id)
6974 {
6975 prev = cur;
6976 cur = cur->next;
6977 }
6978 if (cur == NULL)
6979 {
6980 if (perr == TRUE)
Bram Moolenaar5b302912016-08-24 22:11:55 +02006981 EMSGN(_("E803: ID not found: %ld"), id);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006982 return -1;
6983 }
6984 if (cur == prev)
6985 wp->w_match_head = cur->next;
6986 else
6987 prev->next = cur->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02006988 vim_regfree(cur->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00006989 vim_free(cur->pattern);
Bram Moolenaarb3414592014-06-17 17:48:32 +02006990 if (cur->pos.toplnum != 0)
6991 {
6992 if (wp->w_buffer->b_mod_set)
6993 {
6994 if (wp->w_buffer->b_mod_top > cur->pos.toplnum)
6995 wp->w_buffer->b_mod_top = cur->pos.toplnum;
6996 if (wp->w_buffer->b_mod_bot < cur->pos.botlnum)
6997 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
6998 }
6999 else
7000 {
Bram Moolenaardab70c62014-07-02 17:16:58 +02007001 wp->w_buffer->b_mod_set = TRUE;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007002 wp->w_buffer->b_mod_top = cur->pos.toplnum;
7003 wp->w_buffer->b_mod_bot = cur->pos.botlnum;
Bram Moolenaardab70c62014-07-02 17:16:58 +02007004 wp->w_buffer->b_mod_xlines = 0;
Bram Moolenaarb3414592014-06-17 17:48:32 +02007005 }
Bram Moolenaarb3414592014-06-17 17:48:32 +02007006 rtype = VALID;
7007 }
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007008 vim_free(cur);
Bram Moolenaarb3414592014-06-17 17:48:32 +02007009 redraw_later(rtype);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007010 return 0;
7011}
7012
7013/*
7014 * Delete all matches in the match list of window 'wp'.
7015 */
7016 void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01007017clear_matches(win_T *wp)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007018{
7019 matchitem_T *m;
7020
7021 while (wp->w_match_head != NULL)
7022 {
7023 m = wp->w_match_head->next;
Bram Moolenaar473de612013-06-08 18:19:48 +02007024 vim_regfree(wp->w_match_head->match.regprog);
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007025 vim_free(wp->w_match_head->pattern);
7026 vim_free(wp->w_match_head);
7027 wp->w_match_head = m;
7028 }
7029 redraw_later(SOME_VALID);
7030}
7031
7032/*
7033 * Get match from ID 'id' in window 'wp'.
7034 * Return NULL if match not found.
7035 */
7036 matchitem_T *
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01007037get_match(win_T *wp, int id)
Bram Moolenaar6ee10162007-07-26 20:58:42 +00007038{
7039 matchitem_T *cur = wp->w_match_head;
7040
7041 while (cur != NULL && cur->id != id)
7042 cur = cur->next;
7043 return cur;
7044}
7045#endif
Bram Moolenaar6d216452013-05-12 19:00:41 +02007046
7047#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
7048 int
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007049get_win_number(win_T *wp, win_T *first_win)
Bram Moolenaar6d216452013-05-12 19:00:41 +02007050{
7051 int i = 1;
7052 win_T *w;
7053
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007054 for (w = first_win; w != NULL && w != wp; w = W_NEXT(w))
Bram Moolenaar6d216452013-05-12 19:00:41 +02007055 ++i;
7056
7057 if (w == NULL)
7058 return 0;
7059 else
7060 return i;
7061}
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007062
7063 int
Bram Moolenaar8c0e3222013-06-16 17:32:40 +02007064get_tab_number(tabpage_T *tp UNUSED)
Bram Moolenaar5e538ec2013-05-15 15:12:29 +02007065{
7066 int i = 1;
7067 tabpage_T *t;
7068
7069 for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next)
7070 ++i;
7071
7072 if (t == NULL)
7073 return 0;
7074 else
7075 return i;
7076}
Bram Moolenaar6d216452013-05-12 19:00:41 +02007077#endif
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007078
7079/*
7080 * Return TRUE if "topfrp" and its children are at the right height.
7081 */
7082 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01007083frame_check_height(frame_T *topfrp, int height)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007084{
7085 frame_T *frp;
7086
7087 if (topfrp->fr_height != height)
7088 return FALSE;
7089
7090 if (topfrp->fr_layout == FR_ROW)
7091 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
7092 if (frp->fr_height != height)
7093 return FALSE;
7094
7095 return TRUE;
7096}
7097
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007098/*
7099 * Return TRUE if "topfrp" and its children are at the right width.
7100 */
7101 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +01007102frame_check_width(frame_T *topfrp, int width)
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007103{
7104 frame_T *frp;
7105
7106 if (topfrp->fr_width != width)
7107 return FALSE;
7108
7109 if (topfrp->fr_layout == FR_COL)
7110 for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
7111 if (frp->fr_width != width)
7112 return FALSE;
7113
7114 return TRUE;
7115}
Bram Moolenaarb893ac22013-06-26 14:04:47 +02007116
Bram Moolenaar86edef62016-03-13 18:07:30 +01007117#if defined(FEAT_EVAL) || defined(PROTO)
7118 int
7119win_getid(typval_T *argvars)
7120{
7121 int winnr;
7122 win_T *wp;
7123
7124 if (argvars[0].v_type == VAR_UNKNOWN)
7125 return curwin->w_id;
7126 winnr = get_tv_number(&argvars[0]);
7127 if (winnr > 0)
7128 {
7129 if (argvars[1].v_type == VAR_UNKNOWN)
7130 wp = firstwin;
7131 else
7132 {
7133 tabpage_T *tp;
7134 int tabnr = get_tv_number(&argvars[1]);
7135
Bram Moolenaar29323592016-07-24 22:04:11 +02007136 FOR_ALL_TABPAGES(tp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01007137 if (--tabnr == 0)
7138 break;
7139 if (tp == NULL)
7140 return -1;
Bram Moolenaar8e639052016-11-13 14:31:40 +01007141 if (tp == curtab)
7142 wp = firstwin;
7143 else
7144 wp = tp->tp_firstwin;
Bram Moolenaar86edef62016-03-13 18:07:30 +01007145 }
7146 for ( ; wp != NULL; wp = wp->w_next)
7147 if (--winnr == 0)
7148 return wp->w_id;
7149 }
7150 return 0;
7151}
7152
7153 int
7154win_gotoid(typval_T *argvars)
7155{
7156 win_T *wp;
7157 tabpage_T *tp;
7158 int id = get_tv_number(&argvars[0]);
7159
Bram Moolenaar29323592016-07-24 22:04:11 +02007160 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01007161 if (wp->w_id == id)
7162 {
7163 goto_tabpage_win(tp, wp);
7164 return 1;
7165 }
7166 return 0;
7167}
7168
7169 void
7170win_id2tabwin(typval_T *argvars, list_T *list)
7171{
7172 win_T *wp;
7173 tabpage_T *tp;
7174 int winnr = 1;
7175 int tabnr = 1;
7176 int id = get_tv_number(&argvars[0]);
7177
Bram Moolenaar29323592016-07-24 22:04:11 +02007178 FOR_ALL_TABPAGES(tp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01007179 {
Bram Moolenaar29323592016-07-24 22:04:11 +02007180 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01007181 {
7182 if (wp->w_id == id)
7183 {
7184 list_append_number(list, tabnr);
7185 list_append_number(list, winnr);
7186 return;
7187 }
7188 ++winnr;
7189 }
7190 ++tabnr;
7191 winnr = 1;
7192 }
7193 list_append_number(list, 0);
7194 list_append_number(list, 0);
7195}
7196
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02007197 win_T *
7198win_id2wp(typval_T *argvars)
7199{
7200 win_T *wp;
7201 tabpage_T *tp;
7202 int id = get_tv_number(&argvars[0]);
7203
7204 FOR_ALL_TAB_WINDOWS(tp, wp)
7205 if (wp->w_id == id)
7206 return wp;
7207
7208 return NULL;
7209}
7210
Bram Moolenaar86edef62016-03-13 18:07:30 +01007211 int
7212win_id2win(typval_T *argvars)
7213{
7214 win_T *wp;
7215 int nr = 1;
7216 int id = get_tv_number(&argvars[0]);
7217
Bram Moolenaar29323592016-07-24 22:04:11 +02007218 FOR_ALL_WINDOWS(wp)
Bram Moolenaar86edef62016-03-13 18:07:30 +01007219 {
7220 if (wp->w_id == id)
7221 return nr;
7222 ++nr;
7223 }
7224 return 0;
7225}
Bram Moolenaar9cdf86b2016-03-13 19:04:51 +01007226
7227 void
7228win_findbuf(typval_T *argvars, list_T *list)
7229{
7230 win_T *wp;
7231 tabpage_T *tp;
7232 int bufnr = get_tv_number(&argvars[0]);
7233
Bram Moolenaar29323592016-07-24 22:04:11 +02007234 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar9cdf86b2016-03-13 19:04:51 +01007235 if (wp->w_buffer->b_fnum == bufnr)
7236 list_append_number(list, wp->w_id);
7237}
7238
Bram Moolenaar86edef62016-03-13 18:07:30 +01007239#endif