diff options
Diffstat (limited to 'src/nvim/window.c')
-rw-r--r-- | src/nvim/window.c | 304 |
1 files changed, 187 insertions, 117 deletions
diff --git a/src/nvim/window.c b/src/nvim/window.c index bcf245ef93..e2c4524eaa 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -13,6 +13,7 @@ #include "nvim/arglist.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" +#include "nvim/autocmd_defs.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" @@ -23,29 +24,32 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/eval/window.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" -#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" -#include "nvim/gettext.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/grid.h" +#include "nvim/grid_defs.h" #include "nvim/hashtab.h" #include "nvim/keycodes.h" #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/map_defs.h" -#include "nvim/mapping.h" // IWYU pragma: keep (langmap_adjust_mb) +#include "nvim/mapping.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/match.h" #include "nvim/mbyte.h" #include "nvim/memory.h" @@ -57,12 +61,14 @@ #include "nvim/option_defs.h" #include "nvim/option_vars.h" #include "nvim/os/fs.h" +#include "nvim/os/os_defs.h" #include "nvim/path.h" #include "nvim/plines.h" #include "nvim/pos_defs.h" #include "nvim/quickfix.h" #include "nvim/search.h" #include "nvim/state.h" +#include "nvim/state_defs.h" #include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" @@ -70,6 +76,7 @@ #include "nvim/types_defs.h" #include "nvim/ui.h" #include "nvim/ui_compositor.h" +#include "nvim/ui_defs.h" #include "nvim/undo.h" #include "nvim/vim_defs.h" #include "nvim/window.h" @@ -191,7 +198,7 @@ void do_window(int nchar, int Prenum, int xchar) if (bt_quickfix(curbuf)) { goto newwindow; } - (void)win_split(Prenum, 0); + win_split(Prenum, 0); break; // split current window in two parts, vertically @@ -204,7 +211,7 @@ void do_window(int nchar, int Prenum, int xchar) if (bt_quickfix(curbuf)) { goto newwindow; } - (void)win_split(Prenum, WSP_VERT); + win_split(Prenum, WSP_VERT); break; // split current window and edit alternate file @@ -223,8 +230,8 @@ void do_window(int nchar, int Prenum, int xchar) } if (!curbuf_locked() && win_split(0, 0) == OK) { - (void)buflist_getfile(Prenum == 0 ? curwin->w_alt_fnum : Prenum, - 0, GETF_ALT, false); + buflist_getfile(Prenum == 0 ? curwin->w_alt_fnum : Prenum, + 0, GETF_ALT, false); } break; @@ -321,13 +328,13 @@ newwindow: wp = lastwin; // wrap around } while (wp != NULL && wp->w_floating - && !wp->w_float_config.focusable) { + && !wp->w_config.focusable) { wp = wp->w_prev; } } else { // go to next window wp = curwin->w_next; while (wp != NULL && wp->w_floating - && !wp->w_float_config.focusable) { + && !wp->w_config.focusable) { wp = wp->w_next; } if (wp == NULL) { @@ -611,7 +618,7 @@ wingotofile: LANGMAP_ADJUST(xchar, true); no_mapping--; allow_keys--; - (void)add_to_showcmd(xchar); + add_to_showcmd(xchar); switch (xchar) { case '}': @@ -662,7 +669,7 @@ wingotofile: beep_flush(); break; } - FloatConfig config = FLOAT_CONFIG_INIT; + WinConfig config = WIN_CONFIG_INIT; config.width = curwin->w_width; config.height = curwin->w_height; config.external = true; @@ -706,7 +713,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) } switchwin_T switchwin; - if (switch_win_noblock(&switchwin, win, tab, false) == FAIL) { + if (switch_win_noblock(&switchwin, win, tab, true) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to switch to window %d", @@ -726,7 +733,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) // So do it now. validate_cursor(); - restore_win_noblock(&switchwin, false); + restore_win_noblock(&switchwin, true); if (noautocmd) { unblock_autocmds(); } @@ -756,10 +763,11 @@ void ui_ext_win_position(win_T *wp, bool validate) return; } - FloatConfig c = wp->w_float_config; + WinConfig c = wp->w_config; if (!c.external) { ScreenGrid *grid = &default_grid; - Float row = c.row, col = c.col; + Float row = c.row; + Float col = c.col; if (c.relative == kFloatRelativeWindow) { Error dummy = ERROR_INIT; win_T *win = find_window_by_handle(c.window, &dummy); @@ -771,7 +779,8 @@ void ui_ext_win_position(win_T *wp, bool validate) ui_ext_win_position(win, validate); } grid = &win->w_grid; - int row_off = 0, col_off = 0; + int row_off = 0; + int col_off = 0; grid_adjust(&grid, &row_off, &col_off); row += row_off; col += col_off; @@ -785,9 +794,9 @@ void ui_ext_win_position(win_T *wp, bool validate) } } - wp->w_grid_alloc.zindex = wp->w_float_config.zindex; + wp->w_grid_alloc.zindex = wp->w_config.zindex; if (ui_has(kUIMultigrid)) { - String anchor = cstr_as_string((char *)float_anchor_str[c.anchor]); + String anchor = cstr_as_string(float_anchor_str[c.anchor]); if (!c.hide) { ui_call_win_float_pos(wp->w_grid_alloc.handle, wp->handle, anchor, grid->handle, row, col, c.focusable, @@ -808,9 +817,10 @@ void ui_ext_win_position(win_T *wp, bool validate) int comp_row = (int)row - (south ? wp->w_height_outer : 0); int comp_col = (int)col - (east ? wp->w_width_outer : 0); + int above_ch = wp->w_config.zindex < kZIndexMessages ? (int)p_ch : 0; comp_row += grid->comp_row; comp_col += grid->comp_col; - comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - (p_ch > 0 ? 1 : 0)), 0); + comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - above_ch), 0); if (!c.fixed || east) { comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0); } @@ -821,7 +831,7 @@ void ui_ext_win_position(win_T *wp, bool validate) ui_comp_put_grid(&wp->w_grid_alloc, comp_row, comp_col, wp->w_height_outer, wp->w_width_outer, valid, false); ui_check_cursor_grid(wp->w_grid_alloc.handle); - wp->w_grid_alloc.focusable = wp->w_float_config.focusable; + wp->w_grid_alloc.focusable = wp->w_config.focusable; if (!valid) { wp->w_grid_alloc.valid = false; redraw_later(wp, UPD_NOT_VALID); @@ -919,6 +929,7 @@ static int check_split_disallowed(void) // 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 +// WSP_NOENTER: do not enter the new window or trigger WinNew autocommands // // return FAIL for failure, OK otherwise int win_split(int size, int flags) @@ -947,20 +958,20 @@ int win_split(int size, int flags) clear_snapshot(curtab, SNAP_HELP_IDX); } - return win_split_ins(size, flags, NULL, 0); + return win_split_ins(size, flags, NULL, 0) == NULL ? FAIL : OK; } /// When "new_wp" is NULL: split the current window in two. /// When "new_wp" is not NULL: insert this window at the far /// top/left/right/bottom. -/// @return FAIL for failure, OK otherwise -int win_split_ins(int size, int flags, win_T *new_wp, int dir) +/// @return NULL for failure, or pointer to new window +win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) { win_T *wp = new_wp; // aucmd_win[] should always remain floating if (new_wp != NULL && is_aucmd_win(new_wp)) { - return FAIL; + return NULL; } win_T *oldwin; @@ -976,22 +987,24 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) int need_status = 0; int new_size = size; bool new_in_layout = (new_wp == NULL || new_wp->w_floating); + bool vertical = flags & WSP_VERT; + bool toplevel = flags & (WSP_TOP | WSP_BOT); // add a status line when p_ls == 1 and splitting the first window if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) { if (oldwin->w_height <= p_wmh && new_in_layout) { emsg(_(e_noroom)); - return FAIL; + return NULL; } need_status = STATUS_HEIGHT; } bool do_equal = false; int oldwin_height = 0; - const int layout = flags & WSP_VERT ? FR_ROW : FR_COL; + const int layout = vertical ? FR_ROW : FR_COL; bool did_set_fraction = false; - if (flags & WSP_VERT) { + if (vertical) { // Check if we are able to split the current window and compute its // width. // Current window requires at least 1 space. @@ -1002,7 +1015,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } int minwidth; int available; - if (flags & (WSP_BOT | WSP_TOP)) { + if (toplevel) { minwidth = frame_minwidth(topframe, NOWIN); available = topframe->fr_width; needed += minwidth; @@ -1030,7 +1043,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } if (available < needed && new_in_layout) { emsg(_(e_noroom)); - return FAIL; + return NULL; } if (new_size == 0) { new_size = oldwin->w_width / 2; @@ -1083,7 +1096,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } int minheight; int available; - if (flags & (WSP_BOT | WSP_TOP)) { + if (toplevel) { minheight = frame_minheight(topframe, NOWIN) + need_status; available = topframe->fr_height; needed += minheight; @@ -1110,7 +1123,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } if (available < needed && new_in_layout) { emsg(_(e_noroom)); - return FAIL; + return NULL; } oldwin_height = oldwin->w_height; if (need_status) { @@ -1173,7 +1186,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) && ((flags & WSP_BOT) || (flags & WSP_BELOW) || (!(flags & WSP_ABOVE) - && ((flags & WSP_VERT) ? p_spr : p_sb)))) { + && (vertical ? p_spr : p_sb)))) { // new window below/right of current one if (new_wp == NULL) { wp = win_alloc(oldwin, false); @@ -1190,7 +1203,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) if (new_wp == NULL) { if (wp == NULL) { - return FAIL; + return NULL; } new_frame(wp); @@ -1201,17 +1214,17 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) new_frame(wp); wp->w_floating = false; // non-floating window doesn't store float config or have a border. - wp->w_float_config = FLOAT_CONFIG_INIT; + wp->w_config = WIN_CONFIG_INIT; CLEAR_FIELD(wp->w_border_adj); } - int before; + bool before; frame_T *curfrp; // Reorganise the tree of frames to insert the new window. - if (flags & (WSP_TOP | WSP_BOT)) { - if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0) - || (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0)) { + if (toplevel) { + if ((topframe->fr_layout == FR_COL && !vertical) + || (topframe->fr_layout == FR_ROW && vertical)) { curfrp = topframe->fr_child; if (flags & WSP_BOT) { while (curfrp->fr_next != NULL) { @@ -1228,7 +1241,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) before = false; } else if (flags & WSP_ABOVE) { before = true; - } else if (flags & WSP_VERT) { + } else if (vertical) { before = !p_spr; } else { before = !p_sb; @@ -1276,14 +1289,14 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } wp->w_fraction = oldwin->w_fraction; - if (flags & WSP_VERT) { + if (vertical) { wp->w_p_scr = curwin->w_p_scr; if (need_status) { win_new_height(oldwin, oldwin->w_height - 1); oldwin->w_status_height = need_status; } - if (flags & (WSP_TOP | WSP_BOT)) { + if (toplevel) { // set height and row of new window to full height wp->w_winrow = tabline_height(); win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2)); @@ -1307,7 +1320,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) wp->w_vsep_width = oldwin->w_vsep_width; oldwin->w_vsep_width = 1; } - if (flags & (WSP_TOP | WSP_BOT)) { + if (toplevel) { if (flags & WSP_BOT) { frame_add_vsep(curfrp); } @@ -1329,7 +1342,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } else { const 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)) { + if (toplevel) { wp->w_wincol = 0; win_new_width(wp, Columns); wp->w_vsep_width = 0; @@ -1350,7 +1363,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) wp->w_hsep_height = oldwin->w_hsep_height; oldwin->w_hsep_height = is_stl_global ? 1 : 0; } - if (flags & (WSP_TOP | WSP_BOT)) { + if (toplevel) { int new_fr_height = curfrp->fr_height - new_size; if (is_stl_global) { if (flags & WSP_BOT) { @@ -1396,8 +1409,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) frame_fix_height(oldwin); } - if (flags & (WSP_TOP | WSP_BOT)) { - (void)win_comp_pos(); + if (toplevel) { + win_comp_pos(); } // Both windows need redrawing. Update all status lines, in case they @@ -1417,7 +1430,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, vertical ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v')); } else if (!is_aucmd_win(wp)) { win_fix_scroll(false); } @@ -1438,10 +1451,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) } } - // make the new window the current window - win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS - | WEE_TRIGGER_LEAVE_AUTOCMDS); - if (flags & WSP_VERT) { + if (!(flags & WSP_NOENTER)) { + // make the new window the current window + win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS + | WEE_TRIGGER_LEAVE_AUTOCMDS); + } + if (vertical) { p_wiw = i; } else { p_wh = i; @@ -1452,7 +1467,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir) oldwin->w_pos_changed = true; } - return OK; + return wp; } // Initialize window "newp" from window "oldp". @@ -1548,7 +1563,7 @@ bool win_valid(const win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT /// Check if "win" is a pointer to an existing window in tabpage "tp". /// /// @param win window to check -static bool tabpage_win_valid(const tabpage_T *tp, const win_T *win) +bool tabpage_win_valid(const tabpage_T *tp, const win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (win == NULL) { @@ -1745,7 +1760,7 @@ static void win_exchange(int Prenum) frame_fix_width(curwin); frame_fix_width(wp); - (void)win_comp_pos(); // recompute window positions + win_comp_pos(); // recompute window positions if (wp->w_buffer != curbuf) { reset_VIsual_and_resel(); @@ -1832,7 +1847,7 @@ static void win_rotate(bool upwards, int count) frame_fix_width(wp2); // recompute w_winrow and w_wincol for all windows - (void)win_comp_pos(); + win_comp_pos(); } wp1->w_pos_changed = true; @@ -1869,14 +1884,14 @@ static void win_totop(int size, int flags) } } else { // Remove the window and frame from the tree of frames. - (void)winframe_remove(curwin, &dir, NULL); + winframe_remove(curwin, &dir, NULL); } win_remove(curwin, NULL); last_status(false); // may need to remove last status line - (void)win_comp_pos(); // recompute window positions + win_comp_pos(); // recompute window positions // Split a window on the desired side and put the window there. - (void)win_split_ins(size, flags, curwin, dir); + win_split_ins(size, flags, curwin, dir); if (!(flags & WSP_VERT)) { win_setheight(height); if (p_ea) { @@ -1943,7 +1958,7 @@ void win_move_after(win_T *win1, win_T *win2) win_append(win2, win1); frame_append(win2->w_frame, win1->w_frame); - (void)win_comp_pos(); // recompute w_winrow for all windows + win_comp_pos(); // recompute w_winrow for all windows redraw_later(curwin, UPD_NOT_VALID); } win_enter(win1, false); @@ -2022,7 +2037,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int int totwincount = 0; int next_curwin_size = 0; int room = 0; - int has_next_curwin = 0; + bool has_next_curwin = false; if (topfr->fr_layout == FR_LEAF) { // Set the width/height of this frame. @@ -2311,7 +2326,7 @@ 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 & MODE_INSERT) { + if ((State & MODE_INSERT) && !stop_insert_mode) { stop_insert_mode = true; if (win->w_buffer->b_prompt_insert == NUL) { win->w_buffer->b_prompt_insert = 'A'; @@ -2476,7 +2491,7 @@ bool can_close_in_cmdwin(win_T *win, Error *err) FUNC_ATTR_NONNULL_ALL { if (cmdwin_type != 0) { - if (win == curwin) { + if (win == cmdwin_win) { cmdwin_result = Ctrl_C; return false; } else if (win == cmdwin_old_curwin) { @@ -2544,6 +2559,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev /// "abort_if_last" is passed to close_buffer(): abort closing if all other /// windows are closed. static void win_close_buffer(win_T *win, int action, bool abort_if_last) + FUNC_ATTR_NONNULL_ALL { // Free independent synblock before the buffer is freed. if (win->w_buffer != NULL) { @@ -2581,6 +2597,7 @@ static void win_close_buffer(win_T *win, int action, bool abort_if_last) // 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, bool force) + FUNC_ATTR_NONNULL_ALL { tabpage_T *prev_curtab = curtab; frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent; @@ -2741,7 +2758,7 @@ int win_close(win_T *win, bool free_buf, bool force) if (win->w_floating) { ui_comp_remove_grid(&win->w_grid_alloc); assert(first_tabpage != NULL); // suppress clang "Dereference of NULL pointer" - if (win->w_float_config.external) { + if (win->w_config.external) { for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { if (tp == curtab) { continue; @@ -2813,7 +2830,7 @@ int win_close(win_T *win, bool free_buf, bool force) // only resize that frame. Otherwise resize all windows. win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir); } else { - (void)win_comp_pos(); + win_comp_pos(); win_fix_scroll(false); } } @@ -2879,6 +2896,7 @@ static void do_autocmd_winclosed(win_T *win) // Caller must check if buffer is hidden and whether the tabline needs to be // updated. void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) + FUNC_ATTR_NONNULL_ALL { // Get here with win->w_buffer == NULL when win_close() detects the tab page // changed. @@ -2980,6 +2998,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) /// /// @return a pointer to the window that got the freed up space. static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1) { win_T *wp; tabpage_T *win_tp = tp == NULL ? curtab : tp; @@ -2998,6 +3017,7 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp) wp = firstwin; } } else { + assert(tp != curtab); if (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) { wp = tp->tp_prevwin; } else { @@ -3021,6 +3041,9 @@ void win_free_all(void) { // avoid an error for switching tabpage with the cmdline window open cmdwin_type = 0; + cmdwin_buf = NULL; + cmdwin_win = NULL; + cmdwin_old_curwin = NULL; while (first_tabpage->tp_next != NULL) { tabpage_close(true); @@ -3030,7 +3053,7 @@ void win_free_all(void) win_T *wp = lastwin; win_remove(lastwin, NULL); int dummy; - (void)win_free_mem(wp, &dummy, NULL); + win_free_mem(wp, &dummy, NULL); for (int i = 0; i < AUCMD_WIN_COUNT; i++) { if (aucmd_win[i].auc_win == wp) { aucmd_win[i].auc_win = NULL; @@ -3041,7 +3064,7 @@ void win_free_all(void) for (int i = 0; i < AUCMD_WIN_COUNT; i++) { if (aucmd_win[i].auc_win != NULL) { int dummy; - (void)win_free_mem(aucmd_win[i].auc_win, &dummy, NULL); + win_free_mem(aucmd_win[i].auc_win, &dummy, NULL); aucmd_win[i].auc_win = NULL; } } @@ -3050,7 +3073,7 @@ void win_free_all(void) while (firstwin != NULL) { int dummy; - (void)win_free_mem(firstwin, &dummy, NULL); + win_free_mem(firstwin, &dummy, NULL); } // No window should be used after this. Set curwin to NULL to crash @@ -3067,7 +3090,10 @@ void win_free_all(void) /// /// @return a pointer to the window that got the freed up space. win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1, 2) { + assert(tp == NULL || tp != curtab); + // If there is only one window there is nothing to remove. if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) { return NULL; @@ -3214,7 +3240,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) /// @return a pointer to the frame that will receive the empty screen space that /// is left over after "win" is closed. static frame_T *win_altframe(win_T *win, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1) { + assert(tp == NULL || tp != curtab); + if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) { return alt_tabpage()->tp_curwin->w_frame; } @@ -3278,6 +3307,7 @@ static tabpage_T *alt_tabpage(void) // Find the left-upper window in frame "frp". win_T *frame2win(frame_T *frp) + FUNC_ATTR_NONNULL_ALL { while (frp->fr_win == NULL) { frp = frp->fr_child; @@ -3850,7 +3880,7 @@ void win_alloc_first(void) void win_alloc_aucmd_win(int idx) { Error err = ERROR_INIT; - FloatConfig fconfig = FLOAT_CONFIG_INIT; + WinConfig fconfig = WIN_CONFIG_INIT; fconfig.width = Columns; fconfig.height = 5; fconfig.focusable = false; @@ -4299,7 +4329,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab) for (win_T *wp = old_curtab->tp_firstwin; wp; wp = next_wp) { next_wp = wp->w_next; if (wp->w_floating) { - if (wp->w_float_config.external) { + if (wp->w_config.external) { win_remove(wp, old_curtab); win_append(lastwin_nofloating(), wp); } else { @@ -4310,8 +4340,8 @@ static void tabpage_check_windows(tabpage_T *old_curtab) } for (win_T *wp = firstwin; wp; wp = wp->w_next) { - if (wp->w_floating && !wp->w_float_config.external) { - win_config_float(wp, wp->w_float_config); + if (wp->w_floating && !wp->w_config.external) { + win_config_float(wp, wp->w_config); } wp->w_pos_changed = true; } @@ -4427,6 +4457,10 @@ void tabpage_move(int nr) return; } + if (tabpage_move_disallowed) { + return; + } + int n = 1; tabpage_T *tp; @@ -4471,11 +4505,12 @@ void tabpage_move(int nr) redraw_tabline = true; } -// Go to another window. -// When jumping to another buffer, stop Visual mode. Do this before -// changing windows so we can yank the selection into the '*' register. -// When jumping to another window on the same buffer, adjust its cursor -// position to keep the same Visual area. +/// Go to another window. +/// When jumping to another buffer, stop Visual mode. Do this before +/// changing windows so we can yank the selection into the '*' register. +/// (note: this may trigger ModeChanged autocommand!) +/// When jumping to another window on the same buffer, adjust its cursor +/// position to keep the same Visual area. void win_goto(win_T *wp) { win_T *owp = curwin; @@ -4486,11 +4521,17 @@ void win_goto(win_T *wp) } if (wp->w_buffer != curbuf) { + // careful: triggers ModeChanged autocommand reset_VIsual_and_resel(); } else if (VIsual_active) { wp->w_cursor = curwin->w_cursor; } + // autocommand may have made wp invalid + if (!win_valid(wp)) { + return; + } + win_enter(wp, true); // Conceal cursor line in previous window, unconceal in current window. @@ -4726,10 +4767,14 @@ static void win_enter_ext(win_T *const wp, const int flags) if (wp->w_buffer != curbuf) { buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP); } + if (!curwin_invalid) { prevwin = curwin; // remember for CTRL-W p curwin->w_redr_status = true; + } else if (wp == prevwin) { + prevwin = NULL; // don't want it to be the new curwin } + curwin = wp; curbuf = wp->w_buffer; @@ -4902,12 +4947,12 @@ win_T *buf_jump_open_tab(buf_T *buf) return NULL; } +static int last_win_id = LOWEST_WIN_ID - 1; + /// @param hidden allocate a window structure and link it in the window if // false. win_T *win_alloc(win_T *after, bool hidden) { - static int last_win_id = LOWEST_WIN_ID - 1; - // allocate window structure and linesizes arrays win_T *new_wp = xcalloc(1, sizeof(win_T)); @@ -4939,12 +4984,15 @@ win_T *win_alloc(win_T *after, bool hidden) new_wp->w_cursor.lnum = 1; new_wp->w_scbind_pos = 1; new_wp->w_floating = 0; - new_wp->w_float_config = FLOAT_CONFIG_INIT; + new_wp->w_config = WIN_CONFIG_INIT; new_wp->w_viewport_invalid = true; new_wp->w_viewport_last_topline = 1; new_wp->w_ns_hl = -1; + Set(uint32_t) ns_set = SET_INIT; + new_wp->w_ns_set = ns_set; + // use global option for global-local options new_wp->w_allbuf_opt.wo_so = new_wp->w_p_so = -1; new_wp->w_allbuf_opt.wo_siso = new_wp->w_p_siso = -1; @@ -4972,7 +5020,7 @@ void free_wininfo(wininfo_T *wip, buf_T *bp) /// Remove window 'wp' from the window list and free the structure. /// /// @param tp tab page "win" is in, NULL for current -static void win_free(win_T *wp, tabpage_T *tp) +void win_free(win_T *wp, tabpage_T *tp) { pmap_del(int)(&window_handles, wp->handle, NULL); clearFolding(wp); @@ -4983,6 +5031,8 @@ static void win_free(win_T *wp, tabpage_T *tp) // Don't execute autocommands while the window is halfway being deleted. block_autocmds(); + set_destroy(uint32_t, &wp->w_ns_set); + clear_winopt(&wp->w_onebuf_opt); clear_winopt(&wp->w_allbuf_opt); @@ -5053,8 +5103,8 @@ static void win_free(win_T *wp, tabpage_T *tp) } // free the border text - clear_virttext(&wp->w_float_config.title_chunks); - clear_virttext(&wp->w_float_config.footer_chunks); + clear_virttext(&wp->w_config.title_chunks); + clear_virttext(&wp->w_config.footer_chunks); clear_matches(wp); @@ -5115,7 +5165,10 @@ void win_append(win_T *after, win_T *wp) /// /// @param tp tab page "win" is in, NULL for current void win_remove(win_T *wp, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1) { + assert(tp == NULL || tp != curtab); + if (wp->w_prev != NULL) { wp->w_prev->w_next = wp->w_next; } else if (tp == NULL) { @@ -5177,7 +5230,7 @@ void win_new_screensize(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 && !option_was_set("window"))) { + if (p_window == old_Rows - 1 || (old_Rows == 0 && !option_was_set(kOptWindow))) { p_window = Rows - 1; } old_Rows = Rows; @@ -5209,7 +5262,7 @@ void win_new_screen_rows(void) frame_new_height(topframe, h, false, false); } - (void)win_comp_pos(); // recompute w_winrow and w_wincol + win_comp_pos(); // recompute w_winrow and w_wincol win_reconfig_floats(); // The size of floats might change compute_cmdrow(); curtab->tp_ch_used = p_ch; @@ -5233,7 +5286,7 @@ void win_new_screen_cols(void) frame_new_width(topframe, Columns, false, false); } - (void)win_comp_pos(); // recompute w_winrow and w_wincol + win_comp_pos(); // recompute w_winrow and w_wincol win_reconfig_floats(); // The size of floats might change } @@ -5343,7 +5396,7 @@ static int check_window_scroll_resize(int *size_count, win_T **first_scroll_win, FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { // Skip floating windows that do not have a snapshot (usually because they are newly-created), - // as unlike split windows, creating floating windows do not cause other windows to resize. + // as unlike split windows, creating floating windows doesn't cause other windows to resize. if (wp->w_floating && wp->w_last_topline == 0) { wp->w_last_topline = wp->w_topline; wp->w_last_topfill = wp->w_topfill; @@ -5452,12 +5505,13 @@ void may_trigger_win_scrolled_resized(void) } int size_count = 0; - win_T *first_scroll_win = NULL, *first_size_win = NULL; + win_T *first_scroll_win = NULL; + win_T *first_size_win = NULL; int cwsr = check_window_scroll_resize(&size_count, &first_scroll_win, &first_size_win, NULL, NULL); - int trigger_resize = do_resize && size_count > 0; - int trigger_scroll = do_scroll && cwsr != 0; + bool trigger_resize = do_resize && size_count > 0; + bool trigger_scroll = do_scroll && cwsr != 0; if (!trigger_resize && !trigger_scroll) { return; // no relevant changes } @@ -5467,7 +5521,7 @@ void may_trigger_win_scrolled_resized(void) // Create the list for v:event.windows before making the snapshot. // windows_list = tv_list_alloc_with_items(size_count); windows_list = tv_list_alloc(size_count); - (void)check_window_scroll_resize(NULL, NULL, NULL, windows_list, NULL); + check_window_scroll_resize(NULL, NULL, NULL, windows_list, NULL); } dict_T *scroll_dict = NULL; @@ -5475,7 +5529,7 @@ void may_trigger_win_scrolled_resized(void) // Create the dict with entries for v:event before making the snapshot. scroll_dict = tv_dict_alloc(); scroll_dict->dv_refcount = 1; - (void)check_window_scroll_resize(NULL, NULL, NULL, NULL, scroll_dict); + check_window_scroll_resize(NULL, NULL, NULL, NULL, scroll_dict); } // WinScrolled/WinResized are triggered only once, even when multiple @@ -5559,7 +5613,7 @@ void win_size_restore(garray_T *gap) } } // recompute the window positions - (void)win_comp_pos(); + win_comp_pos(); } } @@ -5574,7 +5628,7 @@ int win_comp_pos(void) for (win_T *wp = lastwin; wp && wp->w_floating; wp = wp->w_prev) { // float might be anchored to moved window - if (wp->w_float_config.relative == kFloatRelativeWindow) { + if (wp->w_config.relative == kFloatRelativeWindow) { wp->w_pos_changed = true; } } @@ -5633,8 +5687,8 @@ void win_setheight_win(int height, win_T *win) height = MAX(height, (int)(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); + win->w_config.height = height; + win_config_float(win, win->w_config); redraw_later(win, UPD_VALID); } else { frame_setheight(win->w_frame, height + win->w_hsep_height + win->w_status_height); @@ -5645,7 +5699,7 @@ void win_setheight_win(int height, win_T *win) // If there is extra space created between the last window and the command // line, clear it. if (full_screen && msg_scrolled == 0 && row < cmdline_row) { - grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0); + grid_clear(&default_grid, row, cmdline_row, 0, Columns, 0); if (msg_grid.chars) { clear_cmdline = true; } @@ -5845,14 +5899,14 @@ void win_setwidth_win(int width, win_T *wp) width = 0; } if (wp->w_floating) { - wp->w_float_config.width = width; - win_config_float(wp, wp->w_float_config); + wp->w_config.width = width; + win_config_float(wp, wp->w_config); redraw_later(wp, UPD_NOT_VALID); } else { frame_setwidth(wp->w_frame, width + wp->w_vsep_width); // recompute the window positions - (void)win_comp_pos(); + win_comp_pos(); redraw_all_later(UPD_NOT_VALID); } } @@ -6128,7 +6182,7 @@ void win_drag_status_line(win_T *dragwin, int offset) } } int row = win_comp_pos(); - grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0); + grid_clear(&default_grid, row, cmdline_row, 0, Columns, 0); if (msg_grid.chars) { clear_cmdline = true; } @@ -6237,7 +6291,7 @@ void win_drag_vsep_line(win_T *dragwin, int offset) fr = fr->fr_next; } } - (void)win_comp_pos(); + win_comp_pos(); redraw_all_later(UPD_NOT_VALID); } @@ -6262,7 +6316,7 @@ void set_fraction(win_T *wp) /// TODO(vim): Ensure this also works with wrapped lines. /// Requires a not fully visible cursor line to be allowed at the bottom of /// a window("zb"), probably only when 'smoothscroll' is also set. -void win_fix_scroll(int resize) +void win_fix_scroll(bool resize) { if (*p_spk == 'c') { return; // 'splitkeep' is "cursor" @@ -6433,7 +6487,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) } } else if (sline > 0) { while (sline > 0 && lnum > 1) { - (void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); if (lnum == 1) { // first line in buffer is folded line_size = 1; @@ -6453,7 +6507,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) if (sline < 0) { // Line we want at top would go off top of screen. Use next // line instead. - (void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); lnum++; wp->w_wrow -= line_size + sline; } else if (sline > 0) { @@ -6548,14 +6602,16 @@ void win_new_width(win_T *wp, int width) win_set_inner_size(wp, true); } +OptInt win_default_scroll(win_T *wp) +{ + return MAX(wp->w_height_inner / 2, 1); +} + void win_comp_scroll(win_T *wp) { const OptInt old_w_p_scr = wp->w_p_scr; + wp->w_p_scr = win_default_scroll(wp); - wp->w_p_scr = wp->w_height_inner / 2; - if (wp->w_p_scr == 0) { - wp->w_p_scr = 1; - } if (wp->w_p_scr != old_w_p_scr) { // Used by "verbose set scroll". wp->w_p_script_ctx[WV_SCROLL].script_ctx.sc_sid = SID_WINLAYOUT; @@ -6617,11 +6673,11 @@ void command_height(void) } // Recompute window positions. - (void)win_comp_pos(); + win_comp_pos(); // clear the lines added to cmdline if (full_screen) { - grid_fill(&default_grid, cmdline_row, Rows, 0, Columns, ' ', ' ', 0); + grid_clear(&default_grid, cmdline_row, Rows, 0, Columns, 0); } msg_row = cmdline_row; redraw_cmdline = true; @@ -6637,7 +6693,7 @@ void command_height(void) // Recompute window positions. if (frp != lastwin->w_frame) { - (void)win_comp_pos(); + win_comp_pos(); } } @@ -6853,7 +6909,7 @@ static bool resize_frame_for_status(frame_T *fr) } else if (fp != fr) { frame_new_height(fp, fp->fr_height - 1, false, false); frame_fix_height(wp); - (void)win_comp_pos(); + win_comp_pos(); } else { win_new_height(wp, wp->w_height - 1); } @@ -6875,7 +6931,7 @@ static bool resize_frame_for_winbar(frame_T *fr) 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(); + win_comp_pos(); return true; } @@ -7211,7 +7267,7 @@ void restore_snapshot(int idx, int close_curwin) && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK) { win_T *wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe); - (void)win_comp_pos(); + win_comp_pos(); if (wp != NULL && close_curwin) { win_goto(wp); } @@ -7309,9 +7365,17 @@ static bool frame_check_width(const frame_T *topfrp, int width) } /// Simple int comparison function for use with qsort() -static int int_cmp(const void *a, const void *b) +static int int_cmp(const void *pa, const void *pb) { - return *(const int *)a - *(const int *)b; + const int a = *(const int *)pa; + const int b = *(const int *)pb; + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; } /// Handle setting 'colorcolumn' or 'textwidth' in window "wp". @@ -7388,12 +7452,18 @@ skip: return NULL; // no error } +int get_last_winid(void) +{ + return last_win_id; +} + void win_get_tabwin(handle_T id, int *tabnr, int *winnr) { *tabnr = 0; *winnr = 0; - int tnum = 1, wnum = 1; + int tnum = 1; + int wnum = 1; FOR_ALL_TABS(tp) { FOR_ALL_WINDOWS_IN_TAB(wp, tp) { if (wp->handle == id) { |