aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r--src/nvim/window.c1628
1 files changed, 887 insertions, 741 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 343d279b1d..2bffe2055f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -26,7 +26,9 @@
#include "nvim/globals.h"
#include "nvim/hashtab.h"
#include "nvim/main.h"
+#include "nvim/mapping.h"
#include "nvim/mark.h"
+#include "nvim/match.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
@@ -52,15 +54,13 @@
#include "nvim/vim.h"
#include "nvim/window.h"
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "window.c.generated.h"
#endif
+#define NOWIN ((win_T *)-1) // non-existing window
-#define NOWIN (win_T *)-1 // non-existing window
-
-#define ROWS_AVAIL (Rows - p_ch - tabline_height())
+#define ROWS_AVAIL (Rows - p_ch - tabline_height() - global_stl_height())
/// flags for win_enter_ext()
typedef enum {
@@ -71,8 +71,49 @@ typedef enum {
WEE_TRIGGER_LEAVE_AUTOCMDS = 0x10,
} wee_flags_T;
+static char e_cannot_split_window_when_closing_buffer[]
+ = N_("E1159: Cannot split a window when closing the buffer");
+
static char *m_onlyone = N_("Already only one window");
+/// When non-zero splitting a window is forbidden. Used to avoid that nasty
+/// autocommands mess up the window structure.
+static int split_disallowed = 0;
+
+// #define WIN_DEBUG
+#ifdef WIN_DEBUG
+/// Call this method to log the current window layout.
+static void log_frame_layout(frame_T *frame)
+{
+ DLOG("layout %s, wi: %d, he: %d, wwi: %d, whe: %d, id: %d",
+ frame->fr_layout == FR_LEAF ? "LEAF" : frame->fr_layout == FR_ROW ? "ROW" : "COL",
+ frame->fr_width,
+ frame->fr_height,
+ frame->fr_win == NULL ? -1 : frame->fr_win->w_width,
+ frame->fr_win == NULL ? -1 : frame->fr_win->w_height,
+ frame->fr_win == NULL ? -1 : frame->fr_win->w_id);
+ if (frame->fr_child != NULL) {
+ DLOG("children");
+ log_frame_layout(frame->fr_child);
+ if (frame->fr_next != NULL) {
+ DLOG("END of children");
+ }
+ }
+ if (frame->fr_next != NULL) {
+ log_frame_layout(frame->fr_next);
+ }
+}
+#endif
+
+/// @return the current window, unless in the cmdline window and "prevwin" is
+/// set, then return "prevwin".
+win_T *prevwin_curwin(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // In cmdwin, the alternative buffer should be used.
+ return is_in_cmdwin() && prevwin != NULL ? prevwin : curwin;
+}
+
/// all CTRL-W window commands are handled here, called from normal_cmd().
///
/// @param xchar extra char from ":wincmd gx" or NUL
@@ -290,7 +331,8 @@ newwindow:
// move window to new tab page
case 'T':
- if (one_window()) {
+ CHECK_CMDWIN;
+ if (one_window(curwin)) {
msg(_(m_onlyone));
} else {
tabpage_T *oldtab = curtab;
@@ -304,7 +346,7 @@ newwindow:
newtab = curtab;
goto_tabpage_tp(oldtab, true, true);
if (curwin == wp) {
- win_close(curwin, false);
+ win_close(curwin, false, false);
}
if (valid_tabpage(newtab)) {
goto_tabpage_tp(newtab, true, true);
@@ -387,7 +429,7 @@ newwindow:
// set current window height
case Ctrl__:
case '_':
- win_setheight(Prenum ? (int)Prenum : Rows-1);
+ win_setheight(Prenum ? (int)Prenum : Rows - 1);
break;
// increase current window width
@@ -447,9 +489,9 @@ wingotofile:
setpcmark();
if (win_split(0, 0) == OK) {
RESET_BINDING(curwin);
- if (do_ecmd(0, ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
+ if (do_ecmd(0, (char *)ptr, NULL, NULL, ECMD_LASTL, ECMD_HIDE, NULL) == FAIL) {
// Failed to open the file, close the window opened for it.
- win_close(curwin, false);
+ win_close(curwin, false, false);
goto_tabpage_win(oldtab, oldwin);
} else if (nchar == 'F' && lnum >= 0) {
curwin->w_cursor.lnum = lnum;
@@ -473,9 +515,14 @@ wingotofile:
if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
break;
}
+
+ // Make a copy, if the line was changed it will be freed.
+ ptr = vim_strnsave(ptr, len);
+
find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
- curwin->w_set_curswant = TRUE;
+ xfree(ptr);
+ curwin->w_set_curswant = true;
break;
// Quickfix window only: view the result under the cursor in a new split.
@@ -486,17 +533,18 @@ wingotofile:
}
break;
-
// CTRL-W g extended commands
case 'g':
case Ctrl_G:
CHECK_CMDWIN;
no_mapping++;
+ allow_keys++; // no mapping for xchar, but allow key codes
if (xchar == NUL) {
xchar = plain_vgetc();
}
LANGMAP_ADJUST(xchar, true);
no_mapping--;
+ allow_keys--;
(void)add_to_showcmd(xchar);
switch (xchar) {
case '}':
@@ -521,13 +569,9 @@ wingotofile:
do_nv_ident('g', xchar);
break;
- case TAB:
- goto_tabpage_lastused();
- break;
-
case 'f': // CTRL-W gf: "gf" in a new tab page
case 'F': // CTRL-W gF: "gF" in a new tab page
- cmdmod.tab = tabpage_index(curtab) + 1;
+ cmdmod.cmod_tab = tabpage_index(curtab) + 1;
nchar = xchar;
goto wingotofile;
case 't': // CTRL-W gt: go to next tab page
@@ -538,6 +582,12 @@ wingotofile:
goto_tabpage(-(int)Prenum1);
break;
+ case TAB: // CTRL-W g<Tab>: go to last used tab page
+ if (!goto_tabpage_lastused()) {
+ beep_flush();
+ }
+ break;
+
case 'e':
if (curwin->w_floating || !ui_has(kUIMultigrid)) {
beep_flush();
@@ -548,7 +598,7 @@ wingotofile:
config.height = curwin->w_height;
config.external = true;
Error err = ERROR_INIT;
- if (!win_new_float(curwin, config, &err)) {
+ if (!win_new_float(curwin, false, config, &err)) {
emsg(err.msg);
api_clear_error(&err);
beep_flush();
@@ -577,18 +627,19 @@ static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, int64_t Pren
void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err)
{
- win_T *win = find_window_by_handle(window, err), *save_curwin = curwin;
+ win_T *win = find_window_by_handle(window, err);
buf_T *buf = find_buffer_by_handle(buffer, err);
- tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab;
+ tabpage_T *tab = win_find_tabpage(win);
if (!win || !buf) {
return;
}
-
if (noautocmd) {
block_autocmds();
}
- if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) {
+
+ switchwin_T switchwin;
+ if (switch_win_noblock(&switchwin, win, tab, false) == FAIL) {
api_set_error(err,
kErrorTypeException,
"Failed to switch to window %d",
@@ -608,7 +659,7 @@ void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err)
// So do it now.
validate_cursor();
- restore_win_noblock(save_curwin, save_curtab, false);
+ restore_win_noblock(&switchwin, false);
if (noautocmd) {
unblock_autocmds();
}
@@ -616,16 +667,18 @@ void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err)
/// Create a new float.
///
-/// if wp == NULL allocate a new window, otherwise turn existing window into a
-/// float. It must then already belong to the current tabpage!
-///
-/// config must already have been validated!
-win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
+/// @param wp if NULL, allocate a new window, otherwise turn existing window into a float.
+/// It must then already belong to the current tabpage!
+/// @param last make the window the last one in the window list.
+/// Only used when allocating the autocommand window.
+/// @param config must already have been validated!
+win_T *win_new_float(win_T *wp, bool last, FloatConfig fconfig, Error *err)
{
if (wp == NULL) {
- wp = win_alloc(lastwin_nofloating(), false);
+ wp = win_alloc(last ? lastwin : lastwin_nofloating(), false);
win_init(wp, curwin, 0);
} else {
+ assert(!last);
assert(!wp->w_floating);
if (firstwin == wp && lastwin_nofloating() == wp) {
// last non-float
@@ -646,6 +699,8 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
}
wp->w_floating = 1;
wp->w_status_height = 0;
+ wp->w_winbar_height = 0;
+ wp->w_hsep_height = 0;
wp->w_vsep_width = 0;
win_config_float(wp, fconfig);
@@ -717,7 +772,6 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
wp->w_float_config.border_hl_ids,
sizeof fconfig.border_hl_ids));
-
wp->w_float_config = fconfig;
bool has_border = wp->w_floating && wp->w_float_config.border;
@@ -730,10 +784,8 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
}
if (!ui_has(kUIMultigrid)) {
- wp->w_height = MIN(wp->w_height,
- Rows - 1 - (wp->w_border_adj[0] + wp->w_border_adj[2]));
- wp->w_width = MIN(wp->w_width,
- Columns - (wp->w_border_adj[1] + wp->w_border_adj[3]));
+ wp->w_height = MIN(wp->w_height, Rows - 1 - win_border_height(wp));
+ wp->w_width = MIN(wp->w_width, Columns - win_border_width(wp));
}
win_set_inner_size(wp);
@@ -756,7 +808,7 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
col += parent->w_wincol;
ScreenGrid *grid = &parent->w_grid;
int row_off = 0, col_off = 0;
- screen_adjust_grid(&grid, &row_off, &col_off);
+ grid_adjust(&grid, &row_off, &col_off);
row += row_off;
col += col_off;
}
@@ -820,22 +872,22 @@ void ui_ext_win_position(win_T *wp)
FloatConfig c = wp->w_float_config;
if (!c.external) {
ScreenGrid *grid = &default_grid;
- float row = c.row, col = c.col;
+ Float row = c.row, col = c.col;
if (c.relative == kFloatRelativeWindow) {
Error dummy = ERROR_INIT;
win_T *win = find_window_by_handle(c.window, &dummy);
if (win) {
grid = &win->w_grid;
int row_off = 0, col_off = 0;
- screen_adjust_grid(&grid, &row_off, &col_off);
+ grid_adjust(&grid, &row_off, &col_off);
row += row_off;
col += col_off;
if (c.bufpos.lnum >= 0) {
- pos_T pos = { c.bufpos.lnum+1, c.bufpos.col, 0 };
+ pos_T pos = { c.bufpos.lnum + 1, c.bufpos.col, 0 };
int trow, tcol, tcolc, tcole;
textpos2screenpos(win, &pos, &trow, &tcol, &tcolc, &tcole, true);
- row += trow-1;
- col += tcol-1;
+ row += trow - 1;
+ col += tcol - 1;
}
}
api_clear_error(&dummy);
@@ -843,7 +895,7 @@ void ui_ext_win_position(win_T *wp)
wp->w_grid_alloc.zindex = wp->w_float_config.zindex;
if (ui_has(kUIMultigrid)) {
- String anchor = cstr_to_string(float_anchor_str[c.anchor]);
+ String anchor = cstr_as_string((char *)float_anchor_str[c.anchor]);
ui_call_win_float_pos(wp->w_grid_alloc.handle, wp->handle, anchor,
grid->handle, row, col, c.focusable,
wp->w_grid_alloc.zindex);
@@ -857,7 +909,7 @@ void ui_ext_win_position(win_T *wp)
int comp_col = (int)col - (east ? wp->w_width_outer : 0);
comp_row += grid->comp_row;
comp_col += grid->comp_col;
- comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - 1), 0);
+ comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - (p_ch > 0 ? 1 : 0)), 0);
comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0);
wp->w_winrow = comp_row;
wp->w_wincol = comp_col;
@@ -881,18 +933,33 @@ void ui_ext_win_viewport(win_T *wp)
if ((wp == curwin || ui_has(kUIMultigrid)) && wp->w_viewport_invalid) {
int botline = wp->w_botline;
int line_count = wp->w_buffer->b_ml.ml_line_count;
- if (botline == line_count+1 && wp->w_empty_rows == 0) {
+ if (botline == line_count + 1 && wp->w_empty_rows == 0) {
// TODO(bfredl): The might be more cases to consider, like how does this
// interact with incomplete final line? Diff filler lines?
botline = wp->w_buffer->b_ml.ml_line_count;
}
- ui_call_win_viewport(wp->w_grid_alloc.handle, wp->handle, wp->w_topline-1,
- botline, wp->w_cursor.lnum-1, wp->w_cursor.col,
+ ui_call_win_viewport(wp->w_grid_alloc.handle, wp->handle, wp->w_topline - 1,
+ botline, wp->w_cursor.lnum - 1, wp->w_cursor.col,
line_count);
wp->w_viewport_invalid = false;
}
}
+/// If "split_disallowed" is set given an error and return FAIL.
+/// Otherwise return OK.
+static int check_split_disallowed(void)
+{
+ if (split_disallowed > 0) {
+ emsg(_("E242: Can't split a window while closing another"));
+ return FAIL;
+ }
+ if (curwin->w_buffer->b_locked_split) {
+ emsg(_(e_cannot_split_window_when_closing_buffer));
+ return FAIL;
+ }
+ return OK;
+}
+
/*
* split the current window, implements CTRL-W s and :split
*
@@ -902,21 +969,25 @@ void ui_ext_win_viewport(win_T *wp)
* "flags":
* WSP_ROOM: require enough room for new window
* WSP_VERT: vertical split.
- * WSP_TOP: open window at the top-left of the shell (help window).
- * WSP_BOT: open window at the bottom-right of the shell (quickfix window).
+ * WSP_TOP: open window at the top-left of the screen (help window).
+ * WSP_BOT: open window at the bottom-right of the screen (quickfix window).
* WSP_HELP: creating the help window, keep layout snapshot
*
* return FAIL for failure, OK otherwise
*/
int win_split(int size, int flags)
{
+ if (check_split_disallowed() == FAIL) {
+ return FAIL;
+ }
+
// When the ":tab" modifier was used open a new tab page instead.
if (may_open_tabpage() == OK) {
return OK;
}
// Add flags from ":vertical", ":topleft" and ":botright".
- flags |= cmdmod.split;
+ flags |= cmdmod.cmod_split;
if ((flags & WSP_TOP) && (flags & WSP_BOT)) {
emsg(_("E442: Can't split topleft and botright at the same time"));
return FAIL;
@@ -957,6 +1028,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
int wmh1;
bool did_set_fraction = false;
+ // aucmd_win should always remain floating
+ if (new_wp != NULL && new_wp == aucmd_win) {
+ return FAIL;
+ }
+
if (flags & WSP_TOP) {
oldwin = firstwin;
} else if (flags & WSP_BOT || curwin->w_floating) {
@@ -977,7 +1053,6 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
need_status = STATUS_HEIGHT;
}
-
if (flags & WSP_VERT) {
int wmw1;
int minwidth;
@@ -1064,15 +1139,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else {
layout = FR_COL;
- /*
- * Check if we are able to split the current window and compute its
- * height.
- */
- // Current window requires at least 1 space.
- wmh1 = p_wmh == 0 ? 1 : p_wmh;
+ // Check if we are able to split the current window and compute its height.
+ // Current window requires at least 1 space plus space for the window bar.
+ wmh1 = MAX(p_wmh, 1) + oldwin->w_winbar_height;
needed = wmh1 + STATUS_HEIGHT;
if (flags & WSP_ROOM) {
- needed += p_wh - wmh1;
+ needed += p_wh - wmh1 + oldwin->w_winbar_height;
+ }
+ if (p_ch < 1) {
+ needed += 1; // Adjust for cmdheight=0.
}
if (flags & (WSP_BOT | WSP_TOP)) {
minheight = frame_minheight(topframe, NOWIN) + need_status;
@@ -1081,8 +1156,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else if (p_ea) {
minheight = frame_minheight(oldwin->w_frame, NOWIN) + need_status;
prevfrp = oldwin->w_frame;
- for (frp = oldwin->w_frame->fr_parent; frp != NULL;
- frp = frp->fr_parent) {
+ for (frp = oldwin->w_frame->fr_parent; frp != NULL; frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
@@ -1150,8 +1224,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
while (frp != NULL) {
if (frp->fr_win != oldwin && frp->fr_win != NULL
&& (frp->fr_win->w_height > new_size
- || frp->fr_win->w_height > oldwin_height - new_size
- - STATUS_HEIGHT)) {
+ || frp->fr_win->w_height > oldwin_height - new_size - STATUS_HEIGHT)) {
do_equal = true;
break;
}
@@ -1194,8 +1267,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
} else if (wp->w_floating) {
new_frame(wp);
wp->w_floating = false;
- // non-floating window doesn't store float config.
+ // non-floating window doesn't store float config or have a border.
wp->w_float_config = FLOAT_CONFIG_INIT;
+ memset(wp->w_border_adj, 0, sizeof(wp->w_border_adj));
}
/*
@@ -1277,13 +1351,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & (WSP_TOP | WSP_BOT)) {
// set height and row of new window to full height
wp->w_winrow = tabline_height();
- win_new_height(wp, curfrp->fr_height - (p_ls > 0));
- wp->w_status_height = (p_ls > 0);
+ win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2));
+ wp->w_status_height = (p_ls == 1 || p_ls == 2);
+ wp->w_hsep_height = 0;
} else {
// height and row of new window is same as current window
wp->w_winrow = oldwin->w_winrow;
win_new_height(wp, oldwin->w_height);
wp->w_status_height = oldwin->w_status_height;
+ wp->w_hsep_height = oldwin->w_hsep_height;
}
frp->fr_height = curfrp->fr_height;
@@ -1316,6 +1392,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
frame_fix_width(oldwin);
frame_fix_width(wp);
} else {
+ bool is_stl_global = global_stl_height() > 0;
// width and column of new window is same as current window
if (flags & (WSP_TOP | WSP_BOT)) {
wp->w_wincol = 0;
@@ -1331,28 +1408,52 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// "new_size" of the current window goes to the new window, use
// one row for the status line
win_new_height(wp, new_size);
+ if (before) {
+ wp->w_hsep_height = is_stl_global ? 1 : 0;
+ } else {
+ wp->w_hsep_height = oldwin->w_hsep_height;
+ oldwin->w_hsep_height = is_stl_global ? 1 : 0;
+ }
if (flags & (WSP_TOP | WSP_BOT)) {
int new_fr_height = curfrp->fr_height - new_size;
- if (!((flags & WSP_BOT) && p_ls == 0)) {
+ if (!((flags & WSP_BOT) && p_ls == 0) && !is_stl_global) {
new_fr_height -= STATUS_HEIGHT;
+ } else if (is_stl_global) {
+ if (flags & WSP_BOT) {
+ frame_add_hsep(curfrp);
+ } else {
+ new_fr_height -= 1;
+ }
}
frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, false);
} else {
win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
}
+
if (before) { // new window above current one
wp->w_winrow = oldwin->w_winrow;
- wp->w_status_height = STATUS_HEIGHT;
- oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
+
+ if (is_stl_global) {
+ wp->w_status_height = 0;
+ oldwin->w_winrow += wp->w_height + 1;
+ } else {
+ wp->w_status_height = STATUS_HEIGHT;
+ oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
+ }
} else { // new window below current one
- wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
- wp->w_status_height = oldwin->w_status_height;
- if (!(flags & WSP_BOT)) {
- oldwin->w_status_height = STATUS_HEIGHT;
+ if (is_stl_global) {
+ wp->w_winrow = oldwin->w_winrow + oldwin->w_height + 1;
+ wp->w_status_height = 0;
+ } else {
+ wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
+ wp->w_status_height = oldwin->w_status_height;
+ if (!(flags & WSP_BOT)) {
+ oldwin->w_status_height = STATUS_HEIGHT;
+ }
}
}
- if (flags & WSP_BOT) {
+ if ((flags & WSP_BOT) && !is_stl_global) {
frame_add_statusline(curfrp);
}
frame_fix_height(wp);
@@ -1382,10 +1483,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
* equalize the window sizes.
*/
if (do_equal || dir != 0) {
- win_equal(wp, true,
- (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
- : dir == 'h' ? 'b' :
- 'v');
+ win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
}
// Don't change the window height/width to 'winheight' / 'winwidth' if a
@@ -1414,17 +1512,14 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
p_wh = i;
}
- if (!win_valid(oldwin)) {
- return FAIL;
+ if (win_valid(oldwin)) {
+ // Send the window positions to the UI
+ oldwin->w_pos_changed = true;
}
- // Send the window positions to the UI
- oldwin->w_pos_changed = true;
-
return OK;
}
-
/*
* Initialize window "newp" from window "oldp".
* Used when splitting a window and when creating a new tab page.
@@ -1461,9 +1556,9 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
copy_loclist_stack(oldp, newp);
}
newp->w_localdir = (oldp->w_localdir == NULL)
- ? NULL : vim_strsave(oldp->w_localdir);
+ ? NULL : xstrdup(oldp->w_localdir);
newp->w_prevdir = (oldp->w_prevdir == NULL)
- ? NULL : vim_strsave(oldp->w_prevdir);
+ ? NULL : xstrdup(oldp->w_prevdir);
// copy tagstack and folds
for (i = 0; i < oldp->w_tagstacklen; i++) {
@@ -1482,7 +1577,7 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
win_init_some(newp, oldp);
- didset_window_options(newp);
+ newp->w_winbar_height = oldp->w_winbar_height;
}
/*
@@ -1579,10 +1674,10 @@ int win_count(void)
}
/// Make "count" windows on the screen.
-/// Must be called when there is just one window, filling the whole screen
+/// Must be called when there is just one window, filling the whole screen.
/// (excluding the command line).
///
-/// @param vertical split windows vertically if true
+/// @param vertical split windows vertically if true.
///
/// @return actual number of windows on the screen.
int make_windows(int count, bool vertical)
@@ -1591,15 +1686,15 @@ int make_windows(int count, bool vertical)
int todo;
if (vertical) {
- // Each window needs at least 'winminwidth' lines and a separator
- // column.
+ // Each window needs at least 'winminwidth' lines and a separator column.
maxcount = (curwin->w_width + curwin->w_vsep_width
- (p_wiw - p_wmw)) / (p_wmw + 1);
} else {
- // Each window needs at least 'winminheight' lines and a status line.
- maxcount = (curwin->w_height
- + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
+ // Each window needs at least 'winminheight' lines.
+ // If statusline isn't global, each window also needs a statusline.
+ // If 'winbar' is set, each window also needs a winbar.
+ maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
+ - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT + global_winbar_height());
}
if (maxcount < 2) {
@@ -1609,17 +1704,13 @@ int make_windows(int count, bool vertical)
count = maxcount;
}
- /*
- * add status line now, otherwise first window will be too big
- */
+ // add status line now, otherwise first window will be too big
if (count > 1) {
last_status(true);
}
- /*
- * Don't execute autocommands while creating the windows. Must do that
- * when putting the buffers in the windows.
- */
+ // Don't execute autocommands while creating the windows. Must do that
+ // when putting the buffers in the windows.
block_autocmds();
// todo is number of windows left to create
@@ -1666,7 +1757,6 @@ static void win_exchange(long Prenum)
return;
}
-
/*
* find window to exchange with
*/
@@ -1694,7 +1784,7 @@ static void win_exchange(long Prenum)
* if wp != wp2
* 3. remove wp from the list
* 4. insert wp after wp2
- * 5. exchange the status line height and vsep width.
+ * 5. exchange the status line height, winbar height, hsep height and vsep width.
*/
wp2 = curwin->w_prev;
frp2 = curwin->w_frame->fr_prev;
@@ -1720,6 +1810,9 @@ static void win_exchange(long Prenum)
temp = curwin->w_vsep_width;
curwin->w_vsep_width = wp->w_vsep_width;
wp->w_vsep_width = temp;
+ temp = curwin->w_hsep_height;
+ curwin->w_hsep_height = wp->w_hsep_height;
+ wp->w_hsep_height = temp;
frame_fix_height(curwin);
frame_fix_height(wp);
@@ -1728,6 +1821,12 @@ static void win_exchange(long Prenum)
(void)win_comp_pos(); // recompute window positions
+ if (wp->w_buffer != curbuf) {
+ reset_VIsual_and_resel();
+ } else if (VIsual_active) {
+ wp->w_cursor = curwin->w_cursor;
+ }
+
win_enter(wp, true);
redraw_later(curwin, NOT_VALID);
redraw_later(wp, NOT_VALID);
@@ -1772,8 +1871,7 @@ static void win_rotate(bool upwards, int count)
assert(frp->fr_parent->fr_child);
// find last frame and append removed window/frame after it
- for (; frp->fr_next != NULL; frp = frp->fr_next) {
- }
+ for (; frp->fr_next != NULL; frp = frp->fr_next) {}
win_append(frp->fr_win, wp1);
frame_append(frp, wp1->w_frame);
@@ -1781,8 +1879,7 @@ static void win_rotate(bool upwards, int count)
} else { // last window becomes first window
// find last window/frame in the list and remove it
for (frp = curwin->w_frame; frp->fr_next != NULL;
- frp = frp->fr_next) {
- }
+ frp = frp->fr_next) {}
wp1 = frp->fr_win;
wp2 = wp1->w_prev; // will become last window
win_remove(wp1, NULL);
@@ -1794,10 +1891,13 @@ static void win_rotate(bool upwards, int count)
frame_insert(frp->fr_parent->fr_child, frp);
}
- // exchange status height and vsep width of old and new last window
+ // exchange status height, winbar height, hsep height and vsep width of old and new last window
n = wp2->w_status_height;
wp2->w_status_height = wp1->w_status_height;
wp1->w_status_height = n;
+ n = wp2->w_hsep_height;
+ wp2->w_hsep_height = wp1->w_hsep_height;
+ wp1->w_hsep_height = n;
frame_fix_height(wp1);
frame_fix_height(wp2);
n = wp2->w_vsep_width;
@@ -1828,6 +1928,12 @@ static void win_totop(int size, int flags)
beep_flush();
return;
}
+ if (curwin == aucmd_win) {
+ return;
+ }
+ if (check_split_disallowed() == FAIL) {
+ return;
+ }
if (curwin->w_floating) {
ui_comp_remove_grid(&curwin->w_grid_alloc);
@@ -1836,7 +1942,7 @@ static void win_totop(int size, int flags)
} else {
// No longer a float, a non-multigrid UI shouldn't draw it as such
ui_call_win_hide(curwin->w_grid_alloc.handle);
- win_free_grid(curwin, false);
+ win_free_grid(curwin, true);
}
} else {
// Remove the window and frame from the tree of frames.
@@ -1871,11 +1977,22 @@ void win_move_after(win_T *win1, win_T *win2)
// check if there is something to do
if (win2->w_next != win1) {
- // may need move the status line/vertical separator of the last window
+ if (win1->w_frame->fr_parent != win2->w_frame->fr_parent) {
+ iemsg("INTERNAL: trying to move a window into another frame");
+ return;
+ }
+
+ // may need to move the status line, window bar, horizontal or vertical separator of the last
+ // window
if (win1 == lastwin) {
height = win1->w_prev->w_status_height;
win1->w_prev->w_status_height = win1->w_status_height;
win1->w_status_height = height;
+
+ height = win1->w_prev->w_hsep_height;
+ win1->w_prev->w_hsep_height = win1->w_hsep_height;
+ win1->w_hsep_height = height;
+
if (win1->w_prev->w_vsep_width == 1) {
// Remove the vertical separator from the last-but-one window,
// add it to the last window. Adjust the frame widths.
@@ -1888,6 +2005,11 @@ void win_move_after(win_T *win1, win_T *win2)
height = win1->w_status_height;
win1->w_status_height = win2->w_status_height;
win2->w_status_height = height;
+
+ height = win1->w_hsep_height;
+ win1->w_hsep_height = win2->w_hsep_height;
+ win2->w_hsep_height = height;
+
if (win1->w_vsep_width == 1) {
// Remove the vertical separator from win1, add it to the last
// window, win2. Adjust the frame widths.
@@ -1911,6 +2033,37 @@ void win_move_after(win_T *win1, win_T *win2)
win2->w_pos_changed = true;
}
+/// Compute maximum number of windows that can fit within "height" in frame "fr".
+static int get_maximum_wincount(frame_T *fr, int height)
+{
+ if (fr->fr_layout != FR_COL) {
+ return (height / (p_wmh + STATUS_HEIGHT + frame2win(fr)->w_winbar_height));
+ } else if (global_winbar_height()) {
+ // If winbar is globally enabled, no need to check each window for it.
+ return (height / (p_wmh + STATUS_HEIGHT + 1));
+ }
+
+ frame_T *frp;
+ int total_wincount = 0;
+
+ // First, try to fit all child frames of "fr" into "height"
+ FOR_ALL_FRAMES(frp, fr->fr_child) {
+ win_T *wp = frame2win(frp);
+
+ if (height < (p_wmh + STATUS_HEIGHT + wp->w_winbar_height)) {
+ break;
+ }
+ height -= p_wmh + STATUS_HEIGHT + wp->w_winbar_height;
+ total_wincount += 1;
+ }
+
+ // If we still have enough room for more windows, just use the default winbar height (which is 0)
+ // in order to get the amount of windows that'd fit in the remaining space
+ total_wincount += height / (p_wmh + STATUS_HEIGHT);
+
+ return total_wincount;
+}
+
/// Make all windows the same height.
///'next_curwin' will soon be the current window, make sure it has enough rows.
///
@@ -2102,13 +2255,15 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
if (dir != 'h') { // equalize frame heights
// Compute maximum number of windows vertically in this frame.
n = frame_minheight(topfr, NOWIN);
- // add one for the bottom window if it doesn't have a statusline
+ // add one for the bottom window if it doesn't have a statusline or separator
if (row + height == cmdline_row && p_ls == 0) {
+ extra_sep = STATUS_HEIGHT;
+ } else if (global_stl_height() > 0) {
extra_sep = 1;
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmh + 1);
+ totwincount = get_maximum_wincount(topfr, n + extra_sep);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2142,8 +2297,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
}
} else {
// These windows don't use up room.
- totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmh + 1);
+ totwincount -= get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
}
room -= new_size - n;
if (room < 0) {
@@ -2188,8 +2342,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
- wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmh + 1);
+ wincount = get_maximum_wincount(fr, (n + (fr->fr_next == NULL ? extra_sep : 0)));
m = frame_minheight(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -2247,7 +2400,7 @@ static void leaving_window(win_T *const win)
// When leaving the window (or closing the window) was done from a
// callback we need to break out of the Insert mode loop and restart Insert
// mode when entering the window again.
- if (State & INSERT) {
+ if (State & MODE_INSERT) {
stop_insert_mode = true;
if (win->w_buffer->b_prompt_insert == NUL) {
win->w_buffer->b_prompt_insert = 'A';
@@ -2271,33 +2424,59 @@ void entering_window(win_T *const win)
// When entering the prompt window restart Insert mode if we were in Insert
// mode when we left it and not already in Insert mode.
- if ((State & INSERT) == 0) {
+ if ((State & MODE_INSERT) == 0) {
restart_edit = win->w_buffer->b_prompt_insert;
}
}
-/// Closes all windows for buffer `buf`.
+void win_init_empty(win_T *wp)
+{
+ redraw_later(wp, NOT_VALID);
+ wp->w_lines_valid = 0;
+ wp->w_cursor.lnum = 1;
+ wp->w_curswant = wp->w_cursor.col = 0;
+ wp->w_cursor.coladd = 0;
+ wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
+ wp->w_pcmark.col = 0;
+ wp->w_prev_pcmark.lnum = 0;
+ wp->w_prev_pcmark.col = 0;
+ wp->w_topline = 1;
+ wp->w_topfill = 0;
+ wp->w_botline = 2;
+ wp->w_s = &wp->w_buffer->b_s;
+}
+
+/// Init the current window "curwin".
+/// Called when a new file is being edited.
+void curwin_init(void)
+{
+ win_init_empty(curwin);
+}
+
+/// Closes all windows for buffer `buf` unless there is only one non-floating window.
///
-/// @param keep_curwin don't close `curwin`
-void close_windows(buf_T *buf, int keep_curwin)
+/// @param keep_curwin don't close `curwin`
+void close_windows(buf_T *buf, bool keep_curwin)
{
tabpage_T *tp, *nexttp;
int h = tabline_height();
++RedrawingDisabled;
- for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW;) {
+ // Start from lastwin to close floating windows with the same buffer first.
+ // When the autocommand window is involved win_close() may need to print an error message.
+ for (win_T *wp = lastwin; wp != NULL && (lastwin == aucmd_win || !one_window(wp));) {
if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
&& !(wp->w_closing || wp->w_buffer->b_locked > 0)) {
- if (win_close(wp, false) == FAIL) {
+ if (win_close(wp, false, false) == FAIL) {
// If closing the window fails give up, to avoid looping forever.
break;
}
// Start all over, autocommands may change the window layout.
- wp = firstwin;
+ wp = lastwin;
} else {
- wp = wp->w_next;
+ wp = wp->w_prev;
}
}
@@ -2323,27 +2502,28 @@ void close_windows(buf_T *buf, int keep_curwin)
redraw_tabline = true;
if (h != tabline_height()) {
- shell_new_rows();
+ win_new_screen_rows();
}
}
-/// Check that current window is the last one.
+/// Check that the specified window is the last one.
+/// @param win counted even if floating
///
-/// @return true if the current window is the only window that exists, false if
-/// there is another, possibly in another tab page.
-static bool last_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+/// @return true if the specified window is the only window that exists,
+/// false if there is another, possibly in another tab page.
+bool last_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return one_window() && first_tabpage->tp_next == NULL;
+ return one_window(win) && first_tabpage->tp_next == NULL;
}
-/// Check that current tab page contains no more then one window other than
-/// "aucmd_win". Only counts floating window if it is current.
-bool one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+/// Check that current tab page contains no more then one window other than `aucmd_win`.
+/// @param counted_float counted even if floating, but not if it is `aucmd_win`
+bool one_window(win_T *counted_float) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
bool seen_one = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp != aucmd_win && (!wp->w_floating || wp == curwin)) {
+ if (wp != aucmd_win && (!wp->w_floating || wp == counted_float)) {
if (seen_one) {
return false;
}
@@ -2367,6 +2547,24 @@ bool last_nonfloat(win_T *wp) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return wp != NULL && firstwin == wp && !(wp->w_next && !wp->w_floating);
}
+/// Check if floating windows in the current tab can be closed.
+/// Do not call this when the autocommand window is in use!
+///
+/// @return true if all floating windows can be closed
+static bool can_close_floating_windows(void)
+{
+ assert(lastwin != aucmd_win);
+ for (win_T *wp = lastwin; wp->w_floating; wp = wp->w_prev) {
+ buf_T *buf = wp->w_buffer;
+ int need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1);
+
+ if (need_hide && !buf_hide(buf)) {
+ return false;
+ }
+ }
+ return true;
+}
+
/// Close the possibly last window in a tab page.
///
/// @param win window to close
@@ -2411,7 +2609,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
win_close_othertab(win, free_buf, prev_curtab);
if (h != tabline_height()) {
- shell_new_rows();
+ win_new_screen_rows();
}
}
entering_window(curwin);
@@ -2426,12 +2624,47 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
return true;
}
+/// Close the buffer of "win" and unload it if "free_buf" is true.
+/// "abort_if_last" is passed to close_buffer(): abort closing if all other
+/// windows are closed.
+static void win_close_buffer(win_T *win, bool free_buf, bool abort_if_last)
+{
+ // Free independent synblock before the buffer is freed.
+ if (win->w_buffer != NULL) {
+ reset_synblock(win);
+ }
+
+ // When a quickfix/location list window is closed and the buffer is
+ // displayed in only one window, then unlist the buffer.
+ if (win->w_buffer != NULL && bt_quickfix(win->w_buffer)
+ && win->w_buffer->b_nwindows == 1) {
+ win->w_buffer->b_p_bl = false;
+ }
+
+ // Close the link to the buffer.
+ if (win->w_buffer != NULL) {
+ bufref_T bufref;
+ set_bufref(&bufref, curbuf);
+ win->w_closing = true;
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, abort_if_last, true);
+ if (win_valid_any_tab(win)) {
+ win->w_closing = false;
+ }
+
+ // Make sure curbuf is valid. It can become invalid if 'bufhidden' is
+ // "wipe".
+ if (!bufref_valid(&bufref)) {
+ curbuf = firstbuf;
+ }
+ }
+}
+
// Close window "win". Only works for the current tab page.
// If "free_buf" is true related buffer may be unloaded.
//
// Called by :quit, :close, :xit, :wq and findtag().
// Returns FAIL when the window was not closed.
-int win_close(win_T *win, bool free_buf)
+int win_close(win_T *win, bool free_buf, bool force)
{
win_T *wp;
bool other_buffer = false;
@@ -2442,7 +2675,7 @@ int win_close(win_T *win, bool free_buf)
frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent;
const bool had_diffmode = win->w_p_diff;
- if (last_window() && !win->w_floating) {
+ if (last_window(win)) {
emsg(_("E444: Cannot close last window"));
return FAIL;
}
@@ -2455,15 +2688,24 @@ int win_close(win_T *win, bool free_buf)
emsg(_(e_autocmd_close));
return FAIL;
}
- if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window()) {
- emsg(_("E814: Cannot close window, only autocmd window would remain"));
- return FAIL;
- }
- if ((firstwin == win && lastwin_nofloating() == win)
- && lastwin->w_floating) {
- // TODO(bfredl): we might close the float also instead
- emsg(e_floatonly);
- return FAIL;
+ if (lastwin->w_floating && one_window(win)) {
+ if (lastwin == aucmd_win) {
+ emsg(_("E814: Cannot close window, only autocmd window would remain"));
+ return FAIL;
+ }
+ if (force || can_close_floating_windows()) {
+ // close the last window until the there are no floating windows
+ while (lastwin->w_floating) {
+ // `force` flag isn't actually used when closing a floating window.
+ if (win_close(lastwin, free_buf, true) == FAIL) {
+ // If closing the window fails give up, to avoid looping forever.
+ return FAIL;
+ }
+ }
+ } else {
+ emsg(e_floatonly);
+ return FAIL;
+ }
}
// When closing the last window in a tab page first go to another tab page
@@ -2501,6 +2743,8 @@ int win_close(win_T *win, bool free_buf)
* to be the last one left, return now.
*/
if (wp->w_buffer != curbuf) {
+ reset_VIsual_and_resel(); // stop Visual mode
+
other_buffer = true;
win->w_closing = true;
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
@@ -2508,7 +2752,7 @@ int win_close(win_T *win, bool free_buf)
return FAIL;
}
win->w_closing = false;
- if (last_window()) {
+ if (last_window(win)) {
return FAIL;
}
}
@@ -2518,7 +2762,7 @@ int win_close(win_T *win, bool free_buf)
return FAIL;
}
win->w_closing = false;
- if (last_window()) {
+ if (last_window(win)) {
return FAIL;
}
// autocmds may abort script processing
@@ -2555,32 +2799,10 @@ int win_close(win_T *win, bool free_buf)
return OK;
}
- // Free independent synblock before the buffer is freed.
- if (win->w_buffer != NULL) {
- reset_synblock(win);
- }
-
- /*
- * Close the link to the buffer.
- */
- if (win->w_buffer != NULL) {
- bufref_T bufref;
- set_bufref(&bufref, curbuf);
- win->w_closing = true;
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, true);
- if (win_valid_any_tab(win)) {
- win->w_closing = false;
- }
-
- // Make sure curbuf is valid. It can become invalid if 'bufhidden' is
- // "wipe".
- if (!bufref_valid(&bufref)) {
- curbuf = firstbuf;
- }
- }
+ win_close_buffer(win, free_buf, true);
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
- && (last_window() || curtab != prev_curtab
+ && (last_window(win) || curtab != prev_curtab
|| close_last_window_tabpage(win, free_buf, prev_curtab))
&& !win->w_floating) {
// Autocommands have closed all windows, quit now. Restore
@@ -2600,11 +2822,15 @@ int win_close(win_T *win, bool free_buf)
// Autocommands may have closed the window already, or closed the only
// other window or moved to another tab page.
- if (!win_valid(win) || (!win->w_floating && last_window())
+ if (!win_valid(win) || (!win->w_floating && last_window(win))
|| close_last_window_tabpage(win, free_buf, prev_curtab)) {
return FAIL;
}
+ // Now we are really going to close the window. Disallow any autocommand
+ // to split a window to avoid trouble.
+ split_disallowed++;
+
// let terminal buffers know that this window dimensions may be ignored
win->w_closing = true;
@@ -2613,10 +2839,11 @@ int win_close(win_T *win, bool free_buf)
wp = win_free_mem(win, &dir, NULL);
if (help_window) {
- // Closing the help window moves the cursor back to the original window.
- win_T *tmpwp = get_snapshot_focus(SNAP_HELP_IDX);
- if (tmpwp != NULL) {
- wp = tmpwp;
+ // Closing the help window moves the cursor back to the current window
+ // of the snapshot.
+ win_T *prev_win = get_snapshot_curwin(SNAP_HELP_IDX);
+ if (win_valid(prev_win)) {
+ wp = prev_win;
}
}
@@ -2672,6 +2899,8 @@ int win_close(win_T *win, bool free_buf)
}
}
+ split_disallowed--;
+
/*
* If last window has a status line now and we don't want one,
* remove the status line.
@@ -2713,8 +2942,8 @@ static void do_autocmd_winclosed(win_T *win)
return;
}
recursive = true;
- char_u winid[NUMBUFLEN];
- vim_snprintf((char *)winid, sizeof(winid), "%i", win->handle);
+ char winid[NUMBUFLEN];
+ vim_snprintf(winid, sizeof(winid), "%d", win->handle);
apply_autocmds(EVENT_WINCLOSED, winid, winid, false, win->w_buffer);
recursive = false;
}
@@ -2748,14 +2977,20 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
if (win->w_buffer != NULL) {
// Close the link to the buffer.
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false);
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false, true);
}
// Careful: Autocommands may have closed the tab page or made it the
// current tab page.
- for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next) {
- }
+ for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next) {}
if (ptp == NULL || tp == curtab) {
+ // If the buffer was removed from the window we have to give it any
+ // buffer.
+ if (win_valid_any_tab(win) && win->w_buffer == NULL) {
+ win->w_buffer = firstbuf;
+ firstbuf->b_nwindows++;
+ win_init_empty(win);
+ }
return;
}
@@ -2775,9 +3010,9 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
// When closing the last window in a tab page remove the tab page.
if (tp->tp_firstwin == tp->tp_lastwin) {
- char_u prev_idx[NUMBUFLEN];
+ char prev_idx[NUMBUFLEN];
if (has_event(EVENT_TABCLOSED)) {
- vim_snprintf((char *)prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
+ vim_snprintf(prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
}
if (tp == first_tabpage) {
@@ -2857,6 +3092,9 @@ void win_free_all(void)
{
int dummy;
+ // avoid an error for switching tabpage with the cmdline window open
+ cmdwin_type = 0;
+
while (first_tabpage->tp_next != NULL) {
tabpage_close(TRUE);
}
@@ -3060,9 +3298,21 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp)
return frp->fr_prev;
}
+ // By default the next window will get the space that was abandoned by this
+ // window
frame_T *target_fr = frp->fr_next;
frame_T *other_fr = frp->fr_prev;
- if (p_spr || p_sb) {
+
+ // If this is part of a column of windows and 'splitbelow' is true then the
+ // previous window will get the space.
+ if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_COL && p_sb) {
+ target_fr = frp->fr_prev;
+ other_fr = frp->fr_next;
+ }
+
+ // If this is part of a row of windows, and 'splitright' is true then the
+ // previous window will get the space.
+ if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW && p_spr) {
target_fr = frp->fr_prev;
other_fr = frp->fr_next;
}
@@ -3095,15 +3345,14 @@ static tabpage_T *alt_tabpage(void)
}
// Find the last but one tab page.
- for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {
- }
+ for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {}
return tp;
}
/*
* Find the left-upper window in frame "frp".
*/
-static win_T *frame2win(frame_T *frp)
+win_T *frame2win(frame_T *frp)
{
while (frp->fr_win == NULL) {
frp = frp->fr_child;
@@ -3130,23 +3379,40 @@ static bool frame_has_win(const frame_T *frp, const win_T *wp)
return false;
}
+/// Check if current window is at the bottom
+/// Returns true if there are no windows below current window
+static bool is_bottom_win(win_T *wp)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ frame_T *frp;
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_COL && frp->fr_next != NULL) {
+ return false;
+ }
+ }
+ return true;
+}
/// Set a new height for a frame. Recursively sets the height for contained
/// frames and windows. Caller must take care of positions.
///
/// @param topfirst resize topmost contained frame first.
/// @param wfh obey 'winfixheight' when there is a choice;
/// may cause the height not to be set.
-static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
+void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
FUNC_ATTR_NONNULL_ALL
{
frame_T *frp;
int extra_lines;
int h;
+ win_T *wp;
if (topfrp->fr_win != NULL) {
// Simple case: just one window.
- win_new_height(topfrp->fr_win,
- height - topfrp->fr_win->w_status_height);
+ wp = topfrp->fr_win;
+ if (is_bottom_win(wp)) {
+ wp->w_hsep_height = 0;
+ }
+ win_new_height(wp, height - wp->w_hsep_height - wp->w_status_height);
} else if (topfrp->fr_layout == FR_ROW) {
do {
// All frames in this row get the same new height.
@@ -3202,13 +3468,11 @@ static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wf
if (topfirst) {
do {
frp = frp->fr_next;
- }
- while (wfh && frp != NULL && frame_fixed_height(frp));
+ } while (wfh && frp != NULL && frame_fixed_height(frp));
} else {
do {
frp = frp->fr_prev;
- }
- while (wfh && frp != NULL && frame_fixed_height(frp));
+ } while (wfh && frp != NULL && frame_fixed_height(frp));
}
// Increase "height" if we could not reduce enough frames.
if (frp == NULL) {
@@ -3302,8 +3566,8 @@ static void frame_add_statusline(frame_T *frp)
if (frp->fr_layout == FR_LEAF) {
wp = frp->fr_win;
if (wp->w_status_height == 0) {
- if (wp->w_height > 0) { // don't make it negative
- --wp->w_height;
+ if (wp->w_height - STATUS_HEIGHT >= 0) { // don't make it negative
+ wp->w_height -= STATUS_HEIGHT;
}
wp->w_status_height = STATUS_HEIGHT;
}
@@ -3315,8 +3579,7 @@ static void frame_add_statusline(frame_T *frp)
} else {
assert(frp->fr_layout == FR_COL);
// Only need to handle the last frame in the column.
- for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) {
- }
+ for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) {}
frame_add_statusline(frp);
}
}
@@ -3402,13 +3665,11 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw
if (leftfirst) {
do {
frp = frp->fr_next;
- }
- while (wfw && frp != NULL && frame_fixed_width(frp));
+ } while (wfw && frp != NULL && frame_fixed_width(frp));
} else {
do {
frp = frp->fr_prev;
- }
- while (wfw && frp != NULL && frame_fixed_width(frp));
+ } while (wfw && frp != NULL && frame_fixed_width(frp));
}
// Increase "width" if we could not reduce enough frames.
if (frp == NULL) {
@@ -3423,10 +3684,8 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw
topfrp->fr_width = width;
}
-/*
- * Add the vertical separator to windows at the right side of "frp".
- * Note: Does not check if there is room!
- */
+/// Add the vertical separator to windows at the right side of "frp".
+/// Note: Does not check if there is room!
static void frame_add_vsep(const frame_T *frp)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -3456,6 +3715,37 @@ static void frame_add_vsep(const frame_T *frp)
}
}
+/// Add the horizontal separator to windows at the bottom of "frp".
+/// Note: Does not check if there is room or whether the windows have a statusline!
+static void frame_add_hsep(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ win_T *wp;
+
+ if (frp->fr_layout == FR_LEAF) {
+ wp = frp->fr_win;
+ if (wp->w_hsep_height == 0) {
+ if (wp->w_height > 0) { // don't make it negative
+ wp->w_height++;
+ }
+ wp->w_hsep_height = 1;
+ }
+ } else if (frp->fr_layout == FR_ROW) {
+ // Handle all the frames in the row.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
+ frame_add_hsep(frp);
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
+ // Only need to handle the last frame in the column.
+ frp = frp->fr_child;
+ while (frp->fr_next != NULL) {
+ frp = frp->fr_next;
+ }
+ frame_add_hsep(frp);
+ }
+}
+
/*
* Set frame width from the window it contains.
*/
@@ -3470,16 +3760,12 @@ static void frame_fix_width(win_T *wp)
static void frame_fix_height(win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
- wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
+ wp->w_frame->fr_height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
}
-/*
- * Compute the minimal height for frame "topfrp".
- * Uses the 'winminheight' option.
- * When "next_curwin" isn't NULL, use p_wh for this window.
- * When "next_curwin" is NOWIN, don't use at least one line for the current
- * window.
- */
+/// Compute the minimal height for frame "topfrp". Uses the 'winminheight' option.
+/// When "next_curwin" isn't NULL, use p_wh for this window.
+/// When "next_curwin" is NOWIN, don't use at least one line for the current window.
static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
{
frame_T *frp;
@@ -3487,11 +3773,14 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
int n;
if (topfrp->fr_win != NULL) {
+ // Combined height of window bar and separator column or status line.
+ int extra_height = topfrp->fr_win->w_winbar_height + topfrp->fr_win->w_hsep_height
+ + topfrp->fr_win->w_status_height;
+
if (topfrp->fr_win == next_curwin) {
- m = p_wh + topfrp->fr_win->w_status_height;
+ m = p_wh + extra_height;
} else {
- // window: minimal height of the window plus status line
- m = p_wmh + topfrp->fr_win->w_status_height;
+ m = p_wmh + extra_height;
if (topfrp->fr_win == curwin && next_curwin == NULL) {
// Current window is minimal one line high.
if (p_wmh == 0) {
@@ -3561,7 +3850,6 @@ static int frame_minwidth(frame_T *topfrp, win_T *next_curwin)
return m;
}
-
/// Try to close all windows except current one.
/// Buffers in the other windows become hidden if 'hidden' is set, or '!' is
/// used and the buffer was modified.
@@ -3582,7 +3870,7 @@ void close_others(int message, int forceit)
return;
}
- if (one_window() && !lastwin->w_floating) {
+ if (one_nonfloat() && !lastwin->w_floating) {
if (message
&& !autocmd_busy) {
msg(_(m_onlyone));
@@ -3604,7 +3892,7 @@ void close_others(int message, int forceit)
continue;
}
if (!r) {
- if (message && (p_confirm || cmdmod.confirm) && p_write) {
+ if (message && (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) {
dialog_changed(wp->w_buffer, false);
if (!win_valid(wp)) { // autocommands messed wp up
nextwp = firstwin;
@@ -3615,7 +3903,9 @@ void close_others(int message, int forceit)
continue;
}
}
- win_close(wp, !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
+ win_close(wp,
+ !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer),
+ false);
}
if (message && !ONE_WINDOW) {
@@ -3623,33 +3913,6 @@ void close_others(int message, int forceit)
}
}
-
-/*
- * Init the current window "curwin".
- * Called when a new file is being edited.
- */
-void curwin_init(void)
-{
- win_init_empty(curwin);
-}
-
-void win_init_empty(win_T *wp)
-{
- redraw_later(wp, NOT_VALID);
- wp->w_lines_valid = 0;
- wp->w_cursor.lnum = 1;
- wp->w_curswant = wp->w_cursor.col = 0;
- wp->w_cursor.coladd = 0;
- wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
- wp->w_pcmark.col = 0;
- wp->w_prev_pcmark.lnum = 0;
- wp->w_prev_pcmark.col = 0;
- wp->w_topline = 1;
- wp->w_topfill = 0;
- wp->w_botline = 2;
- wp->w_s = &wp->w_buffer->b_s;
-}
-
/*
* Allocate the first window and put an empty buffer in it.
* Called from main().
@@ -3681,7 +3944,7 @@ void win_alloc_aucmd_win(void)
fconfig.width = Columns;
fconfig.height = 5;
fconfig.focusable = false;
- aucmd_win = win_new_float(NULL, fconfig, &err);
+ aucmd_win = win_new_float(NULL, true, fconfig, &err);
aucmd_win->w_buffer->b_nwindows--;
RESET_BINDING(aucmd_win);
}
@@ -3718,7 +3981,7 @@ static int win_alloc_firstwin(win_T *oldwin)
new_frame(curwin);
topframe = curwin->w_frame;
topframe->fr_width = Columns;
- topframe->fr_height = Rows - p_ch;
+ topframe->fr_height = Rows - p_ch - global_stl_height();
return OK;
}
@@ -3741,8 +4004,9 @@ static void new_frame(win_T *wp)
void win_init_size(void)
{
firstwin->w_height = ROWS_AVAIL;
- firstwin->w_height_inner = firstwin->w_height;
+ firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
firstwin->w_height_outer = firstwin->w_height;
+ firstwin->w_winrow_off = firstwin->w_winbar_height;
topframe->fr_height = ROWS_AVAIL;
firstwin->w_width = Columns;
firstwin->w_width_inner = firstwin->w_width;
@@ -3805,6 +4069,11 @@ int win_new_tabpage(int after, char_u *filename)
tabpage_T *newtp;
int n;
+ if (cmdwin_type != 0) {
+ emsg(_(e_cmdwin));
+ return FAIL;
+ }
+
newtp = alloc_tabpage();
// Remember the current windows in this Tab page.
@@ -3814,7 +4083,7 @@ int win_new_tabpage(int after, char_u *filename)
}
newtp->tp_localdir = old_curtab->tp_localdir
- ? vim_strsave(old_curtab->tp_localdir) : NULL;
+ ? xstrdup(old_curtab->tp_localdir) : NULL;
curtab = newtp;
@@ -3847,6 +4116,7 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_topframe = topframe;
last_status(false);
+ set_winbar();
redraw_all_later(NOT_VALID);
@@ -3858,7 +4128,7 @@ int win_new_tabpage(int after, char_u *filename)
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
- apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
+ apply_autocmds(EVENT_TABNEW, (char *)filename, (char *)filename, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
return OK;
@@ -3876,10 +4146,10 @@ int win_new_tabpage(int after, char_u *filename)
*/
int may_open_tabpage(void)
{
- int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
+ int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab;
if (n != 0) {
- cmdmod.tab = 0; // reset it to avoid doing it twice
+ cmdmod.cmod_tab = 0; // reset it to avoid doing it twice
postponed_split_tab = 0;
return win_new_tabpage(n, NULL);
}
@@ -4050,8 +4320,8 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a
{
int old_off = tp->tp_firstwin->w_winrow;
win_T *next_prevwin = tp->tp_prevwin;
-
tabpage_T *old_curtab = curtab;
+
curtab = tp;
firstwin = tp->tp_firstwin;
lastwin = tp->tp_lastwin;
@@ -4090,10 +4360,10 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a
}
if (curtab->tp_old_Rows != Rows || (old_off != firstwin->w_winrow)) {
- shell_new_rows();
+ win_new_screen_rows();
}
if (curtab->tp_old_Columns != Columns && starting == 0) {
- shell_new_columns(); // update window widths
+ win_new_screen_cols(); // update window widths
}
lastused_tabpage = old_curtab;
@@ -4176,14 +4446,12 @@ void goto_tabpage(int n)
ttp = curtab;
for (i = n; i < 0; ++i) {
for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
- tp = tp->tp_next) {
- }
+ tp = tp->tp_next) {}
ttp = tp;
}
} else if (n == 9999) {
// Go to last tab page.
- for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next) {
- }
+ for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next) {}
} else {
// Go to tab page "n".
tp = find_tabpage(n);
@@ -4203,6 +4471,10 @@ void goto_tabpage(int n)
/// @param trigger_leave_autocmds when true trigger *Leave autocommands.
void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_leave_autocmds)
{
+ if (trigger_enter_autocmds || trigger_leave_autocmds) {
+ CHECK_CMDWIN;
+ }
+
// Don't repeat a message in another tab page.
set_keep_msg(NULL, 0);
@@ -4218,13 +4490,15 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le
}
}
-// Go to the last accessed tab page, if there is one.
-void goto_tabpage_lastused(void)
+/// Go to the last accessed tab page, if there is one.
+/// @return true if the tab page is valid, false otherwise.
+bool goto_tabpage_lastused(void)
{
- int index = tabpage_index(lastused_tabpage);
- if (index < tabpage_index(NULL)) {
- goto_tabpage(index);
+ if (valid_tabpage(lastused_tabpage)) {
+ goto_tabpage_tp(lastused_tabpage, true, true);
+ return true;
}
+ return false;
}
/*
@@ -4293,7 +4567,6 @@ void tabpage_move(int nr)
redraw_tabline = true;
}
-
/*
* Go to another window.
* When jumping to another buffer, stop Visual mode. Do this before
@@ -4305,12 +4578,8 @@ void win_goto(win_T *wp)
{
win_T *owp = curwin;
- if (text_locked()) {
+ if (text_or_buf_locked()) {
beep_flush();
- text_locked_msg();
- return;
- }
- if (curbuf_locked()) {
return;
}
@@ -4331,7 +4600,6 @@ void win_goto(win_T *wp)
}
}
-
/*
* Find the tabpage for window "win".
*/
@@ -4634,8 +4902,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
void fix_current_dir(void)
{
// New directory is either the local directory of the window, tab or NULL.
- char *new_dir = (char *)(curwin->w_localdir
- ? curwin->w_localdir : curtab->tp_localdir);
+ char *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->tp_localdir;
char cwd[MAXPATHL];
if (os_dirname((char_u *)cwd, MAXPATHL) != OK) {
cwd[0] = NUL;
@@ -4646,23 +4913,32 @@ void fix_current_dir(void)
// (unless that was done already) and change to the local directory.
if (globaldir == NULL) {
if (cwd[0] != NUL) {
- globaldir = (char_u *)xstrdup(cwd);
+ globaldir = xstrdup(cwd);
}
}
+ bool dir_differs = pathcmp(new_dir, cwd, -1) != 0;
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
+ kCdCauseWindow, true);
+ }
if (os_chdir(new_dir) == 0) {
- if (!p_acd && pathcmp(new_dir, cwd, -1) != 0) {
- do_autocmd_dirchanged(new_dir, curwin->w_localdir
- ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow);
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir ? kCdScopeWindow : kCdScopeTabpage,
+ kCdCauseWindow, false);
}
- last_chdir_reason = NULL;
- shorten_fnames(true);
}
+ last_chdir_reason = NULL;
+ shorten_fnames(true);
} else if (globaldir != NULL) {
// Window doesn't have a local directory and we are not in the global
// directory: Change to the global directory.
- if (os_chdir((char *)globaldir) == 0) {
- if (!p_acd && pathcmp((char *)globaldir, cwd, -1) != 0) {
- do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
+ bool dir_differs = pathcmp(globaldir, cwd, -1) != 0;
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(globaldir, kCdScopeGlobal, kCdCauseWindow, true);
+ }
+ if (os_chdir(globaldir) == 0) {
+ if (!p_acd && dir_differs) {
+ do_autocmd_dirchanged(globaldir, kCdScopeGlobal, kCdCauseWindow, false);
}
}
XFREE_CLEAR(globaldir);
@@ -4785,7 +5061,6 @@ static win_T *win_alloc(win_T *after, bool hidden)
return new_wp;
}
-
// Free one wininfo_T.
void free_wininfo(wininfo_T *wip, buf_T *bp)
{
@@ -4796,7 +5071,6 @@ void free_wininfo(wininfo_T *wip, buf_T *bp)
xfree(wip);
}
-
/// Remove window 'wp' from the window list and free the structure.
///
/// @param tp tab page "win" is in, NULL for current
@@ -4819,6 +5093,7 @@ static void win_free(win_T *wp, tabpage_T *tp)
clear_winopt(&wp->w_allbuf_opt);
xfree(wp->w_p_lcs_chars.multispace);
+ xfree(wp->w_p_lcs_chars.leadmultispace);
vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables
hash_init(&wp->w_vars->dv_hashtab);
@@ -4843,6 +5118,12 @@ static void win_free(win_T *wp, tabpage_T *tp)
xfree(wp->w_localdir);
xfree(wp->w_prevdir);
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+
// Remove the window from the b_wininfo lists, it may happen that the
// freed memory is re-used for another window.
FOR_ALL_BUFFERS(buf) {
@@ -4904,8 +5185,7 @@ void win_free_grid(win_T *wp, bool reinit)
}
grid_free(&wp->w_grid_alloc);
if (reinit) {
- // if a float is turned into a split and back into a float, the grid
- // data structure will be reused
+ // if a float is turned into a split, the grid data structure will be reused
memset(&wp->w_grid_alloc, 0, sizeof(wp->w_grid_alloc));
}
}
@@ -5001,12 +5281,29 @@ static void frame_remove(frame_T *frp)
}
}
+void win_new_screensize(void)
+{
+ static long old_Rows = 0;
+ static long old_Columns = 0;
-/*
- * Called from win_new_shellsize() after Rows changed.
- * This only does the current tab page, others must be done when made active.
- */
-void shell_new_rows(void)
+ if (old_Rows != Rows) {
+ // If 'window' uses the whole screen, keep it using that.
+ // Don't change it when set with "-w size" on the command line.
+ if (p_window == old_Rows - 1 || (old_Rows == 0 && p_window == 0)) {
+ p_window = Rows - 1;
+ }
+ old_Rows = Rows;
+ win_new_screen_rows(); // update window sizes
+ }
+ if (old_Columns != Columns) {
+ old_Columns = Columns;
+ win_new_screen_cols(); // update window sizes
+ }
+}
+/// Called from win_new_screensize() after Rows changed.
+///
+/// This only does the current tab page, others must be done when made active.
+void win_new_screen_rows(void)
{
int h = (int)ROWS_AVAIL;
@@ -5030,10 +5327,8 @@ void shell_new_rows(void)
curtab->tp_ch_used = p_ch;
}
-/*
- * Called from win_new_shellsize() after Columns changed.
- */
-void shell_new_columns(void)
+/// Called from win_new_screensize() after Columns changed.
+void win_new_screen_cols(void)
{
if (firstwin == NULL) { // not initialized yet
return;
@@ -5050,25 +5345,35 @@ void shell_new_columns(void)
win_reconfig_floats(); // The size of floats might change
}
-/// Check if "wp" has scrolled since last time it was checked
-/// @param wp the window to check
-bool win_did_scroll(win_T *wp)
+/// Trigger WinScrolled for "curwin" if needed.
+void may_trigger_winscrolled(void)
{
- return (curwin->w_last_topline != curwin->w_topline
- || curwin->w_last_leftcol != curwin->w_leftcol
- || curwin->w_last_width != curwin->w_width
- || curwin->w_last_height != curwin->w_height);
-}
+ static bool recursive = false;
-/// Trigger WinScrolled autocmd
-void do_autocmd_winscrolled(win_T *wp)
-{
- apply_autocmds(EVENT_WINSCROLLED, NULL, NULL, false, curbuf);
+ if (recursive || !has_event(EVENT_WINSCROLLED)) {
+ return;
+ }
+
+ win_T *wp = curwin;
+ if (wp->w_last_topline != wp->w_topline
+ || wp->w_last_leftcol != wp->w_leftcol
+ || wp->w_last_width != wp->w_width
+ || wp->w_last_height != wp->w_height) {
+ char winid[NUMBUFLEN];
+ vim_snprintf(winid, sizeof(winid), "%d", wp->handle);
- wp->w_last_topline = wp->w_topline;
- wp->w_last_leftcol = wp->w_leftcol;
- wp->w_last_width = wp->w_width;
- wp->w_last_height = wp->w_height;
+ recursive = true;
+ apply_autocmds(EVENT_WINSCROLLED, winid, winid, false, wp->w_buffer);
+ recursive = false;
+
+ // an autocmd may close the window, "wp" may be invalid now
+ if (win_valid_any_tab(wp)) {
+ wp->w_last_topline = wp->w_topline;
+ wp->w_last_leftcol = wp->w_leftcol;
+ wp->w_last_width = wp->w_width;
+ wp->w_last_height = wp->w_height;
+ }
+ }
}
/*
@@ -5114,11 +5419,8 @@ void win_size_restore(garray_T *gap)
}
}
-/*
- * Update the position for all windows, using the width and height of the
- * frames.
- * Returns the row just after the last window.
- */
+// Update the position for all windows, using the width and height of the frames.
+// Returns the row just after the last window and global statusline (if there is one).
int win_comp_pos(void)
{
int row = tabline_height();
@@ -5133,7 +5435,7 @@ int win_comp_pos(void)
}
}
- return row;
+ return row + global_stl_height();
}
void win_reconfig_floats(void)
@@ -5167,7 +5469,7 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
wp->w_redr_status = true;
wp->w_pos_changed = true;
}
- const int h = wp->w_height + wp->w_status_height;
+ const int h = wp->w_height + wp->w_hsep_height + wp->w_status_height;
*row += h > topfrp->fr_height ? topfrp->fr_height : h;
*col += wp->w_width + wp->w_vsep_width;
} else {
@@ -5184,7 +5486,6 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
}
}
-
/*
* Set current window height and take care of repositioning other windows to
* fit around it.
@@ -5200,23 +5501,16 @@ void win_setheight(int height)
*/
void win_setheight_win(int height, win_T *win)
{
- if (win == curwin) {
- // Always keep current window at least one line high, even when
- // 'winminheight' is zero.
- if (height < p_wmh) {
- height = p_wmh;
- }
- if (height == 0) {
- height = 1;
- }
- }
+ // Always keep current window at least one line high, even when 'winminheight' is zero.
+ // Keep window at least two lines high if 'winbar' is enabled.
+ height = MAX(height, (win == curwin ? MAX(p_wmh, 1) : p_wmh) + win->w_winbar_height);
if (win->w_floating) {
win->w_float_config.height = height;
win_config_float(win, win->w_float_config);
redraw_later(win, NOT_VALID);
} else {
- frame_setheight(win->w_frame, height + win->w_status_height);
+ frame_setheight(win->w_frame, height + win->w_hsep_height + win->w_status_height);
// recompute the window positions
int row = win_comp_pos();
@@ -5225,15 +5519,19 @@ void win_setheight_win(int height, win_T *win)
// line, clear it.
if (full_screen && msg_scrolled == 0 && row < cmdline_row) {
grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0);
+ if (msg_grid.chars) {
+ clear_cmdline = true;
+ }
}
cmdline_row = row;
+ p_ch = MAX(Rows - cmdline_row, 0);
+ curtab->tp_ch_used = p_ch;
msg_row = row;
msg_col = 0;
redraw_all_later(NOT_VALID);
}
}
-
/*
* Set the height of a frame to "height" and take care that all frames and
* windows inside it are resized. Also resize frames on the left and right if
@@ -5265,7 +5563,10 @@ static void frame_setheight(frame_T *curfrp, int height)
if (curfrp->fr_parent == NULL) {
// topframe: can only change the command line
if (height > ROWS_AVAIL) {
- height = ROWS_AVAIL;
+ // If height is greater than the available space, try to create space for
+ // the frame by reducing 'cmdheight' if possible, while making sure
+ // `cmdheight` doesn't go below 1.
+ height = MIN((p_ch > 0 ? ROWS_AVAIL + (p_ch - 1) : ROWS_AVAIL), height);
}
if (height > 0) {
frame_new_height(curfrp, height, false, false);
@@ -5307,8 +5608,8 @@ static void frame_setheight(frame_T *curfrp, int height)
room_cmdline = 0;
} else {
win_T *wp = lastwin_nofloating();
- room_cmdline = Rows - p_ch
- - (wp->w_winrow + wp->w_height + wp->w_status_height);
+ room_cmdline = Rows - p_ch - global_stl_height()
+ - (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height);
if (room_cmdline < 0) {
room_cmdline = 0;
}
@@ -5671,10 +5972,8 @@ void win_drag_status_line(win_T *dragwin, int offset)
up = false;
// Only dragging the last status line can reduce p_ch.
room = Rows - cmdline_row;
- if (curfr->fr_next == NULL) {
- room -= 1;
- } else {
- room -= p_ch;
+ if (curfr->fr_next != NULL) {
+ room -= p_ch + global_stl_height();
}
if (room < 0) {
room = 0;
@@ -5730,10 +6029,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
clear_cmdline = true;
}
cmdline_row = row;
- p_ch = Rows - cmdline_row;
- if (p_ch < 1) {
- p_ch = 1;
- }
+ p_ch = MAX(Rows - cmdline_row, 0);
curtab->tp_ch_used = p_ch;
redraw_all_later(SOME_VALID);
showmode();
@@ -5800,7 +6096,6 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
}
fr = curfr; // put fr at window that grows
}
- assert(fr);
// Not enough room
if (room < offset) {
@@ -5813,7 +6108,9 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
}
if (fr == NULL) {
- return; // Safety check, should not happen.
+ // This can happen when calling win_move_separator() on the rightmost
+ // window. Just don't do anything.
+ return;
}
// grow frame fr by offset lines
@@ -5844,7 +6141,6 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
redraw_all_later(NOT_VALID);
}
-
#define FRACTION_MULT 16384L
// Set wp->w_fraction for the current w_wrow and w_height.
@@ -5996,7 +6292,7 @@ void win_set_inner_size(win_T *wp)
int prev_height = wp->w_height_inner;
int height = wp->w_height_request;
if (height == 0) {
- height = wp->w_height;
+ height = wp->w_height - wp->w_winbar_height;
}
if (height != prev_height) {
@@ -6013,8 +6309,8 @@ void win_set_inner_size(win_T *wp)
set_fraction(wp);
}
}
- wp->w_height_inner = height;
wp->w_skipcol = 0;
+ wp->w_height_inner = height;
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
@@ -6040,10 +6336,20 @@ void win_set_inner_size(win_T *wp)
terminal_check_size(wp->w_buffer->terminal);
}
- wp->w_height_outer = (wp->w_height_inner
- + wp->w_border_adj[0] + wp->w_border_adj[2]);
- wp->w_width_outer = (wp->w_width_inner
- + wp->w_border_adj[1] + wp->w_border_adj[3]);
+ wp->w_height_outer = (wp->w_height_inner + win_border_height(wp) + wp->w_winbar_height);
+ wp->w_width_outer = (wp->w_width_inner + win_border_width(wp));
+ wp->w_winrow_off = wp->w_border_adj[0] + wp->w_winbar_height;
+ wp->w_wincol_off = wp->w_border_adj[3];
+}
+
+static int win_border_height(win_T *wp)
+{
+ return wp->w_border_adj[0] + wp->w_border_adj[2];
+}
+
+static int win_border_width(win_T *wp)
+{
+ return wp->w_border_adj[1] + wp->w_border_adj[3];
}
/// Set the width of a window.
@@ -6179,7 +6485,7 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
*file_lnum = getdigits_long(&p, false, 0);
}
- return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
+ return find_file_name_in_path(ptr, len, options, count, (char_u *)curbuf->b_ffname);
}
return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
}
@@ -6200,7 +6506,7 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum)
{
return file_name_in_line(get_cursor_line_ptr(),
- curwin->w_cursor.col, options, count, curbuf->b_ffname,
+ curwin->w_cursor.col, options, count, (char_u *)curbuf->b_ffname,
file_lnum);
}
@@ -6211,7 +6517,7 @@ char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum)
char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname,
linenr_T *file_lnum)
{
- char_u *ptr;
+ char *ptr;
size_t len;
bool in_type = true;
bool is_url = false;
@@ -6219,7 +6525,7 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
/*
* search forward for what could be the start of a file name
*/
- ptr = line + col;
+ ptr = (char *)line + col;
while (*ptr != NUL && !vim_isfilec(*ptr)) {
MB_PTR_ADV(ptr);
}
@@ -6234,11 +6540,10 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
* Search backward for first char of the file name.
* Go one char back to ":" before "//" even when ':' is not in 'isfname'.
*/
- while (ptr > line) {
- if ((len = (size_t)(utf_head_off(line, ptr - 1))) > 0) {
+ while ((char_u *)ptr > line) {
+ if ((len = (size_t)(utf_head_off(line, (char_u *)ptr - 1))) > 0) {
ptr -= len + 1;
- } else if (vim_isfilec(ptr[-1])
- || ((options & FNAME_HYP) && path_is_url((char *)ptr - 1))) {
+ } else if (vim_isfilec(ptr[-1]) || ((options & FNAME_HYP) && path_is_url(ptr - 1))) {
ptr--;
} else {
break;
@@ -6251,13 +6556,13 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
*/
len = 0;
while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
- || ((options & FNAME_HYP) && path_is_url((char *)ptr + len))
- || (is_url && vim_strchr((char_u *)":?&=", ptr[len]) != NULL)) {
+ || ((options & FNAME_HYP) && path_is_url(ptr + len))
+ || (is_url && vim_strchr(":?&=", ptr[len]) != NULL)) {
// After type:// we also include :, ?, & and = as valid characters, so that
// http://google.com:8080?q=this&that=ok works.
if ((ptr[len] >= 'A' && ptr[len] <= 'Z')
|| (ptr[len] >= 'a' && ptr[len] <= 'z')) {
- if (in_type && path_is_url((char *)ptr + len + 1)) {
+ if (in_type && path_is_url(ptr + len + 1)) {
is_url = true;
}
} else {
@@ -6275,13 +6580,13 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
* If there is trailing punctuation, remove it.
* But don't remove "..", could be a directory name.
*/
- if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
+ if (len > 2 && vim_strchr(".,:;!", ptr[len - 1]) != NULL
&& ptr[len - 2] != '.') {
--len;
}
if (file_lnum != NULL) {
- char_u *p;
+ char *p;
const char *line_english = " line ";
const char *line_transl = _(line_msg);
@@ -6302,80 +6607,177 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
}
p = skipwhite(p);
if (isdigit(*p)) {
- *file_lnum = getdigits_long(&p, false, 0);
+ *file_lnum = getdigits_long((char_u **)&p, false, 0);
}
}
}
- return find_file_name_in_path(ptr, len, options, count, rel_fname);
+ return find_file_name_in_path((char_u *)ptr, len, options, count, rel_fname);
}
-/// Add or remove a status line for the bottom window(s), according to the
+/// Add or remove a status line from window(s), according to the
/// value of 'laststatus'.
///
/// @param morewin pretend there are two or more windows if true.
void last_status(bool morewin)
{
// Don't make a difference between horizontal or vertical split.
- last_status_rec(topframe, (p_ls == 2
- || (p_ls == 1 && (morewin || !one_window()))));
+ last_status_rec(topframe, (p_ls == 2 || (p_ls == 1 && (morewin || !one_nonfloat()))),
+ global_stl_height() > 0);
+}
+
+// Remove status line from window, replacing it with a horizontal separator if needed.
+static void win_remove_status_line(win_T *wp, bool add_hsep)
+{
+ wp->w_status_height = 0;
+ if (add_hsep) {
+ wp->w_hsep_height = 1;
+ } else {
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT);
+ }
+ comp_col();
+
+ stl_clear_click_defs(wp->w_status_click_defs, wp->w_status_click_defs_size);
+ xfree(wp->w_status_click_defs);
+ wp->w_status_click_defs_size = 0;
+ wp->w_status_click_defs = NULL;
+}
+
+// Look for a horizontally resizable frame, starting with frame "fr".
+// Returns NULL if there are no resizable frames.
+static frame_T *find_horizontally_resizable_frame(frame_T *fr)
+{
+ frame_T *fp = fr;
+
+ while (fp->fr_height <= frame_minheight(fp, NULL)) {
+ if (fp == topframe) {
+ return NULL;
+ }
+ // In a column of frames: go to frame above. If already at
+ // the top or in a row of frames: go to parent.
+ if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
+ fp = fp->fr_prev;
+ } else {
+ fp = fp->fr_parent;
+ }
+ }
+
+ return fp;
}
-static void last_status_rec(frame_T *fr, bool statusline)
+// Look for resizable frames and take lines from them to make room for the statusline.
+// @return Success or failure.
+static bool resize_frame_for_status(frame_T *fr)
+{
+ win_T *wp = fr->fr_win;
+ frame_T *fp = find_horizontally_resizable_frame(fr);
+
+ if (fp == NULL) {
+ emsg(_(e_noroom));
+ return false;
+ } else if (fp != fr) {
+ frame_new_height(fp, fp->fr_height - 1, false, false);
+ frame_fix_height(wp);
+ (void)win_comp_pos();
+ } else {
+ win_new_height(wp, wp->w_height - 1);
+ }
+
+ return true;
+}
+
+// Look for resizable frames and take lines from them to make room for the winbar.
+// @return Success or failure.
+static bool resize_frame_for_winbar(frame_T *fr)
+{
+ win_T *wp = fr->fr_win;
+ frame_T *fp = find_horizontally_resizable_frame(fr);
+
+ if (fp == NULL || fp == fr) {
+ emsg(_(e_noroom));
+ return false;
+ } else {
+ frame_new_height(fp, fp->fr_height - 1, false, false);
+ win_new_height(wp, wp->w_height + 1);
+ frame_fix_height(wp);
+ (void)win_comp_pos();
+ }
+
+ return true;
+}
+
+static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
{
frame_T *fp;
win_T *wp;
if (fr->fr_layout == FR_LEAF) {
wp = fr->fr_win;
- if (wp->w_status_height != 0 && !statusline) {
- // remove status line
- win_new_height(wp, wp->w_height + 1);
- wp->w_status_height = 0;
- comp_col();
- } else if (wp->w_status_height == 0 && statusline) {
- // Find a frame to take a line from.
- fp = fr;
- while (fp->fr_height <= frame_minheight(fp, NULL)) {
- if (fp == topframe) {
- emsg(_(e_noroom));
+ bool is_last = is_bottom_win(wp);
+
+ if (is_last) {
+ if (wp->w_status_height != 0 && (!statusline || is_stl_global)) {
+ win_remove_status_line(wp, false);
+ } else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
+ // Add statusline to window if needed
+ wp->w_status_height = STATUS_HEIGHT;
+ if (!resize_frame_for_status(fr)) {
return;
}
- // In a column of frames: go to frame above. If already at
- // the top or in a row of frames: go to parent.
- if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
- fp = fp->fr_prev;
- } else {
- fp = fp->fr_parent;
- }
- }
- wp->w_status_height = 1;
- if (fp != fr) {
- frame_new_height(fp, fp->fr_height - 1, false, false);
- frame_fix_height(wp);
- (void)win_comp_pos();
- } else {
- win_new_height(wp, wp->w_height - 1);
- }
+ comp_col();
+ }
+ } else if (wp->w_status_height != 0 && is_stl_global) {
+ // If statusline is global and the window has a statusline, replace it with a horizontal
+ // separator
+ win_remove_status_line(wp, true);
+ } else if (wp->w_status_height == 0 && !is_stl_global) {
+ // If statusline isn't global and the window doesn't have a statusline, re-add it
+ wp->w_status_height = STATUS_HEIGHT;
+ wp->w_hsep_height = 0;
comp_col();
- redraw_all_later(SOME_VALID);
}
- } else if (fr->fr_layout == FR_ROW) {
- // vertically split windows, set status line for each one
+ redraw_all_later(SOME_VALID);
+ } else {
+ // For a column or row frame, recursively call this function for all child frames
FOR_ALL_FRAMES(fp, fr->fr_child) {
- last_status_rec(fp, statusline);
+ last_status_rec(fp, statusline, is_stl_global);
}
- } else {
- // horizontally split window, set status line for last one
- for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
+ }
+}
+
+// Add or remove window bars from windows depending on the value of 'winbar'.
+void set_winbar(void)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ // Require the local value to be set in order to show winbar on a floating window.
+ int winbar_height = wp->w_floating ? ((*wp->w_p_wbr != NUL) ? 1 : 0)
+ : ((*p_wbr != NUL || *wp->w_p_wbr != NUL) ? 1 : 0);
+
+ if (wp->w_winbar_height != winbar_height) {
+ if (winbar_height == 1 && wp->w_height_inner <= 1) {
+ if (wp->w_floating) {
+ emsg(_(e_noroom));
+ continue;
+ } else if (!resize_frame_for_winbar(wp->w_frame)) {
+ return;
+ }
+ }
+ wp->w_winbar_height = winbar_height;
+ win_set_inner_size(wp);
+ wp->w_redr_status = wp->w_redr_status || winbar_height;
+
+ if (winbar_height == 0) {
+ // When removing winbar, deallocate the w_winbar_click_defs array
+ stl_clear_click_defs(wp->w_winbar_click_defs, wp->w_winbar_click_defs_size);
+ xfree(wp->w_winbar_click_defs);
+ wp->w_winbar_click_defs_size = 0;
+ wp->w_winbar_click_defs = NULL;
+ }
}
- last_status_rec(fp, statusline);
}
}
-/*
- * Return the number of lines used by the tab page line.
- */
+/// Return the number of lines used by the tab page line.
int tabline_height(void)
{
if (ui_has(kUITabline)) {
@@ -6391,10 +6793,20 @@ int tabline_height(void)
return 1;
}
-/*
- * Return the minimal number of rows that is needed on the screen to display
- * the current number of windows.
- */
+/// Return the number of lines used by default by the window bar.
+int global_winbar_height(void)
+{
+ return *p_wbr != NUL ? 1 : 0;
+}
+
+/// Return the number of lines used by the global statusline
+int global_stl_height(void)
+{
+ return (p_ls == 3) ? STATUS_HEIGHT : 0;
+}
+
+/// Return the minimal number of rows that is needed on the screen to display
+/// the current number of windows.
int min_rows(void)
{
if (firstwin == NULL) { // not initialized yet
@@ -6408,7 +6820,7 @@ int min_rows(void)
total = n;
}
}
- total += tabline_height();
+ total += tabline_height() + global_stl_height();
total += 1; // count the room for the command line
return total;
}
@@ -6533,6 +6945,35 @@ static void clear_snapshot_rec(frame_T *fr)
}
}
+/// Traverse a snapshot to find the previous curwin.
+static win_T *get_snapshot_curwin_rec(frame_T *ft)
+{
+ win_T *wp;
+
+ if (ft->fr_next != NULL) {
+ if ((wp = get_snapshot_curwin_rec(ft->fr_next)) != NULL) {
+ return wp;
+ }
+ }
+ if (ft->fr_child != NULL) {
+ if ((wp = get_snapshot_curwin_rec(ft->fr_child)) != NULL) {
+ return wp;
+ }
+ }
+
+ return ft->fr_win;
+}
+
+/// @return the current window stored in the snapshot or NULL.
+static win_T *get_snapshot_curwin(int idx)
+{
+ if (curtab->tp_snapshot[idx] == NULL) {
+ return NULL;
+ }
+
+ return get_snapshot_curwin_rec(curtab->tp_snapshot[idx]);
+}
+
/// Restore a previously created snapshot, if there is any.
/// This is only done if the screen size didn't change and the window layout is
/// still the same.
@@ -6605,28 +7046,6 @@ static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr)
return wp;
}
-/// Gets the focused window (the one holding the cursor) of the snapshot.
-static win_T *get_snapshot_focus(int idx)
-{
- if (curtab->tp_snapshot[idx] == NULL) {
- return NULL;
- }
-
- frame_T *sn = curtab->tp_snapshot[idx];
- // This should be equivalent to the recursive algorithm found in
- // restore_snapshot as far as traveling nodes go.
- while (sn->fr_child != NULL || sn->fr_next != NULL) {
- while (sn->fr_child != NULL) {
- sn = sn->fr_child;
- }
- if (sn->fr_next != NULL) {
- sn = sn->fr_next;
- }
- }
-
- return win_valid(sn->fr_win) ? sn->fr_win : NULL;
-}
-
/// Set "win" to be the curwin and "tp" to be the current tab page.
/// restore_win() MUST be called to undo, also when FAIL is returned.
/// No autocommands will be executed until restore_win() is called.
@@ -6635,20 +7054,27 @@ static win_T *get_snapshot_focus(int idx)
/// triggered, another tabpage access is limited.
///
/// @return FAIL if switching to "win" failed.
-int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp,
- bool no_display)
+int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
{
block_autocmds();
- return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
+ return switch_win_noblock(switchwin, win, tp, no_display);
}
// As switch_win() but without blocking autocommands.
-int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp,
- bool no_display)
+int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display)
{
- *save_curwin = curwin;
+ memset(switchwin, 0, sizeof(switchwin_T));
+ switchwin->sw_curwin = curwin;
+ if (win == curwin) {
+ switchwin->sw_same_win = true;
+ } else {
+ // Disable Visual selection, because redrawing may fail.
+ switchwin->sw_visual_active = VIsual_active;
+ VIsual_active = false;
+ }
+
if (tp != NULL) {
- *save_curtab = curtab;
+ switchwin->sw_curtab = curtab;
if (no_display) {
curtab->tp_firstwin = firstwin;
curtab->tp_lastwin = lastwin;
@@ -6670,33 +7096,35 @@ int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win,
// Restore current tabpage and window saved by switch_win(), if still valid.
// When "no_display" is true the display won't be affected, no redraw is
// triggered.
-void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
+void restore_win(switchwin_T *switchwin, bool no_display)
{
- restore_win_noblock(save_curwin, save_curtab, no_display);
+ restore_win_noblock(switchwin, no_display);
unblock_autocmds();
}
// As restore_win() but without unblocking autocommands.
-void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
+void restore_win_noblock(switchwin_T *switchwin, bool no_display)
{
- if (save_curtab != NULL && valid_tabpage(save_curtab)) {
+ if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) {
if (no_display) {
curtab->tp_firstwin = firstwin;
curtab->tp_lastwin = lastwin;
- curtab = save_curtab;
+ curtab = switchwin->sw_curtab;
firstwin = curtab->tp_firstwin;
lastwin = curtab->tp_lastwin;
} else {
- goto_tabpage_tp(save_curtab, false, false);
+ goto_tabpage_tp(switchwin->sw_curtab, false, false);
}
}
- if (win_valid(save_curwin)) {
- curwin = save_curwin;
+
+ if (!switchwin->sw_same_win) {
+ VIsual_active = switchwin->sw_visual_active;
+ }
+
+ if (win_valid(switchwin->sw_curwin)) {
+ curwin = switchwin->sw_curwin;
curbuf = curwin->w_buffer;
}
- // If called by win_execute() and executing the command changed the
- // directory, it now has to be restored.
- fix_current_dir();
}
/// Make "buf" the current buffer.
@@ -6726,286 +7154,6 @@ void restore_buffer(bufref_T *save_curbuf)
}
}
-
-/// Add match to the match list of window 'wp'. The pattern 'pat' will be
-/// highlighted with the group 'grp' with priority 'prio'.
-/// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
-///
-/// @param[in] id a desired ID 'id' can be specified
-/// (greater than or equal to 1). -1 must be specified if no
-/// particular ID is desired
-/// @param[in] conceal_char pointer to conceal replacement char
-/// @return ID of added match, -1 on failure.
-int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id,
- list_T *pos_list, const char *const conceal_char)
- FUNC_ATTR_NONNULL_ARG(1, 2)
-{
- matchitem_T *cur;
- matchitem_T *prev;
- matchitem_T *m;
- int hlg_id;
- regprog_T *regprog = NULL;
- int rtype = SOME_VALID;
-
- if (*grp == NUL || (pat != NULL && *pat == NUL)) {
- return -1;
- }
- if (id < -1 || id == 0) {
- semsg(_("E799: Invalid ID: %" PRId64
- " (must be greater than or equal to 1)"),
- (int64_t)id);
- return -1;
- }
- if (id != -1) {
- cur = wp->w_match_head;
- while (cur != NULL) {
- if (cur->id == id) {
- semsg(_("E801: ID already taken: %" PRId64), (int64_t)id);
- return -1;
- }
- cur = cur->next;
- }
- }
- if ((hlg_id = syn_check_group(grp, strlen(grp))) == 0) {
- return -1;
- }
- if (pat != NULL && (regprog = vim_regcomp((char_u *)pat, RE_MAGIC)) == NULL) {
- semsg(_(e_invarg2), pat);
- return -1;
- }
-
- // Find available match ID.
- while (id == -1) {
- cur = wp->w_match_head;
- while (cur != NULL && cur->id != wp->w_next_match_id) {
- cur = cur->next;
- }
- if (cur == NULL) {
- id = wp->w_next_match_id;
- }
- wp->w_next_match_id++;
- }
-
- // Build new match.
- m = xcalloc(1, sizeof(matchitem_T));
- m->id = id;
- m->priority = prio;
- m->pattern = pat == NULL ? NULL: (char_u *)xstrdup(pat);
- m->hlg_id = hlg_id;
- m->match.regprog = regprog;
- m->match.rmm_ic = FALSE;
- m->match.rmm_maxcol = 0;
- m->conceal_char = 0;
- if (conceal_char != NULL) {
- m->conceal_char = utf_ptr2char((const char_u *)conceal_char);
- }
-
- // Set up position matches
- if (pos_list != NULL) {
- linenr_T toplnum = 0;
- linenr_T botlnum = 0;
-
- int i = 0;
- TV_LIST_ITER(pos_list, li, {
- linenr_T lnum = 0;
- colnr_T col = 0;
- int len = 1;
- bool error = false;
-
- if (TV_LIST_ITEM_TV(li)->v_type == VAR_LIST) {
- const list_T *const subl = TV_LIST_ITEM_TV(li)->vval.v_list;
- const listitem_T *subli = tv_list_first(subl);
- if (subli == NULL) {
- semsg(_("E5030: Empty list at position %d"),
- (int)tv_list_idx_of_item(pos_list, li));
- goto fail;
- }
- lnum = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
- if (error) {
- goto fail;
- }
- if (lnum <= 0) {
- continue;
- }
- m->pos.pos[i].lnum = lnum;
- subli = TV_LIST_ITEM_NEXT(subl, subli);
- if (subli != NULL) {
- col = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
- if (error) {
- goto fail;
- }
- if (col < 0) {
- continue;
- }
- subli = TV_LIST_ITEM_NEXT(subl, subli);
- if (subli != NULL) {
- len = tv_get_number_chk(TV_LIST_ITEM_TV(subli), &error);
- if (len < 0) {
- continue;
- }
- if (error) {
- goto fail;
- }
- }
- }
- m->pos.pos[i].col = col;
- m->pos.pos[i].len = len;
- } else if (TV_LIST_ITEM_TV(li)->v_type == VAR_NUMBER) {
- if (TV_LIST_ITEM_TV(li)->vval.v_number <= 0) {
- continue;
- }
- m->pos.pos[i].lnum = TV_LIST_ITEM_TV(li)->vval.v_number;
- m->pos.pos[i].col = 0;
- m->pos.pos[i].len = 0;
- } else {
- semsg(_("E5031: List or number required at position %d"),
- (int)tv_list_idx_of_item(pos_list, li));
- goto fail;
- }
- if (toplnum == 0 || lnum < toplnum) {
- toplnum = lnum;
- }
- if (botlnum == 0 || lnum >= botlnum) {
- botlnum = lnum + 1;
- }
- i++;
- if (i >= MAXPOSMATCH) {
- break;
- }
- });
-
- // Calculate top and bottom lines for redrawing area
- if (toplnum != 0) {
- if (wp->w_buffer->b_mod_set) {
- if (wp->w_buffer->b_mod_top > toplnum) {
- wp->w_buffer->b_mod_top = toplnum;
- }
- if (wp->w_buffer->b_mod_bot < botlnum) {
- wp->w_buffer->b_mod_bot = botlnum;
- }
- } else {
- wp->w_buffer->b_mod_set = true;
- wp->w_buffer->b_mod_top = toplnum;
- wp->w_buffer->b_mod_bot = botlnum;
- wp->w_buffer->b_mod_xlines = 0;
- }
- m->pos.toplnum = toplnum;
- m->pos.botlnum = botlnum;
- rtype = VALID;
- }
- }
-
- // Insert new match. The match list is in ascending order with regard to
- // the match priorities.
- cur = wp->w_match_head;
- prev = cur;
- while (cur != NULL && prio >= cur->priority) {
- prev = cur;
- cur = cur->next;
- }
- if (cur == prev) {
- wp->w_match_head = m;
- } else {
- prev->next = m;
- }
- m->next = cur;
-
- redraw_later(wp, rtype);
- return id;
-
-fail:
- xfree(m);
- return -1;
-}
-
-
-/// Delete match with ID 'id' in the match list of window 'wp'.
-///
-/// @param perr print error messages if true.
-int match_delete(win_T *wp, int id, bool perr)
-{
- matchitem_T *cur = wp->w_match_head;
- matchitem_T *prev = cur;
- int rtype = SOME_VALID;
-
- if (id < 1) {
- if (perr) {
- semsg(_("E802: Invalid ID: %" PRId64
- " (must be greater than or equal to 1)"),
- (int64_t)id);
- }
- return -1;
- }
- while (cur != NULL && cur->id != id) {
- prev = cur;
- cur = cur->next;
- }
- if (cur == NULL) {
- if (perr) {
- semsg(_("E803: ID not found: %" PRId64), (int64_t)id);
- }
- return -1;
- }
- if (cur == prev) {
- wp->w_match_head = cur->next;
- } else {
- prev->next = cur->next;
- }
- vim_regfree(cur->match.regprog);
- xfree(cur->pattern);
- if (cur->pos.toplnum != 0) {
- if (wp->w_buffer->b_mod_set) {
- if (wp->w_buffer->b_mod_top > cur->pos.toplnum) {
- wp->w_buffer->b_mod_top = cur->pos.toplnum;
- }
- if (wp->w_buffer->b_mod_bot < cur->pos.botlnum) {
- wp->w_buffer->b_mod_bot = cur->pos.botlnum;
- }
- } else {
- wp->w_buffer->b_mod_set = true;
- wp->w_buffer->b_mod_top = cur->pos.toplnum;
- wp->w_buffer->b_mod_bot = cur->pos.botlnum;
- wp->w_buffer->b_mod_xlines = 0;
- }
- rtype = VALID;
- }
- xfree(cur);
- redraw_later(wp, rtype);
- return 0;
-}
-
-/*
- * Delete all matches in the match list of window 'wp'.
- */
-void clear_matches(win_T *wp)
-{
- matchitem_T *m;
-
- while (wp->w_match_head != NULL) {
- m = wp->w_match_head->next;
- vim_regfree(wp->w_match_head->match.regprog);
- xfree(wp->w_match_head->pattern);
- xfree(wp->w_match_head);
- wp->w_match_head = m;
- }
- redraw_later(wp, SOME_VALID);
-}
-
-/*
- * Get match from ID 'id' in window 'wp'.
- * Return NULL if match not found.
- */
-matchitem_T *get_match(win_T *wp, int id)
-{
- matchitem_T *cur = wp->w_match_head;
-
- while (cur != NULL && cur->id != id) {
- cur = cur->next;
- }
- return cur;
-}
-
-
/// Check that "topfrp" and its children are at the right height.
///
/// @param topfrp top frame pointer
@@ -7131,16 +7279,14 @@ void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
tv_list_append_number(list, winnr);
}
-win_T *win_id2wp(typval_T *argvars)
+win_T *win_id2wp(int id)
{
- return win_id2wp_tp(argvars, NULL);
+ return win_id2wp_tp(id, NULL);
}
// Return the window and tab pointer of window "id".
-win_T *win_id2wp_tp(typval_T *argvars, tabpage_T **tpp)
+win_T *win_id2wp_tp(int id, tabpage_T **tpp)
{
- int id = tv_get_number(&argvars[0]);
-
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->handle == id) {
if (tpp != NULL) {
@@ -7172,7 +7318,7 @@ void win_findbuf(typval_T *argvars, list_T *list)
int bufnr = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (!wp->w_closing && wp->w_buffer->b_fnum == bufnr) {
+ if (wp->w_buffer->b_fnum == bufnr) {
tv_list_append_number(list, wp->handle);
}
}