mirror of
https://github.com/neovim/neovim.git
synced 2026-04-25 00:35:36 +00:00
feat(api): nvim_win_set_config can move split to other tp as floatwin
Problem: not possible for nvim_win_set_config to convert a split to a floatwin, then move it to another tabpage in one call. Solution: allow it.
This commit is contained in:
@@ -167,7 +167,7 @@ API
|
|||||||
they were so specified in `nvim_create_user_command()`.
|
they were so specified in `nvim_create_user_command()`.
|
||||||
• |nvim_open_win()| floating windows can show a 'statusline'. Plugins can use
|
• |nvim_open_win()| floating windows can show a 'statusline'. Plugins can use
|
||||||
`style='minimal'` or `:setlocal statusline=` to hide the statusline.
|
`style='minimal'` or `:setlocal statusline=` to hide the statusline.
|
||||||
• |nvim_win_set_config()| can move floating windows to other tab pages.
|
• |nvim_win_set_config()| can move windows to other tab pages as floats.
|
||||||
• Added experimental |nvim__exec_lua_fast()| to allow remote API clients to
|
• Added experimental |nvim__exec_lua_fast()| to allow remote API clients to
|
||||||
execute code while nvim is blocking for input.
|
execute code while nvim is blocking for input.
|
||||||
• |vim.secure.trust()| accepts `path` for the `allow` action.
|
• |vim.secure.trust()| accepts `path` for the `allow` action.
|
||||||
|
|||||||
@@ -384,9 +384,13 @@ static int win_split_flags(WinSplit split, bool toplevel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if window `wp` can be moved to tabpage `tp`.
|
/// Checks if window `wp` can be moved to tabpage `tp`.
|
||||||
static bool win_can_move_tp(win_T *wp, Error *err)
|
static bool win_can_move_tp(win_T *wp, tabpage_T *tp, Error *err)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
if (one_window(wp, tp == curtab ? NULL : tp)) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Cannot move last non-floating window");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (is_aucmd_win(wp)) {
|
if (is_aucmd_win(wp)) {
|
||||||
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
|
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
|
||||||
return false;
|
return false;
|
||||||
@@ -403,6 +407,17 @@ static bool win_can_move_tp(win_T *wp, Error *err)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static win_T *win_find_altwin(win_T *win, tabpage_T *tp)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
if (win->w_floating) {
|
||||||
|
return win_float_find_altwin(win, tp == curtab ? NULL : tp);
|
||||||
|
} else {
|
||||||
|
int dir;
|
||||||
|
return winframe_find_altwin(win, &dir, tp == curtab ? NULL : tp, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configures `win` into a split, also moving it to another tabpage if requested.
|
/// Configures `win` into a split, also moving it to another tabpage if requested.
|
||||||
static bool win_config_split(win_T *win, const Dict(win_config) *config, WinConfig *fconfig,
|
static bool win_config_split(win_T *win, const Dict(win_config) *config, WinConfig *fconfig,
|
||||||
Error *err)
|
Error *err)
|
||||||
@@ -446,7 +461,7 @@ static bool win_config_split(win_T *win, const Dict(win_config) *config, WinConf
|
|||||||
api_set_error(err, kErrorTypeException, "Cannot split a floating window");
|
api_set_error(err, kErrorTypeException, "Cannot split a floating window");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (win_tp != parent_tp && !win_can_move_tp(win, err)) {
|
if (win_tp != parent_tp && !win_can_move_tp(win, win_tp, err)) {
|
||||||
return false; // error already set
|
return false; // error already set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,19 +475,9 @@ static bool win_config_split(win_T *win, const Dict(win_config) *config, WinConf
|
|||||||
// window list or remove its frame (if non-floating), so it's valid for autocommands.
|
// window list or remove its frame (if non-floating), so it's valid for autocommands.
|
||||||
const bool curwin_moving_tp = win == curwin && parent && win_tp != parent_tp;
|
const bool curwin_moving_tp = win == curwin && parent && win_tp != parent_tp;
|
||||||
if (curwin_moving_tp) {
|
if (curwin_moving_tp) {
|
||||||
if (was_split) {
|
win_T *altwin = win_find_altwin(win, win_tp);
|
||||||
int dir;
|
assert(altwin); // win_can_move_tp ensures `win` is not the only window
|
||||||
win_T *altwin = winframe_find_altwin(win, &dir, NULL, NULL);
|
win_goto(altwin);
|
||||||
// Autocommands may still make this the last non-float after this check.
|
|
||||||
// That case will be caught later when trying to move the window.
|
|
||||||
if (!altwin) {
|
|
||||||
api_set_error(err, kErrorTypeException, "Cannot move last non-floating window");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
win_goto(altwin);
|
|
||||||
} else {
|
|
||||||
win_goto(win_float_find_altwin(win, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Autocommands may have been a real nuisance and messed things up...
|
// Autocommands may have been a real nuisance and messed things up...
|
||||||
if (curwin == win) {
|
if (curwin == win) {
|
||||||
@@ -642,12 +647,21 @@ static bool win_config_float_tp(win_T *win, const Dict(win_config) *config,
|
|||||||
parent_tp = win_find_tabpage(parent);
|
parent_tp = win_find_tabpage(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool curwin_moving_tp = false;
|
||||||
|
win_T *altwin = NULL;
|
||||||
|
|
||||||
if (win_tp != parent_tp) {
|
if (win_tp != parent_tp) {
|
||||||
if (!win_can_move_tp(win, err)) {
|
if (!win_can_move_tp(win, win_tp, err)) {
|
||||||
return false; // error already set
|
return false; // error already set
|
||||||
}
|
}
|
||||||
|
altwin = win_find_altwin(win, win_tp);
|
||||||
|
assert(altwin); // win_can_move_tp ensures `win` is not the only window
|
||||||
|
|
||||||
|
// 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.
|
||||||
if (curwin == win) {
|
if (curwin == win) {
|
||||||
win_goto(win_float_find_altwin(win, NULL));
|
curwin_moving_tp = true;
|
||||||
|
win_goto(altwin);
|
||||||
|
|
||||||
// Autocommands may have been a real nuisance and messed things up...
|
// Autocommands may have been a real nuisance and messed things up...
|
||||||
if (curwin == win) {
|
if (curwin == win) {
|
||||||
@@ -658,47 +672,51 @@ static bool win_config_float_tp(win_T *win, const Dict(win_config) *config,
|
|||||||
win_tp = win_find_tabpage(win);
|
win_tp = win_find_tabpage(win);
|
||||||
parent_tp = win_find_tabpage(parent);
|
parent_tp = win_find_tabpage(parent);
|
||||||
|
|
||||||
bool restore_curwin = false;
|
|
||||||
if (!win_tp || !parent_tp) {
|
if (!win_tp || !parent_tp) {
|
||||||
api_set_error(err, kErrorTypeException, "Target windows were closed");
|
api_set_error(err, kErrorTypeException, "Target windows were closed");
|
||||||
restore_curwin = true;
|
goto restore_curwin;
|
||||||
} else if (!win->w_floating) {
|
|
||||||
api_set_error(err, kErrorTypeException, "Window %d was made non-floating", win->handle);
|
|
||||||
restore_curwin = true;
|
|
||||||
} else if (win_tp != parent_tp && !win_can_move_tp(win, err)) {
|
|
||||||
restore_curwin = true; // error already set
|
|
||||||
}
|
}
|
||||||
if (restore_curwin) {
|
if (win_tp != parent_tp && !win_can_move_tp(win, win_tp, err)) {
|
||||||
// As `win` was the original curwin, and autocommands didn't move it outside of curtab, be
|
goto restore_curwin; // error already set
|
||||||
// a good citizen and try to return to it.
|
|
||||||
if (win_valid(win)) {
|
|
||||||
win_goto(win);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
altwin = win_find_altwin(win, win_tp);
|
||||||
|
assert(altwin); // win_can_move_tp ensures `win` is not the only window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the window to a float if needed.
|
||||||
|
if (!win->w_floating) {
|
||||||
|
if (!win_new_float(win, false, *fconfig, err)) {
|
||||||
|
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 false;
|
||||||
|
}
|
||||||
|
redraw_later(win, UPD_NOT_VALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (win_tp != parent_tp) {
|
||||||
|
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
||||||
|
tabpage_T *append_tp = parent_tp == curtab ? NULL : parent_tp;
|
||||||
|
win_append(lastwin_nofloating(append_tp), win, append_tp);
|
||||||
|
|
||||||
|
// If `win` was the curwin of its old tabpage, select a new curwin for it.
|
||||||
|
if (win_tp != curtab && win_tp->tp_curwin == win) {
|
||||||
|
win_tp->tp_curwin = altwin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check again, in case autocommands above moved windows to the same tabpage.
|
// Remove grid if present. More reliable than checking curtab, as tabpage_check_windows may not
|
||||||
if (win_tp != parent_tp) {
|
// run when temporarily switching tabpages, meaning grids may be stale from another tabpage!
|
||||||
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
// (e.g: switch_win_noblock with no_display=true)
|
||||||
tabpage_T *append_tp = parent_tp == curtab ? NULL : parent_tp;
|
ui_comp_remove_grid(&win->w_grid_alloc);
|
||||||
win_append(lastwin_nofloating(append_tp), win, append_tp);
|
|
||||||
|
|
||||||
// If `win` was the curwin of its old tabpage, select a new curwin for it.
|
// Redraw tabline, update window's hl attribs, etc. Set must_redraw here, as redraw_later might
|
||||||
if (win_tp != curtab && win_tp->tp_curwin == win) {
|
// not if w_redr_type >= UPD_NOT_VALID was set in the old tabpage.
|
||||||
win_tp->tp_curwin = win_float_find_altwin(win, win_tp);
|
redraw_later(win, UPD_NOT_VALID);
|
||||||
}
|
set_must_redraw(UPD_NOT_VALID);
|
||||||
|
|
||||||
// Remove grid if present. More reliable than checking curtab, as tabpage_check_windows may
|
|
||||||
// not run when temporarily switching tabpages, meaning grids may be stale from another
|
|
||||||
// tabpage! (e.g: switch_win_noblock with no_display=true)
|
|
||||||
ui_comp_remove_grid(&win->w_grid_alloc);
|
|
||||||
|
|
||||||
// Redraw tabline, update window's hl attribs, etc. Set must_redraw here, as redraw_later
|
|
||||||
// might not if w_redr_type >= UPD_NOT_VALID was set in the old tabpage.
|
|
||||||
redraw_later(win, UPD_NOT_VALID);
|
|
||||||
set_must_redraw(UPD_NOT_VALID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
win_config_float(win, *fconfig);
|
win_config_float(win, *fconfig);
|
||||||
@@ -745,27 +763,11 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (was_split && !to_split) {
|
if (to_split) {
|
||||||
win_T *parent = find_window_by_handle(fconfig.window, err);
|
|
||||||
if (!parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO(seandewar): support this, preferably via win_config_float_tp.
|
|
||||||
if (!win_valid(parent)) {
|
|
||||||
api_set_error(err, kErrorTypeValidation,
|
|
||||||
"Cannot configure split into float in another tabpage");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!win_new_float(win, false, fconfig, err)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
redraw_later(win, UPD_NOT_VALID);
|
|
||||||
} else if (to_split) {
|
|
||||||
if (!win_config_split(win, config, &fconfig, err)) {
|
if (!win_config_split(win, config, &fconfig, err)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(!was_split);
|
|
||||||
if (!win_config_float_tp(win, config, &fconfig, err)) {
|
if (!win_config_float_tp(win, config, &fconfig, err)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,9 @@
|
|||||||
|
|
||||||
#include "winfloat.c.generated.h"
|
#include "winfloat.c.generated.h"
|
||||||
|
|
||||||
/// Create a new float.
|
/// Creates a new float, or transforms an existing window to a float.
|
||||||
///
|
///
|
||||||
/// @param wp if NULL, allocate a new window, otherwise turn existing window into a float.
|
/// @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.
|
/// @param last make the window the last one in the window list.
|
||||||
/// Only used when allocating the autocommand window.
|
/// Only used when allocating the autocommand window.
|
||||||
/// @param config must already have been validated!
|
/// @param config must already have been validated!
|
||||||
@@ -74,19 +73,19 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|
|||||||
} else {
|
} else {
|
||||||
assert(!last);
|
assert(!last);
|
||||||
assert(!wp->w_floating);
|
assert(!wp->w_floating);
|
||||||
if (firstwin == wp && lastwin_nofloating(NULL) == wp) {
|
tabpage_T *win_tp = win_find_tabpage(wp);
|
||||||
// last non-float
|
assert(win_tp);
|
||||||
api_set_error(err, kErrorTypeException,
|
if ((win_tp == curtab && firstwin == wp && lastwin_nofloating(NULL) == wp)
|
||||||
"Cannot change last window into float");
|
|| (win_tp != curtab && win_tp->tp_firstwin == wp && lastwin_nofloating(win_tp) == wp)) {
|
||||||
return NULL;
|
api_set_error(err, kErrorTypeException, "Cannot change last window into float");
|
||||||
} else if (!win_valid(wp)) {
|
|
||||||
api_set_error(err, kErrorTypeException,
|
|
||||||
"Cannot change window from different tabpage into float");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
|
} else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
|
||||||
// cmdwin can't become the only non-float. Check for others.
|
// cmdwin can't become the only non-float. Check for others.
|
||||||
bool other_nonfloat = false;
|
bool other_nonfloat = false;
|
||||||
for (win_T *wp2 = firstwin; wp2 != NULL && !wp2->w_floating; wp2 = wp2->w_next) {
|
FOR_ALL_WINDOWS_IN_TAB(wp2, win_tp) {
|
||||||
|
if (wp2->w_floating) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (wp2 != wp && wp2 != cmdwin_win) {
|
if (wp2 != wp && wp2 != cmdwin_win) {
|
||||||
other_nonfloat = true;
|
other_nonfloat = true;
|
||||||
break;
|
break;
|
||||||
@@ -97,13 +96,16 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tabpage_T *tp = win_tp == curtab ? NULL : win_tp;
|
||||||
int dir;
|
int dir;
|
||||||
winframe_remove(wp, &dir, NULL, NULL);
|
winframe_remove(wp, &dir, tp, NULL);
|
||||||
XFREE_CLEAR(wp->w_frame);
|
XFREE_CLEAR(wp->w_frame);
|
||||||
win_remove(wp, NULL);
|
win_remove(wp, tp);
|
||||||
last_status(false); // may need to remove last status line
|
if (win_tp == curtab) {
|
||||||
win_comp_pos(); // recompute window positions
|
last_status(false); // may need to remove last status line
|
||||||
win_append(lastwin_nofloating(NULL), wp, NULL);
|
win_comp_pos(); // recompute window positions
|
||||||
|
}
|
||||||
|
win_append(lastwin_nofloating(tp), wp, tp);
|
||||||
}
|
}
|
||||||
wp->w_floating = true;
|
wp->w_floating = true;
|
||||||
wp->w_status_height = wp->w_p_stl && *wp->w_p_stl != NUL
|
wp->w_status_height = wp->w_p_stl && *wp->w_p_stl != NUL
|
||||||
|
|||||||
@@ -2585,15 +2585,17 @@ describe('API/win', function()
|
|||||||
},
|
},
|
||||||
}, layout)
|
}, layout)
|
||||||
|
|
||||||
-- converting split into a float for a different tabpage is not yet supported
|
-- directly convert split into a float for a different tabpage
|
||||||
eq(
|
local win2 = api.nvim_open_win(0, true, { split = 'below' })
|
||||||
'Cannot configure split into float in another tabpage',
|
eq('', api.nvim_win_get_config(win2).relative)
|
||||||
pcall_err(
|
api.nvim_win_set_config(
|
||||||
api.nvim_win_set_config,
|
win2,
|
||||||
win,
|
{ relative = 'editor', row = 0, col = 0, width = 1, height = 1, win = first_win }
|
||||||
{ relative = 'editor', row = 0, col = 0, width = 1, height = 1, win = first_win }
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
eq(first_tab, api.nvim_win_get_tabpage(win2))
|
||||||
|
eq('editor', api.nvim_win_get_config(win2).relative)
|
||||||
|
eq({ first_win, win2 }, api.nvim_tabpage_list_wins(first_tab))
|
||||||
|
eq({ tab2_win, win }, api.nvim_tabpage_list_wins(new_tab))
|
||||||
|
|
||||||
-- convert new win to float in new tabpage
|
-- convert new win to float in new tabpage
|
||||||
api.nvim_win_set_config(win, { relative = 'editor', row = 2, col = 2, height = 2, width = 2 })
|
api.nvim_win_set_config(win, { relative = 'editor', row = 2, col = 2, height = 2, width = 2 })
|
||||||
@@ -2601,10 +2603,23 @@ describe('API/win', function()
|
|||||||
-- move to other tabpage
|
-- move to other tabpage
|
||||||
api.nvim_win_set_config(win, { win = first_win })
|
api.nvim_win_set_config(win, { win = first_win })
|
||||||
eq(first_tab, api.nvim_win_get_tabpage(win))
|
eq(first_tab, api.nvim_win_get_tabpage(win))
|
||||||
eq({ first_win, win }, api.nvim_tabpage_list_wins(first_tab))
|
eq({ first_win, win, win2 }, api.nvim_tabpage_list_wins(first_tab))
|
||||||
eq({ tab2_win }, api.nvim_tabpage_list_wins(new_tab))
|
eq({ tab2_win }, api.nvim_tabpage_list_wins(new_tab))
|
||||||
-- unlike splits, negative win is invalid
|
-- unlike splits, negative win is invalid
|
||||||
eq('Invalid window id: -1', pcall_err(api.nvim_win_set_config, win, { win = -1 }))
|
eq('Invalid window id: -1', pcall_err(api.nvim_win_set_config, win, { win = -1 }))
|
||||||
|
|
||||||
|
-- can't convert only window in other tabpage to float
|
||||||
|
command('tabnew')
|
||||||
|
local only_win = api.nvim_get_current_win()
|
||||||
|
command('tabprevious')
|
||||||
|
eq(
|
||||||
|
'Cannot change last window into float',
|
||||||
|
pcall_err(
|
||||||
|
api.nvim_win_set_config,
|
||||||
|
only_win,
|
||||||
|
{ relative = 'editor', width = 5, height = 5, row = 0, col = 0 }
|
||||||
|
)
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('correctly moves curwin when moving curwin to a different tabpage', function()
|
it('correctly moves curwin when moving curwin to a different tabpage', function()
|
||||||
@@ -2773,7 +2788,6 @@ describe('API/win', function()
|
|||||||
|
|
||||||
it('messing with "win" or "parent" when moving "win" to other tabpage', function()
|
it('messing with "win" or "parent" when moving "win" to other tabpage', function()
|
||||||
command('split | tabnew')
|
command('split | tabnew')
|
||||||
local t2 = api.nvim_get_current_tabpage()
|
|
||||||
local t2_win1 = api.nvim_get_current_win()
|
local t2_win1 = api.nvim_get_current_win()
|
||||||
command('split')
|
command('split')
|
||||||
local t2_win2 = api.nvim_get_current_win()
|
local t2_win2 = api.nvim_get_current_win()
|
||||||
@@ -2818,23 +2832,19 @@ describe('API/win', function()
|
|||||||
eq('', api.nvim_win_get_config(0).relative)
|
eq('', api.nvim_win_get_config(0).relative)
|
||||||
eq(cur_win, api.nvim_get_current_win())
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
-- Try to make "parent" floating. This should give the same error as before, but because
|
-- Try to make "parent" floating. This should give the same error as before.
|
||||||
-- 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(([[
|
exec(([[
|
||||||
autocmd WinLeave * ++once silent!
|
autocmd WinLeave * ++once
|
||||||
\ call nvim_win_set_config(%d, #{relative:'editor', row:0, col:0, width:5, height:5})
|
\ call nvim_win_set_config(%d, #{relative:'editor', row:0, col:0, width:5, height:5})
|
||||||
]]):format(t2_win3))
|
]]):format(t2_win3))
|
||||||
cur_win = api.nvim_get_current_win()
|
cur_win = api.nvim_get_current_win()
|
||||||
api.nvim_win_set_config(0, { win = t2_win3, split = 'left' })
|
eq(
|
||||||
matches(
|
'Floating state of windows to split changed',
|
||||||
'Cannot change window from different tabpage into float$',
|
pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' })
|
||||||
api.nvim_get_vvar('errmsg')
|
|
||||||
)
|
)
|
||||||
-- The error doesn't abort moving the window (or maybe it should, if that's wanted?)
|
eq('editor', api.nvim_win_get_config(t2_win3).relative)
|
||||||
neq(cur_win, api.nvim_get_current_win())
|
eq('', api.nvim_win_get_config(0).relative)
|
||||||
eq(t2, api.nvim_win_get_tabpage(cur_win))
|
eq(cur_win, api.nvim_get_current_win())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('expected autocmds when moving window to other tabpage', function()
|
it('expected autocmds when moving window to other tabpage', function()
|
||||||
@@ -3228,6 +3238,35 @@ describe('API/win', function()
|
|||||||
api.nvim_win_set_config(t2_cur_win, { split = 'left', win = 0 })
|
api.nvim_win_set_config(t2_cur_win, { split = 'left', win = 0 })
|
||||||
eq(t2_alt_win, api.nvim_tabpage_get_win(t2))
|
eq(t2_alt_win, api.nvim_tabpage_get_win(t2))
|
||||||
eq(t1, api.nvim_win_get_tabpage(t2_cur_win))
|
eq(t1, api.nvim_win_get_tabpage(t2_cur_win))
|
||||||
|
|
||||||
|
-- Very fun: move curwin between tabpages, converting from split to float, but with an autocmd
|
||||||
|
-- that deletes altwin after we're bumped to it, re-enters curwin, then switches to a 3rd
|
||||||
|
-- tabpage. tp_curwin of the window's old tabpage shouldn't be set to the freed altwin!
|
||||||
|
command('tablast | tab split | tabprevious | split')
|
||||||
|
command('autocmd WinEnter * ++once quit | let expect_alt = win_getid() | wincmd p | tabnext')
|
||||||
|
api.nvim_win_set_config(0, {
|
||||||
|
relative = 'editor',
|
||||||
|
win = api.nvim_tabpage_get_win(t1),
|
||||||
|
row = 0,
|
||||||
|
col = 0,
|
||||||
|
width = 5,
|
||||||
|
height = 5,
|
||||||
|
})
|
||||||
|
eq(eval('g:expect_alt'), api.nvim_tabpage_get_win(t2))
|
||||||
|
|
||||||
|
-- Same, but for float -> float.
|
||||||
|
command('tabprevious | split')
|
||||||
|
api.nvim_open_win(0, true, { relative = 'editor', row = 0, col = 0, width = 1, height = 1 })
|
||||||
|
command('autocmd WinEnter * ++once quit | let expect_alt = win_getid() | wincmd p | tabnext')
|
||||||
|
api.nvim_win_set_config(0, {
|
||||||
|
relative = 'editor',
|
||||||
|
win = api.nvim_tabpage_get_win(t1),
|
||||||
|
row = 0,
|
||||||
|
col = 0,
|
||||||
|
width = 5,
|
||||||
|
height = 5,
|
||||||
|
})
|
||||||
|
eq(eval('g:expect_alt'), api.nvim_tabpage_get_win(t2))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('set_config cannot change "noautocmd" #36409', function()
|
it('set_config cannot change "noautocmd" #36409', function()
|
||||||
@@ -3742,7 +3781,6 @@ describe('API/win', function()
|
|||||||
|
|
||||||
it('preserve current floating window when moving fails', function()
|
it('preserve current floating window when moving fails', function()
|
||||||
local buf = api.nvim_create_buf(false, true)
|
local buf = api.nvim_create_buf(false, true)
|
||||||
local tab1_win = api.nvim_get_current_win()
|
|
||||||
local float_win = api.nvim_open_win(buf, true, {
|
local float_win = api.nvim_open_win(buf, true, {
|
||||||
relative = 'editor',
|
relative = 'editor',
|
||||||
row = 1,
|
row = 1,
|
||||||
@@ -3770,18 +3808,6 @@ describe('API/win', function()
|
|||||||
)
|
)
|
||||||
eq(float_win, api.nvim_get_current_win())
|
eq(float_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
command(
|
|
||||||
('autocmd WinLeave * ++once call nvim_win_set_config(%d, #{split: "left", win: %d})'):format(
|
|
||||||
float_win,
|
|
||||||
tab1_win
|
|
||||||
)
|
|
||||||
)
|
|
||||||
eq(
|
|
||||||
('Window %d was made non-floating'):format(float_win),
|
|
||||||
pcall_err(api.nvim_win_set_config, float_win, { win = tab3_win })
|
|
||||||
)
|
|
||||||
eq(float_win, api.nvim_get_current_win())
|
|
||||||
|
|
||||||
-- Need multigrid for external windows.
|
-- Need multigrid for external windows.
|
||||||
Screen.new(20, 9, { ext_multigrid = true })
|
Screen.new(20, 9, { ext_multigrid = true })
|
||||||
api.nvim_win_set_config(float_win, { external = true, width = 5, height = 5 })
|
api.nvim_win_set_config(float_win, { external = true, width = 5, height = 5 })
|
||||||
|
|||||||
@@ -3782,10 +3782,7 @@ describe('float window', function()
|
|||||||
it('API has proper error messages', function()
|
it('API has proper error messages', function()
|
||||||
local buf = api.nvim_create_buf(false, false)
|
local buf = api.nvim_create_buf(false, false)
|
||||||
eq("Invalid key: 'bork'", pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, bork = true }))
|
eq("Invalid key: 'bork'", pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, bork = true }))
|
||||||
eq(
|
eq("Must specify 'relative' or 'external' when creating a float", pcall_err(api.nvim_open_win, buf, false, { win = 0 }))
|
||||||
"Must specify 'relative' or 'external' when creating a float",
|
|
||||||
pcall_err(api.nvim_open_win, buf, false, { win = 0 })
|
|
||||||
)
|
|
||||||
eq(
|
eq(
|
||||||
"floating windows cannot have 'vertical'",
|
"floating windows cannot have 'vertical'",
|
||||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, vertical = true })
|
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, vertical = true })
|
||||||
@@ -12030,6 +12027,7 @@ describe('float window', function()
|
|||||||
|
|
||||||
-- Check tablines are redrawn even when moving floats between two non-current tabpages.
|
-- Check tablines are redrawn even when moving floats between two non-current tabpages.
|
||||||
command('tabnew')
|
command('tabnew')
|
||||||
|
local tab3_win = api.nvim_get_current_win()
|
||||||
if multigrid then
|
if multigrid then
|
||||||
screen:expect({
|
screen:expect({
|
||||||
grid = [[
|
grid = [[
|
||||||
@@ -12094,6 +12092,270 @@ describe('float window', function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Try converting a split to a float, then moving it to another tabpage in one call.
|
||||||
|
command('set norightleft | new')
|
||||||
|
fn.setline(1, 'floaty mcfloatface')
|
||||||
|
api.nvim_win_set_config(0, { relative = 'editor', win = tab1_win, row = 3, col = 3, width = 15, height = 5 })
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{9: }{10:2}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
[6:----------------------------------------]|*5
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2 (hidden)
|
||||||
|
olleh|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4 (hidden)
|
||||||
|
hello |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 5 (hidden)
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6
|
||||||
|
^ |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7 (hidden)
|
||||||
|
floaty mcfloatface |
|
||||||
|
{0:~ }|
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{9: }{10:2}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
^ |
|
||||||
|
{0:~ }|*4
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
command('tabfirst')
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{3: }{11:2}{3:+ No Name] }{9: [No Name] }{10:2}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
[2:----------------------------------------]|*5
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
olle^h|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4 (hidden)
|
||||||
|
hello |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 5 (hidden)
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6 (hidden)
|
||||||
|
|
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7
|
||||||
|
{1:floaty mcfloatf}|
|
||||||
|
{1:ace }|
|
||||||
|
{2:~ }|*3
|
||||||
|
]],
|
||||||
|
float_pos = {
|
||||||
|
[7] = { 1004, 'NW', 1, 3, 3, true, 50, 1, 1, 3 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{3: }{11:2}{3:+ No Name] }{9: [No Name] }{10:2}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
{1:floaty mcfloatf} olle^h|
|
||||||
|
{0: }{1:ace }{0: ~}|
|
||||||
|
{0: }{2:~ }{0: ~}|*3
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Works when doing the same between two non-current tabpages.
|
||||||
|
local float2 = api.nvim_open_win(0, false, { split = 'below', win = tab3_win })
|
||||||
|
api.nvim_win_set_config(float2, { relative = 'win', win = tab2_win, row = 2, col = 7, width = 4, height = 4, border = 'single' })
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{3: }{11:2}{3:+ No Name] }{9: [No Name] }{10:3}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
[2:----------------------------------------]|*5
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
olle^h|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4 (hidden)
|
||||||
|
hello |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 5 (hidden)
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6 (hidden)
|
||||||
|
|
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7
|
||||||
|
{1:floaty mcfloatf}|
|
||||||
|
{1:ace }|
|
||||||
|
{2:~ }|*3
|
||||||
|
]],
|
||||||
|
float_pos = {
|
||||||
|
[7] = { 1004, 'NW', 1, 3, 3, true, 50, 1, 1, 3 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{3: }{11:2}{3:+ No Name] }{9: [No Name] }{10:3}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
{1:floaty mcfloatf} olle^h|
|
||||||
|
{0: }{1:ace }{0: ~}|
|
||||||
|
{0: }{2:~ }{0: ~}|*3
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
command('tabnext')
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{9: }{10:3}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
[6:----------------------------------------]|*5
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2 (hidden)
|
||||||
|
olleh|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4 (hidden)
|
||||||
|
hello |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 5 (hidden)
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6
|
||||||
|
^ |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7 (hidden)
|
||||||
|
{1:floaty mcfloatf}|
|
||||||
|
{1:ace }|
|
||||||
|
{2:~ }|*3
|
||||||
|
]],
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{9: }{10:3}{9:+ No Name] }{5: }{9:X}|
|
||||||
|
^ |
|
||||||
|
{0:~ }|*4
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
command('tabnext')
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{9: }{10:2}{9:+ No Name] [No Name] }{3: }{11:3}{3:+ No Name] }{5: }{9:X}|
|
||||||
|
[4:----------------------------------------]|*5
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2 (hidden)
|
||||||
|
olleh|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4
|
||||||
|
^hello |
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 5
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6 (hidden)
|
||||||
|
|
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7 (hidden)
|
||||||
|
{1:floaty mcfloatf}|
|
||||||
|
{1:ace }|
|
||||||
|
{2:~ }|*3
|
||||||
|
## grid 8
|
||||||
|
{5:┌────┐}|
|
||||||
|
{5:│}{1:lleh}{5:│}|
|
||||||
|
{5:│}{1: o}{5:│}|
|
||||||
|
{5:│}{2: ~}{5:│}|*2
|
||||||
|
{5:└────┘}|
|
||||||
|
]],
|
||||||
|
float_pos = {
|
||||||
|
[5] = { 1002, 'NW', 4, 0, 0, true, 50, 1, 1, 0 },
|
||||||
|
[8] = { 1005, 'NW', 4, 2, 7, true, 50, 2, 0, 7 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{9: }{10:2}{9:+ No }{5:┌────┐}{9: [No Name] }{3: }{11:3}{3:+ No Name] }{5: }{9:X}|
|
||||||
|
{1:^hello }{5:│}{1:lleh}{5:│} |
|
||||||
|
{2:~ }{5:│}{1: o}{5:│}{0: }|
|
||||||
|
{2:~ }{5:│}{2: ~}{5:│}{0: }|*2
|
||||||
|
{2:~ }{5:└────┘}{0: }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Used relative=win on two floats relative to this window.
|
||||||
|
-- Split it to the right to ensure both follow.
|
||||||
|
command('topleft vsplit')
|
||||||
|
if multigrid then
|
||||||
|
screen:expect({
|
||||||
|
grid = [[
|
||||||
|
## grid 1
|
||||||
|
{9: }{10:2}{9:+ No Name] [No Name] }{3: }{11:4}{3:+ No Name] }{5: }{9:X}|
|
||||||
|
[9:--------------------]{5:│}[4:-------------------]|*4
|
||||||
|
{4:[No Name] [+] }{5:[No Name] [+] }|
|
||||||
|
[3:----------------------------------------]|
|
||||||
|
## grid 2 (hidden)
|
||||||
|
olleh|
|
||||||
|
{0: ~}|*4
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4
|
||||||
|
hello |
|
||||||
|
{0:~ }|*3
|
||||||
|
## grid 5
|
||||||
|
{1:hello }|
|
||||||
|
{2:~ }|*4
|
||||||
|
## grid 6 (hidden)
|
||||||
|
|
|
||||||
|
{0:~ }|*4
|
||||||
|
## grid 7 (hidden)
|
||||||
|
{1:floaty mcfloatf}|
|
||||||
|
{1:ace }|
|
||||||
|
{2:~ }|*3
|
||||||
|
## grid 8
|
||||||
|
{5:┌────┐}|
|
||||||
|
{5:│}{1:lleh}{5:│}|
|
||||||
|
{5:│}{1: o}{5:│}|
|
||||||
|
{5:│}{2: ~}{5:│}|*2
|
||||||
|
{5:└────┘}|
|
||||||
|
## grid 9
|
||||||
|
^hello |
|
||||||
|
{0:~ }|*3
|
||||||
|
]],
|
||||||
|
float_pos = {
|
||||||
|
[5] = { 1002, 'NW', 4, 0, 0, true, 50, 1, 1, 21 },
|
||||||
|
[8] = { 1005, 'NW', 4, 2, 7, true, 50, 2, 0, 28 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
else
|
||||||
|
screen:expect([[
|
||||||
|
{9: }{10:2}{9:+ No Name] [No Name] }{3: }{11:4}{3:+ }{5:┌────┐}{3:e] }{5: }{9:X}|
|
||||||
|
^hello {5:│}{1:hello }{5:│}{1:lleh}{5:│} |
|
||||||
|
{0:~ }{5:│}{2:~ }{5:│}{1: o}{5:│}{0: }|
|
||||||
|
{0:~ }{5:│}{2:~ }{5:│}{2: ~}{5:│}{0: }|*2
|
||||||
|
{4:[No Name] [+] }{2:~ }{5:└────┘ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user