mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(api): handle win_split_ins failure properly
Problem: nvim_win_set_config does not handle failure in win_split_ins properly yet, which can cause all sorts of issues. Also nvim_open_win and nvim_win_set_config do not set the error message to the one from win_split_ins. Solution: handle failure by undoing winframe_remove, like in win_splitmove. Make sure autocommands from switching to the altwin fire within a valid window, and ensure they don't screw things up. Set the error message to that of win_split_ins, if any. Also change a few other small things, including: - adjust win_append to take a tabpage_T * argument, which is more consistent with win_remove (and also allows us to undo a call to win_remove). - allow winframe_restore to restore window positions. Useful if `wp` was in a different tabpage, as a call to win_comp_pos (which only works for the current tabpage) after winframe_restore should no longer be needed. Though enter_tabpage calls win_comp_pos anyway, this has the advantage of ensuring w_winrow/col remains accurate even before entering the tabpage (useful for stuff like win_screenpos, if used on a window in another tabpage). (This change should probably also be PR'd to Vim later, even though it doesn't use winframe_restore for a `wp` in a different tabpage yet).
This commit is contained in:
parent
832bc5c169
commit
d942c2b943
@ -259,7 +259,8 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
|
|||||||
}
|
}
|
||||||
int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER;
|
int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER;
|
||||||
|
|
||||||
if (parent == NULL) {
|
TRY_WRAP(err, {
|
||||||
|
if (parent == NULL || parent == curwin) {
|
||||||
wp = win_split_ins(0, flags, NULL, 0, NULL);
|
wp = win_split_ins(0, flags, NULL, 0, NULL);
|
||||||
} else {
|
} else {
|
||||||
tp = win_find_tabpage(parent);
|
tp = win_find_tabpage(parent);
|
||||||
@ -271,6 +272,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
|
|||||||
wp = win_split_ins(0, flags, NULL, 0, NULL);
|
wp = win_split_ins(0, flags, NULL, 0, NULL);
|
||||||
restore_win(&switchwin, true);
|
restore_win(&switchwin, true);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
if (wp) {
|
if (wp) {
|
||||||
wp->w_config = fconfig;
|
wp->w_config = fconfig;
|
||||||
}
|
}
|
||||||
@ -278,7 +280,9 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
|
|||||||
wp = win_new_float(NULL, false, fconfig, err);
|
wp = win_new_float(NULL, false, fconfig, err);
|
||||||
}
|
}
|
||||||
if (!wp) {
|
if (!wp) {
|
||||||
|
if (!ERROR_SET(err)) {
|
||||||
api_set_error(err, kErrorTypeException, "Failed to create window");
|
api_set_error(err, kErrorTypeException, "Failed to create window");
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,17 +452,47 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
|||||||
return; // error already set
|
return; // error already set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool to_split_ok = false;
|
||||||
|
// If we are moving curwin to another tabpage, switch windows *before* we remove it from the
|
||||||
|
// window list or remove its frame (if non-floating), so it's valid for autocommands.
|
||||||
|
const bool curwin_moving_tp
|
||||||
|
= win == curwin && parent != NULL && win_tp != win_find_tabpage(parent);
|
||||||
|
if (curwin_moving_tp) {
|
||||||
if (was_split) {
|
if (was_split) {
|
||||||
win_T *new_curwin = NULL;
|
int dir;
|
||||||
|
win_goto(winframe_find_altwin(win, &dir, NULL, NULL));
|
||||||
|
} else {
|
||||||
|
win_goto(win_valid(prevwin) && prevwin != win ? prevwin : firstwin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autocommands may have been a real nuisance and messed things up...
|
||||||
|
if (curwin == win) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to switch away from window %d",
|
||||||
|
win->handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
win_tp = win_find_tabpage(win);
|
||||||
|
if (!win_tp || !win_valid_any_tab(parent)) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Windows to split were closed");
|
||||||
|
goto restore_curwin;
|
||||||
|
}
|
||||||
|
if (was_split == win->w_floating || parent->w_floating) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Floating state of windows to split changed");
|
||||||
|
goto restore_curwin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dir = 0;
|
||||||
|
frame_T *unflat_altfr = NULL;
|
||||||
|
if (was_split) {
|
||||||
// If the window is the last in the tabpage or `fconfig.win` is
|
// If the window is the last in the tabpage or `fconfig.win` is
|
||||||
// a handle to itself, we can't split it.
|
// a handle to itself, we can't split it.
|
||||||
if (win->w_frame->fr_parent == NULL) {
|
if (win->w_frame->fr_parent == NULL) {
|
||||||
// FIXME(willothy): if the window is the last in the tabpage but there is another tabpage
|
// FIXME(willothy): if the window is the last in the tabpage but there is another tabpage
|
||||||
// and the target window is in that other tabpage, should we move the window to that
|
// and the target window is in that other tabpage, should we move the window to that
|
||||||
// tabpage and close the previous one, or just error?
|
// tabpage and close the previous one, or just error?
|
||||||
api_set_error(err, kErrorTypeValidation, "Cannot move last window");
|
api_set_error(err, kErrorTypeException, "Cannot move last window");
|
||||||
return;
|
goto restore_curwin;
|
||||||
} else if (parent != NULL && parent->handle == win->handle) {
|
} else if (parent != NULL && parent->handle == win->handle) {
|
||||||
int n_frames = 0;
|
int n_frames = 0;
|
||||||
for (frame_T *fr = win->w_frame->fr_parent->fr_child; fr != NULL; fr = fr->fr_next) {
|
for (frame_T *fr = win->w_frame->fr_parent->fr_child; fr != NULL; fr = fr->fr_next) {
|
||||||
@ -494,64 +528,67 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
|||||||
}
|
}
|
||||||
// If the frame doesn't have a parent, the old frame
|
// If the frame doesn't have a parent, the old frame
|
||||||
// was the root frame and we need to create a top-level split.
|
// was the root frame and we need to create a top-level split.
|
||||||
int dir;
|
winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr);
|
||||||
new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL);
|
|
||||||
} else if (n_frames == 2) {
|
} else if (n_frames == 2) {
|
||||||
// There are two windows in the frame, we can just rotate it.
|
// There are two windows in the frame, we can just rotate it.
|
||||||
int dir;
|
neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr);
|
||||||
neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL);
|
|
||||||
new_curwin = neighbor;
|
|
||||||
} else {
|
} else {
|
||||||
// There is only one window in the frame, we can't split it.
|
// There is only one window in the frame, we can't split it.
|
||||||
api_set_error(err, kErrorTypeValidation, "Cannot split window into itself");
|
api_set_error(err, kErrorTypeException, "Cannot split window into itself");
|
||||||
return;
|
goto restore_curwin;
|
||||||
}
|
}
|
||||||
// Set the parent to whatever the correct
|
// Set the parent to whatever the correct neighbor window was determined to be.
|
||||||
// neighbor window was determined to be.
|
|
||||||
parent = neighbor;
|
parent = neighbor;
|
||||||
} else {
|
} else {
|
||||||
int dir;
|
winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr);
|
||||||
new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, NULL);
|
}
|
||||||
}
|
}
|
||||||
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
||||||
// move to neighboring window if we're moving the current window to a new tabpage
|
|
||||||
if (curwin == win && parent != NULL && new_curwin != NULL
|
|
||||||
&& win_tp != win_find_tabpage(parent)) {
|
|
||||||
win_enter(new_curwin, true);
|
|
||||||
if (!win_valid_any_tab(parent)) {
|
|
||||||
// win_enter autocommands closed the `parent` to split from.
|
|
||||||
api_set_error(err, kErrorTypeException, "Window to split was closed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER;
|
int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER;
|
||||||
|
TRY_WRAP(err, {
|
||||||
if (parent == NULL) {
|
const bool need_switch = parent != NULL && parent != curwin;
|
||||||
if (!win_split_ins(0, flags, win, 0, NULL)) {
|
|
||||||
// TODO(willothy): What should this error message say?
|
|
||||||
api_set_error(err, kErrorTypeException, "Failed to split window");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switchwin_T switchwin;
|
switchwin_T switchwin;
|
||||||
|
if (need_switch) {
|
||||||
// `parent` is valid in its tabpage, so switch_win should not fail.
|
// `parent` is valid in its tabpage, so switch_win should not fail.
|
||||||
const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true);
|
const int result = switch_win(&switchwin, parent, win_find_tabpage(parent), true);
|
||||||
(void)result;
|
(void)result;
|
||||||
assert(result == OK);
|
assert(result == OK);
|
||||||
win_split_ins(0, flags, win, 0, NULL);
|
}
|
||||||
|
to_split_ok = win_split_ins(0, flags, win, 0, unflat_altfr) != NULL;
|
||||||
|
if (!to_split_ok) {
|
||||||
|
// Restore `win` to the window list now, so it's valid for restore_win (if used).
|
||||||
|
win_append(win->w_prev, win, win_tp == curtab ? NULL : win_tp);
|
||||||
|
}
|
||||||
|
if (need_switch) {
|
||||||
restore_win(&switchwin, true);
|
restore_win(&switchwin, true);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
if (!to_split_ok) {
|
||||||
|
if (was_split) {
|
||||||
|
// win_split_ins doesn't change sizes or layout if it fails to insert an existing window, so
|
||||||
|
// just undo winframe_remove.
|
||||||
|
winframe_restore(win, dir, unflat_altfr);
|
||||||
|
}
|
||||||
|
if (!ERROR_SET(err)) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to move window %d into split", win->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_curwin:
|
||||||
|
// If `win` was the original curwin, and autocommands didn't move it outside of curtab, be a
|
||||||
|
// good citizen and try to return to it.
|
||||||
|
if (curwin_moving_tp && win_valid(win)) {
|
||||||
|
win_goto(win);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, width)) {
|
if (HAS_KEY_X(config, width)) {
|
||||||
win_setwidth_win(fconfig.width, win);
|
win_setwidth_win(fconfig.width, win);
|
||||||
}
|
}
|
||||||
if (HAS_KEY_X(config, height)) {
|
if (HAS_KEY_X(config, height)) {
|
||||||
win_setheight_win(fconfig.height, win);
|
win_setheight_win(fconfig.height, win);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
win_config_float(win, fconfig);
|
win_config_float(win, fconfig);
|
||||||
win->w_pos_changed = true;
|
win->w_pos_changed = true;
|
||||||
|
@ -1333,7 +1333,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
|
|||||||
|
|
||||||
block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
|
block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
|
||||||
if (need_append) {
|
if (need_append) {
|
||||||
win_append(lastwin, auc_win);
|
win_append(lastwin, auc_win, NULL);
|
||||||
pmap_put(int)(&window_handles, auc_win->handle, auc_win);
|
pmap_put(int)(&window_handles, auc_win->handle, auc_win);
|
||||||
win_config_float(auc_win, auc_win->w_config);
|
win_config_float(auc_win, auc_win->w_config);
|
||||||
}
|
}
|
||||||
|
@ -1218,13 +1218,13 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl
|
|||||||
if (new_wp == NULL) {
|
if (new_wp == NULL) {
|
||||||
wp = win_alloc(oldwin, false);
|
wp = win_alloc(oldwin, false);
|
||||||
} else {
|
} else {
|
||||||
win_append(oldwin, wp);
|
win_append(oldwin, wp, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (new_wp == NULL) {
|
if (new_wp == NULL) {
|
||||||
wp = win_alloc(oldwin->w_prev, false);
|
wp = win_alloc(oldwin->w_prev, false);
|
||||||
} else {
|
} else {
|
||||||
win_append(oldwin->w_prev, wp);
|
win_append(oldwin->w_prev, wp, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1783,13 +1783,13 @@ static void win_exchange(int Prenum)
|
|||||||
if (wp->w_prev != curwin) {
|
if (wp->w_prev != curwin) {
|
||||||
win_remove(curwin, NULL);
|
win_remove(curwin, NULL);
|
||||||
frame_remove(curwin->w_frame);
|
frame_remove(curwin->w_frame);
|
||||||
win_append(wp->w_prev, curwin);
|
win_append(wp->w_prev, curwin, NULL);
|
||||||
frame_insert(frp, curwin->w_frame);
|
frame_insert(frp, curwin->w_frame);
|
||||||
}
|
}
|
||||||
if (wp != wp2) {
|
if (wp != wp2) {
|
||||||
win_remove(wp, NULL);
|
win_remove(wp, NULL);
|
||||||
frame_remove(wp->w_frame);
|
frame_remove(wp->w_frame);
|
||||||
win_append(wp2, wp);
|
win_append(wp2, wp, NULL);
|
||||||
if (frp2 == NULL) {
|
if (frp2 == NULL) {
|
||||||
frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
|
frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
|
||||||
} else {
|
} else {
|
||||||
@ -1863,7 +1863,7 @@ static void win_rotate(bool upwards, int count)
|
|||||||
|
|
||||||
// find last frame and append removed window/frame after it
|
// 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);
|
win_append(frp->fr_win, wp1, NULL);
|
||||||
frame_append(frp, wp1->w_frame);
|
frame_append(frp, wp1->w_frame);
|
||||||
|
|
||||||
wp2 = frp->fr_win; // previously last window
|
wp2 = frp->fr_win; // previously last window
|
||||||
@ -1878,7 +1878,7 @@ static void win_rotate(bool upwards, int count)
|
|||||||
assert(frp->fr_parent->fr_child);
|
assert(frp->fr_parent->fr_child);
|
||||||
|
|
||||||
// append the removed window/frame before the first in the list
|
// append the removed window/frame before the first in the list
|
||||||
win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
|
win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1, NULL);
|
||||||
frame_insert(frp->fr_parent->fr_child, frp);
|
frame_insert(frp->fr_parent->fr_child, frp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1937,7 +1937,7 @@ int win_splitmove(win_T *wp, int size, int flags)
|
|||||||
|
|
||||||
// Split a window on the desired side and put "wp" there.
|
// Split a window on the desired side and put "wp" there.
|
||||||
if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) {
|
if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) {
|
||||||
win_append(wp->w_prev, wp);
|
win_append(wp->w_prev, wp, NULL);
|
||||||
if (!wp->w_floating) {
|
if (!wp->w_floating) {
|
||||||
// win_split_ins doesn't change sizes or layout if it fails to insert an
|
// win_split_ins doesn't change sizes or layout if it fails to insert an
|
||||||
// existing window, so just undo winframe_remove.
|
// existing window, so just undo winframe_remove.
|
||||||
@ -2016,7 +2016,7 @@ void win_move_after(win_T *win1, win_T *win2)
|
|||||||
}
|
}
|
||||||
win_remove(win1, NULL);
|
win_remove(win1, NULL);
|
||||||
frame_remove(win1->w_frame);
|
frame_remove(win1->w_frame);
|
||||||
win_append(win2, win1);
|
win_append(win2, win1, NULL);
|
||||||
frame_append(win2->w_frame, win1->w_frame);
|
frame_append(win2->w_frame, win1->w_frame);
|
||||||
|
|
||||||
win_comp_pos(); // recompute w_winrow for all windows
|
win_comp_pos(); // recompute w_winrow for all windows
|
||||||
@ -3151,6 +3151,55 @@ void win_free_all(void)
|
|||||||
/// @return a pointer to the window that got the freed up space.
|
/// @return a pointer to the window that got the freed up space.
|
||||||
win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_altfr)
|
win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_altfr)
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||||
|
{
|
||||||
|
frame_T *altfr;
|
||||||
|
win_T *wp = winframe_find_altwin(win, dirp, tp, &altfr);
|
||||||
|
if (wp == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_T *frp_close = win->w_frame;
|
||||||
|
// Remove this frame from the list of frames.
|
||||||
|
frame_remove(frp_close);
|
||||||
|
|
||||||
|
if (*dirp == 'v') {
|
||||||
|
frame_new_height(altfr, altfr->fr_height + frp_close->fr_height,
|
||||||
|
altfr == frp_close->fr_next, false);
|
||||||
|
} else {
|
||||||
|
assert(*dirp == 'h');
|
||||||
|
frame_new_width(altfr, altfr->fr_width + frp_close->fr_width,
|
||||||
|
altfr == frp_close->fr_next, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If rows/columns go to a window below/right its positions need to be
|
||||||
|
// updated. Can only be done after the sizes have been updated.
|
||||||
|
if (altfr == frp_close->fr_next) {
|
||||||
|
int row = win->w_winrow;
|
||||||
|
int col = win->w_wincol;
|
||||||
|
|
||||||
|
frame_comp_pos(altfr, &row, &col);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unflat_altfr == NULL) {
|
||||||
|
frame_flatten(altfr);
|
||||||
|
} else {
|
||||||
|
*unflat_altfr = altfr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the window that will get the freed space from a call to `winframe_remove`.
|
||||||
|
/// Makes no changes to the window layout.
|
||||||
|
///
|
||||||
|
/// @param dirp set to 'v' or 'h' for the direction where "altfr" will be resized
|
||||||
|
/// to fill the space
|
||||||
|
/// @param tp tab page "win" is in, NULL for current
|
||||||
|
/// @param altfr if not NULL, set to pointer of frame that will get the space
|
||||||
|
///
|
||||||
|
/// @return a pointer to the window that will get the freed up space.
|
||||||
|
win_T *winframe_find_altwin(win_T *win, int *dirp, tabpage_T *tp, frame_T **altfr)
|
||||||
|
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||||
{
|
{
|
||||||
assert(tp == NULL || tp != curtab);
|
assert(tp == NULL || tp != curtab);
|
||||||
|
|
||||||
@ -3161,13 +3210,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al
|
|||||||
|
|
||||||
frame_T *frp_close = win->w_frame;
|
frame_T *frp_close = win->w_frame;
|
||||||
|
|
||||||
// Remove the window from its frame.
|
// Find the window and frame that gets the space.
|
||||||
frame_T *frp2 = win_altframe(win, tp);
|
frame_T *frp2 = win_altframe(win, tp);
|
||||||
win_T *wp = frame2win(frp2);
|
win_T *wp = frame2win(frp2);
|
||||||
|
|
||||||
// Remove this frame from the list of frames.
|
|
||||||
frame_remove(frp_close);
|
|
||||||
|
|
||||||
if (frp_close->fr_parent->fr_layout == FR_COL) {
|
if (frp_close->fr_parent->fr_layout == FR_COL) {
|
||||||
// When 'winfixheight' is set, try to find another frame in the column
|
// When 'winfixheight' is set, try to find another frame in the column
|
||||||
// (as close to the closed frame as possible) to distribute the height
|
// (as close to the closed frame as possible) to distribute the height
|
||||||
@ -3194,8 +3240,6 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
|
|
||||||
frp2 == frp_close->fr_next, false);
|
|
||||||
*dirp = 'v';
|
*dirp = 'v';
|
||||||
} else {
|
} else {
|
||||||
// When 'winfixwidth' is set, try to find another frame in the column
|
// When 'winfixwidth' is set, try to find another frame in the column
|
||||||
@ -3223,24 +3267,12 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
|
|
||||||
frp2 == frp_close->fr_next, false);
|
|
||||||
*dirp = 'h';
|
*dirp = 'h';
|
||||||
}
|
}
|
||||||
|
|
||||||
// If rows/columns go to a window below/right its positions need to be
|
assert(wp != win && frp2 != frp_close);
|
||||||
// updated. Can only be done after the sizes have been updated.
|
if (altfr != NULL) {
|
||||||
if (frp2 == frp_close->fr_next) {
|
*altfr = frp2;
|
||||||
int row = win->w_winrow;
|
|
||||||
int col = win->w_wincol;
|
|
||||||
|
|
||||||
frame_comp_pos(frp2, &row, &col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unflat_altfr == NULL) {
|
|
||||||
frame_flatten(frp2);
|
|
||||||
} else {
|
|
||||||
*unflat_altfr = frp2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wp;
|
return wp;
|
||||||
@ -3305,9 +3337,10 @@ static void frame_flatten(frame_T *frp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Undo changes from a prior call to winframe_remove, also restoring lost
|
/// Undo changes from a prior call to winframe_remove, also restoring lost
|
||||||
/// vertical separators and statuslines.
|
/// vertical separators and statuslines, and changed window positions for
|
||||||
|
/// windows within "unflat_altfr".
|
||||||
/// Caller must ensure no other changes were made to the layout or window sizes!
|
/// Caller must ensure no other changes were made to the layout or window sizes!
|
||||||
static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr)
|
void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
frame_T *frp = wp->w_frame;
|
frame_T *frp = wp->w_frame;
|
||||||
@ -3333,13 +3366,24 @@ static void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int row = wp->w_winrow;
|
||||||
|
int col = wp->w_wincol;
|
||||||
|
|
||||||
// Restore the lost room that was redistributed to the altframe.
|
// Restore the lost room that was redistributed to the altframe.
|
||||||
if (dir == 'v') {
|
if (dir == 'v') {
|
||||||
frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height,
|
frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height,
|
||||||
unflat_altfr == frp->fr_next, false);
|
unflat_altfr == frp->fr_next, false);
|
||||||
|
row += frp->fr_height;
|
||||||
} else if (dir == 'h') {
|
} else if (dir == 'h') {
|
||||||
frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width,
|
frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width,
|
||||||
unflat_altfr == frp->fr_next, false);
|
unflat_altfr == frp->fr_next, false);
|
||||||
|
col += frp->fr_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If rows/columns went to a window below/right, its positions need to be
|
||||||
|
// restored. Can only be done after the sizes have been updated.
|
||||||
|
if (unflat_altfr == frp->fr_next) {
|
||||||
|
frame_comp_pos(unflat_altfr, &row, &col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4445,7 +4489,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab)
|
|||||||
if (wp->w_floating) {
|
if (wp->w_floating) {
|
||||||
if (wp->w_config.external) {
|
if (wp->w_config.external) {
|
||||||
win_remove(wp, old_curtab);
|
win_remove(wp, old_curtab);
|
||||||
win_append(lastwin_nofloating(), wp);
|
win_append(lastwin_nofloating(), wp, NULL);
|
||||||
} else {
|
} else {
|
||||||
ui_comp_remove_grid(&wp->w_grid_alloc);
|
ui_comp_remove_grid(&wp->w_grid_alloc);
|
||||||
}
|
}
|
||||||
@ -5085,7 +5129,7 @@ win_T *win_alloc(win_T *after, bool hidden)
|
|||||||
block_autocmds();
|
block_autocmds();
|
||||||
// link the window in the window list
|
// link the window in the window list
|
||||||
if (!hidden) {
|
if (!hidden) {
|
||||||
win_append(after, new_wp);
|
win_append(after, new_wp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_wp->w_wincol = 0;
|
new_wp->w_wincol = 0;
|
||||||
@ -5255,21 +5299,29 @@ void win_free_grid(win_T *wp, bool reinit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append window "wp" in the window list after window "after".
|
/// Append window "wp" in the window list after window "after".
|
||||||
void win_append(win_T *after, win_T *wp)
|
///
|
||||||
|
/// @param tp tab page "win" (and "after", if not NULL) is in, NULL for current
|
||||||
|
void win_append(win_T *after, win_T *wp, tabpage_T *tp)
|
||||||
|
FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
|
assert(tp == NULL || tp != curtab);
|
||||||
|
|
||||||
|
win_T **first = tp == NULL ? &firstwin : &tp->tp_firstwin;
|
||||||
|
win_T **last = tp == NULL ? &lastwin : &tp->tp_lastwin;
|
||||||
|
|
||||||
// after NULL is in front of the first
|
// after NULL is in front of the first
|
||||||
win_T *before = after == NULL ? firstwin : after->w_next;
|
win_T *before = after == NULL ? *first : after->w_next;
|
||||||
|
|
||||||
wp->w_next = before;
|
wp->w_next = before;
|
||||||
wp->w_prev = after;
|
wp->w_prev = after;
|
||||||
if (after == NULL) {
|
if (after == NULL) {
|
||||||
firstwin = wp;
|
*first = wp;
|
||||||
} else {
|
} else {
|
||||||
after->w_next = wp;
|
after->w_next = wp;
|
||||||
}
|
}
|
||||||
if (before == NULL) {
|
if (before == NULL) {
|
||||||
lastwin = wp;
|
*last = wp;
|
||||||
} else {
|
} else {
|
||||||
before->w_prev = wp;
|
before->w_prev = wp;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|
|||||||
XFREE_CLEAR(wp->w_frame);
|
XFREE_CLEAR(wp->w_frame);
|
||||||
win_comp_pos(); // recompute window positions
|
win_comp_pos(); // recompute window positions
|
||||||
win_remove(wp, NULL);
|
win_remove(wp, NULL);
|
||||||
win_append(lastwin_nofloating(), wp);
|
win_append(lastwin_nofloating(), wp, NULL);
|
||||||
}
|
}
|
||||||
wp->w_floating = true;
|
wp->w_floating = true;
|
||||||
wp->w_status_height = 0;
|
wp->w_status_height = 0;
|
||||||
|
@ -1654,6 +1654,18 @@ describe('API/win', function()
|
|||||||
api.nvim_open_win(new_buf, false, { split = 'left' })
|
api.nvim_open_win(new_buf, false, { split = 'left' })
|
||||||
eq('foobarbaz', eval('triggered'))
|
eq('foobarbaz', eval('triggered'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('sets error when no room', function()
|
||||||
|
matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_open_win, 0, true, { split = 'above', win = 0 })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_open_win, 0, true, { split = 'below', win = 0 })
|
||||||
|
)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set_config', function()
|
describe('set_config', function()
|
||||||
@ -1965,23 +1977,89 @@ describe('API/win', function()
|
|||||||
|
|
||||||
it('closing new curwin when moving window to other tabpage works', function()
|
it('closing new curwin when moving window to other tabpage works', function()
|
||||||
command('split | tabnew')
|
command('split | tabnew')
|
||||||
local w = api.nvim_get_current_win()
|
local t2_win = api.nvim_get_current_win()
|
||||||
local t = api.nvim_get_current_tabpage()
|
command('tabfirst | autocmd WinEnter * ++once quit')
|
||||||
command('tabfirst | autocmd WinEnter * quit')
|
local t1_move_win = api.nvim_get_current_win()
|
||||||
api.nvim_win_set_config(0, { win = w, split = 'left' })
|
-- win_set_config fails to switch away from "t1_move_win" because the WinEnter autocmd that
|
||||||
-- New tabpage is now the only one, as WinEnter closed the new curwin in the original.
|
-- closed the window we're switched to returns us to "t1_move_win", as it filled the space.
|
||||||
eq(t, api.nvim_get_current_tabpage())
|
eq(
|
||||||
eq({ t }, api.nvim_list_tabpages())
|
'Failed to switch away from window ' .. t1_move_win,
|
||||||
|
pcall_err(api.nvim_win_set_config, t1_move_win, { win = t2_win, split = 'left' })
|
||||||
|
)
|
||||||
|
eq(t1_move_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
command('split | split | autocmd WinEnter * ++once quit')
|
||||||
|
t1_move_win = api.nvim_get_current_win()
|
||||||
|
-- In this case, we closed the window that we got switched to, but doing so didn't switch us
|
||||||
|
-- back to "t1_move_win", which is fine.
|
||||||
|
api.nvim_win_set_config(t1_move_win, { win = t2_win, split = 'left' })
|
||||||
|
neq(t1_move_win, api.nvim_get_current_win())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('closing split parent when moving window to other tabpage aborts', function()
|
it('messing with "win" or "parent" when moving "win" to other tabpage', function()
|
||||||
command('split | tabnew')
|
command('split | tabnew')
|
||||||
local w = api.nvim_get_current_win()
|
local t2 = api.nvim_get_current_tabpage()
|
||||||
command('tabfirst | autocmd WinEnter * call nvim_win_close(' .. w .. ', 1)')
|
local t2_win1 = api.nvim_get_current_win()
|
||||||
|
command('split')
|
||||||
|
local t2_win2 = api.nvim_get_current_win()
|
||||||
|
command('split')
|
||||||
|
local t2_win3 = api.nvim_get_current_win()
|
||||||
|
|
||||||
|
command('tabfirst | autocmd WinEnter * ++once call nvim_win_close(' .. t2_win1 .. ', 1)')
|
||||||
|
local cur_win = api.nvim_get_current_win()
|
||||||
eq(
|
eq(
|
||||||
'Window to split was closed',
|
'Windows to split were closed',
|
||||||
pcall_err(api.nvim_win_set_config, 0, { win = w, split = 'left' })
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_win1, split = 'left' })
|
||||||
)
|
)
|
||||||
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
command('split | autocmd WinLeave * ++once quit!')
|
||||||
|
cur_win = api.nvim_get_current_win()
|
||||||
|
eq(
|
||||||
|
'Windows to split were closed',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_win2, split = 'left' })
|
||||||
|
)
|
||||||
|
neq(cur_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
exec([[
|
||||||
|
split
|
||||||
|
autocmd WinLeave * ++once
|
||||||
|
\ call nvim_win_set_config(0, #{relative:'editor', row:0, col:0, width:5, height:5})
|
||||||
|
]])
|
||||||
|
cur_win = api.nvim_get_current_win()
|
||||||
|
eq(
|
||||||
|
'Floating state of windows to split changed',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' })
|
||||||
|
)
|
||||||
|
eq('editor', api.nvim_win_get_config(0).relative)
|
||||||
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
command('autocmd WinLeave * ++once wincmd J')
|
||||||
|
cur_win = api.nvim_get_current_win()
|
||||||
|
eq(
|
||||||
|
'Floating state of windows to split changed',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' })
|
||||||
|
)
|
||||||
|
eq('', api.nvim_win_get_config(0).relative)
|
||||||
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
-- Try to make "parent" floating. This should give the same error as before, but because
|
||||||
|
-- changing a split from another tabpage into a float isn't supported yet, check for that
|
||||||
|
-- error instead for now.
|
||||||
|
-- Use ":silent!" to avoid the one second delay from printing the error message.
|
||||||
|
exec(([[
|
||||||
|
autocmd WinLeave * ++once silent!
|
||||||
|
\ call nvim_win_set_config(%d, #{relative:'editor', row:0, col:0, width:5, height:5})
|
||||||
|
]]):format(t2_win3))
|
||||||
|
cur_win = api.nvim_get_current_win()
|
||||||
|
api.nvim_win_set_config(0, { win = t2_win3, split = 'left' })
|
||||||
|
matches(
|
||||||
|
'Cannot change window from different tabpage into float$',
|
||||||
|
api.nvim_get_vvar('errmsg')
|
||||||
|
)
|
||||||
|
-- The error doesn't abort moving the window (or maybe it should, if that's wanted?)
|
||||||
|
neq(cur_win, api.nvim_get_current_win())
|
||||||
|
eq(t2, api.nvim_win_get_tabpage(cur_win))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('expected autocmds when moving window to other tabpage', function()
|
it('expected autocmds when moving window to other tabpage', function()
|
||||||
@ -2031,6 +2109,223 @@ describe('API/win', function()
|
|||||||
command('autocmd BufHidden * ++once call nvim_win_set_config(' .. w .. ', #{split: "left"})')
|
command('autocmd BufHidden * ++once call nvim_win_set_config(' .. w .. ', #{split: "left"})')
|
||||||
command('new | quit')
|
command('new | quit')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--- Returns a function to get information about the window layout, sizes and positions of a
|
||||||
|
--- tabpage.
|
||||||
|
local function define_tp_info_function()
|
||||||
|
exec_lua([[
|
||||||
|
function tp_info(tp)
|
||||||
|
return {
|
||||||
|
layout = vim.fn.winlayout(vim.api.nvim_tabpage_get_number(tp)),
|
||||||
|
pos_sizes = vim.tbl_map(
|
||||||
|
function(w)
|
||||||
|
local pos = vim.fn.win_screenpos(w)
|
||||||
|
return {
|
||||||
|
row = pos[1],
|
||||||
|
col = pos[2],
|
||||||
|
width = vim.fn.winwidth(w),
|
||||||
|
height = vim.fn.winheight(w)
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
vim.api.nvim_tabpage_list_wins(tp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
]])
|
||||||
|
|
||||||
|
return function(tp)
|
||||||
|
return exec_lua('return tp_info(...)', tp)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it('attempt to move window with no room', function()
|
||||||
|
-- Fill the 2nd tabpage full of windows until we run out of room.
|
||||||
|
-- Use &laststatus=0 to ensure restoring missing statuslines doesn't affect things.
|
||||||
|
command('set laststatus=0 | tabnew')
|
||||||
|
matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
|
||||||
|
command('vsplit | wincmd | | wincmd p')
|
||||||
|
local t2 = api.nvim_get_current_tabpage()
|
||||||
|
local t2_cur_win = api.nvim_get_current_win()
|
||||||
|
local t2_top_split = fn.win_getid(1)
|
||||||
|
local t2_bot_split = fn.win_getid(fn.winnr('$'))
|
||||||
|
local t2_float = api.nvim_open_win(
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
{ relative = 'editor', row = 0, col = 0, width = 10, height = 10 }
|
||||||
|
)
|
||||||
|
local t2_float_config = api.nvim_win_get_config(t2_float)
|
||||||
|
local tp_info = define_tp_info_function()
|
||||||
|
local t2_info = tp_info(t2)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t2_float, { win = t2_top_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t2_float, { win = t2_top_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t2_float, { win = t2_bot_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t2_float, { win = t2_bot_split, split = 'below' })
|
||||||
|
)
|
||||||
|
eq(t2_cur_win, api.nvim_get_current_win())
|
||||||
|
eq(t2_info, tp_info(t2))
|
||||||
|
eq(t2_float_config, api.nvim_win_get_config(t2_float))
|
||||||
|
|
||||||
|
-- Try to move windows from the 1st tabpage to the 2nd.
|
||||||
|
command('tabfirst | split | wincmd _')
|
||||||
|
local t1 = api.nvim_get_current_tabpage()
|
||||||
|
local t1_cur_win = api.nvim_get_current_win()
|
||||||
|
local t1_float = api.nvim_open_win(
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
{ relative = 'editor', row = 5, col = 3, width = 7, height = 6 }
|
||||||
|
)
|
||||||
|
local t1_float_config = api.nvim_win_get_config(t1_float)
|
||||||
|
local t1_info = tp_info(t1)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t1_float, { win = t2_top_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t1_float, { win = t2_top_split, split = 'below' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t1_float, { win = t2_bot_split, split = 'above' })
|
||||||
|
)
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, t1_float, { win = t2_bot_split, split = 'below' })
|
||||||
|
)
|
||||||
|
eq(t1_cur_win, api.nvim_get_current_win())
|
||||||
|
eq(t1_info, tp_info(t1))
|
||||||
|
eq(t1_float_config, api.nvim_win_get_config(t1_float))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('attempt to move window from other tabpage with no room', function()
|
||||||
|
-- Fill up the 1st tabpage with horizontal splits, then create a 2nd with only a few. Go back
|
||||||
|
-- to the 1st and try to move windows from the 2nd (while it's non-current) to it. Check that
|
||||||
|
-- window positions and sizes in the 2nd are unchanged.
|
||||||
|
command('set laststatus=0')
|
||||||
|
matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
|
||||||
|
|
||||||
|
command('tab split')
|
||||||
|
local t2 = api.nvim_get_current_tabpage()
|
||||||
|
local t2_top = api.nvim_get_current_win()
|
||||||
|
command('belowright split')
|
||||||
|
local t2_mid_left = api.nvim_get_current_win()
|
||||||
|
command('belowright vsplit')
|
||||||
|
local t2_mid_right = api.nvim_get_current_win()
|
||||||
|
command('split | wincmd J')
|
||||||
|
local t2_bot = api.nvim_get_current_win()
|
||||||
|
local tp_info = define_tp_info_function()
|
||||||
|
local t2_info = tp_info(t2)
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', t2_top },
|
||||||
|
{
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', t2_mid_left },
|
||||||
|
{ 'leaf', t2_mid_right },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ 'leaf', t2_bot },
|
||||||
|
},
|
||||||
|
}, t2_info.layout)
|
||||||
|
|
||||||
|
local function try_move_t2_wins_to_t1()
|
||||||
|
for _, w in ipairs({ t2_bot, t2_mid_left, t2_mid_right, t2_top }) do
|
||||||
|
matches(
|
||||||
|
'E36: Not enough room$',
|
||||||
|
pcall_err(api.nvim_win_set_config, w, { win = 0, split = 'below' })
|
||||||
|
)
|
||||||
|
eq(t2_info, tp_info(t2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
command('tabfirst')
|
||||||
|
try_move_t2_wins_to_t1()
|
||||||
|
-- Go to the 2nd tabpage to ensure nothing changes after win_comp_pos, last_status, .etc.
|
||||||
|
-- from enter_tabpage.
|
||||||
|
command('tabnext')
|
||||||
|
eq(t2_info, tp_info(t2))
|
||||||
|
|
||||||
|
-- Check things are fine with the global statusline too, for good measure.
|
||||||
|
-- Set it while the 2nd tabpage is current, so last_status runs for it.
|
||||||
|
command('set laststatus=3')
|
||||||
|
t2_info = tp_info(t2)
|
||||||
|
command('tabfirst')
|
||||||
|
try_move_t2_wins_to_t1()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('does not switch window when textlocked or in the cmdwin', function()
|
||||||
|
command('tabnew')
|
||||||
|
local t2_win = api.nvim_get_current_win()
|
||||||
|
command('tabfirst')
|
||||||
|
feed('q:')
|
||||||
|
local cur_win = api.nvim_get_current_win()
|
||||||
|
eq(
|
||||||
|
'Failed to switch away from window ' .. cur_win,
|
||||||
|
pcall_err(api.nvim_win_set_config, 0, { split = 'left', win = t2_win })
|
||||||
|
)
|
||||||
|
eq(
|
||||||
|
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
|
||||||
|
api.nvim_get_vvar('errmsg')
|
||||||
|
)
|
||||||
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
command('quit!')
|
||||||
|
|
||||||
|
exec(([[
|
||||||
|
new
|
||||||
|
call setline(1, 'foo')
|
||||||
|
setlocal debug=throw indentexpr=nvim_win_set_config(0,#{split:'left',win:%d})
|
||||||
|
]]):format(t2_win))
|
||||||
|
cur_win = api.nvim_get_current_win()
|
||||||
|
matches(
|
||||||
|
'E565: Not allowed to change text or change window$',
|
||||||
|
pcall_err(command, 'normal! ==')
|
||||||
|
)
|
||||||
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('get_config', function()
|
describe('get_config', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user