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:
Sean Dewar
2026-03-11 19:06:47 +00:00
parent 3325536150
commit 094b297a3b
5 changed files with 416 additions and 124 deletions

View File

@@ -167,7 +167,7 @@ API
they were so specified in `nvim_create_user_command()`.
• |nvim_open_win()| floating windows can show a 'statusline'. Plugins can use
`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
execute code while nvim is blocking for input.
• |vim.secure.trust()| accepts `path` for the `allow` action.

View File

@@ -384,9 +384,13 @@ static int win_split_flags(WinSplit split, bool toplevel)
}
/// 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
{
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)) {
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
return false;
@@ -403,6 +407,17 @@ static bool win_can_move_tp(win_T *wp, Error *err)
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.
static bool win_config_split(win_T *win, const Dict(win_config) *config, WinConfig *fconfig,
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");
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
}
}
@@ -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.
const bool curwin_moving_tp = win == curwin && parent && win_tp != parent_tp;
if (curwin_moving_tp) {
if (was_split) {
int dir;
win_T *altwin = winframe_find_altwin(win, &dir, NULL, NULL);
// 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));
}
win_T *altwin = win_find_altwin(win, win_tp);
assert(altwin); // win_can_move_tp ensures `win` is not the only window
win_goto(altwin);
// Autocommands may have been a real nuisance and messed things up...
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);
}
bool curwin_moving_tp = false;
win_T *altwin = NULL;
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
}
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) {
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...
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);
parent_tp = win_find_tabpage(parent);
bool restore_curwin = false;
if (!win_tp || !parent_tp) {
api_set_error(err, kErrorTypeException, "Target windows were closed");
restore_curwin = true;
} 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
goto restore_curwin;
}
if (restore_curwin) {
// As `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 (win_valid(win)) {
win_goto(win);
}
return false;
if (win_tp != parent_tp && !win_can_move_tp(win, win_tp, err)) {
goto restore_curwin; // error already set
}
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.
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);
// 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);
// 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 = win_float_find_altwin(win, win_tp);
}
// 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);
}
// 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);
@@ -745,27 +763,11 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
return;
}
if (was_split && !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 (to_split) {
if (!win_config_split(win, config, &fconfig, err)) {
return;
}
} else {
assert(!was_split);
if (!win_config_float_tp(win, config, &fconfig, err)) {
return;
}

View File

@@ -35,10 +35,9 @@
#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.
/// It must then already belong to the current tabpage!
/// @param last make the window the last one in the window list.
/// Only used when allocating the autocommand window.
/// @param config must already have been validated!
@@ -74,19 +73,19 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
} else {
assert(!last);
assert(!wp->w_floating);
if (firstwin == wp && lastwin_nofloating(NULL) == wp) {
// last non-float
api_set_error(err, kErrorTypeException,
"Cannot change last window into float");
return NULL;
} else if (!win_valid(wp)) {
api_set_error(err, kErrorTypeException,
"Cannot change window from different tabpage into float");
tabpage_T *win_tp = win_find_tabpage(wp);
assert(win_tp);
if ((win_tp == curtab && firstwin == wp && lastwin_nofloating(NULL) == wp)
|| (win_tp != curtab && win_tp->tp_firstwin == wp && lastwin_nofloating(win_tp) == wp)) {
api_set_error(err, kErrorTypeException, "Cannot change last window into float");
return NULL;
} else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
// cmdwin can't become the only non-float. Check for others.
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) {
other_nonfloat = true;
break;
@@ -97,13 +96,16 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
return NULL;
}
}
tabpage_T *tp = win_tp == curtab ? NULL : win_tp;
int dir;
winframe_remove(wp, &dir, NULL, NULL);
winframe_remove(wp, &dir, tp, NULL);
XFREE_CLEAR(wp->w_frame);
win_remove(wp, NULL);
last_status(false); // may need to remove last status line
win_comp_pos(); // recompute window positions
win_append(lastwin_nofloating(NULL), wp, NULL);
win_remove(wp, tp);
if (win_tp == curtab) {
last_status(false); // may need to remove last status line
win_comp_pos(); // recompute window positions
}
win_append(lastwin_nofloating(tp), wp, tp);
}
wp->w_floating = true;
wp->w_status_height = wp->w_p_stl && *wp->w_p_stl != NUL

View File

@@ -2585,15 +2585,17 @@ describe('API/win', function()
},
}, layout)
-- converting split into a float for a different tabpage is not yet supported
eq(
'Cannot configure split into float in another tabpage',
pcall_err(
api.nvim_win_set_config,
win,
{ relative = 'editor', row = 0, col = 0, width = 1, height = 1, win = first_win }
)
-- directly convert split into a float for a different tabpage
local win2 = api.nvim_open_win(0, true, { split = 'below' })
eq('', api.nvim_win_get_config(win2).relative)
api.nvim_win_set_config(
win2,
{ 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
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
api.nvim_win_set_config(win, { win = first_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))
-- unlike splits, negative win is invalid
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)
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()
command('split | tabnew')
local t2 = api.nvim_get_current_tabpage()
local t2_win1 = api.nvim_get_current_win()
command('split')
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(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.
-- Try to make "parent" floating. This should give the same error as before.
exec(([[
autocmd WinLeave * ++once silent!
autocmd WinLeave * ++once
\ 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')
eq(
'Floating state of windows to split changed',
pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' })
)
-- 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))
eq('editor', api.nvim_win_get_config(t2_win3).relative)
eq('', api.nvim_win_get_config(0).relative)
eq(cur_win, api.nvim_get_current_win())
end)
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 })
eq(t2_alt_win, api.nvim_tabpage_get_win(t2))
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)
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()
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, {
relative = 'editor',
row = 1,
@@ -3770,18 +3808,6 @@ describe('API/win', function()
)
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.
Screen.new(20, 9, { ext_multigrid = true })
api.nvim_win_set_config(float_win, { external = true, width = 5, height = 5 })

View File

@@ -3782,10 +3782,7 @@ describe('float window', function()
it('API has proper error messages', function()
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(
"Must specify 'relative' or 'external' when creating a float",
pcall_err(api.nvim_open_win, buf, false, { win = 0 })
)
eq("Must specify 'relative' or 'external' when creating a float", pcall_err(api.nvim_open_win, buf, false, { win = 0 }))
eq(
"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 })
@@ -12030,6 +12027,7 @@ describe('float window', function()
-- Check tablines are redrawn even when moving floats between two non-current tabpages.
command('tabnew')
local tab3_win = api.nvim_get_current_win()
if multigrid then
screen:expect({
grid = [[
@@ -12094,6 +12092,270 @@ describe('float window', function()
|
]])
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