mirror of
https://github.com/neovim/neovim.git
synced 2026-03-28 03:12:00 +00:00
Merge #35816 nvim_win_set_config can move floatwin to another tabpage
This commit is contained in:
@@ -3921,9 +3921,11 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
|
||||
Default is `"left"`.
|
||||
• vertical: Split vertically |:vertical|.
|
||||
• width: Window width (in character cells). Minimum of 1.
|
||||
• win: |window-ID| window to split, or relative window when
|
||||
creating a float (relative="win"). When splitting,
|
||||
negative value works like |:topleft|, |:botright|.
|
||||
• win: |window-ID| target window. Can be in a different tab
|
||||
page. Determines the window to split (negative values act
|
||||
like |:topleft|, |:botright|), the relative window for a
|
||||
`relative="win"` float, or just the target tab page
|
||||
(inferred from the window) for others.
|
||||
• zindex: Stacking order. floats with higher `zindex` go on
|
||||
top on floats with lower indices. Must be larger than
|
||||
zero. The following screen elements have hard-coded
|
||||
|
||||
@@ -167,6 +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 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.
|
||||
|
||||
5
runtime/lua/vim/_meta/api.lua
generated
5
runtime/lua/vim/_meta/api.lua
generated
@@ -1848,8 +1848,9 @@ function vim.api.nvim_open_term(buffer, opts) end
|
||||
--- Default is `"left"`.
|
||||
--- - vertical: Split vertically `:vertical`.
|
||||
--- - width: Window width (in character cells). Minimum of 1.
|
||||
--- - win: `window-ID` window to split, or relative window when creating a float (relative="win").
|
||||
--- When splitting, negative value works like `:topleft`, `:botright`.
|
||||
--- - win: `window-ID` target window. Can be in a different tab page. Determines the window to
|
||||
--- split (negative values act like `:topleft`, `:botright`), the relative window for a
|
||||
--- `relative="win"` float, or just the target tab page (inferred from the window) for others.
|
||||
--- - zindex: Stacking order. floats with higher `zindex` go on top on
|
||||
--- floats with lower indices. Must be larger than zero. The
|
||||
--- following screen elements have hard-coded z-indices:
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "nvim/drawscreen.h"
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/globals.h"
|
||||
#include "nvim/highlight_group.h"
|
||||
#include "nvim/macros_defs.h"
|
||||
@@ -32,6 +34,7 @@
|
||||
#include "nvim/syntax.h"
|
||||
#include "nvim/types_defs.h"
|
||||
#include "nvim/ui.h"
|
||||
#include "nvim/ui_compositor.h"
|
||||
#include "nvim/ui_defs.h"
|
||||
#include "nvim/vim_defs.h"
|
||||
#include "nvim/window.h"
|
||||
@@ -39,6 +42,8 @@
|
||||
|
||||
#include "api/win_config.c.generated.h"
|
||||
|
||||
#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key)
|
||||
|
||||
/// Opens a new split window, floating window, or external window.
|
||||
///
|
||||
/// - Specify `relative` to create a floating window. Floats are drawn over the split layout,
|
||||
@@ -177,8 +182,9 @@
|
||||
/// Default is `"left"`.
|
||||
/// - vertical: Split vertically |:vertical|.
|
||||
/// - width: Window width (in character cells). Minimum of 1.
|
||||
/// - win: |window-ID| window to split, or relative window when creating a float (relative="win").
|
||||
/// When splitting, negative value works like |:topleft|, |:botright|.
|
||||
/// - win: |window-ID| target window. Can be in a different tab page. Determines the window to
|
||||
/// split (negative values act like |:topleft|, |:botright|), the relative window for a
|
||||
/// `relative="win"` float, or just the target tab page (inferred from the window) for others.
|
||||
/// - zindex: Stacking order. floats with higher `zindex` go on top on
|
||||
/// floats with lower indices. Must be larger than zero. The
|
||||
/// following screen elements have hard-coded z-indices:
|
||||
@@ -197,7 +203,6 @@
|
||||
Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Error *err)
|
||||
FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||
{
|
||||
#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key)
|
||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||
if (!buf) {
|
||||
return 0;
|
||||
@@ -348,7 +353,6 @@ cleanup:
|
||||
unblock_autocmds();
|
||||
}
|
||||
return rv;
|
||||
#undef HAS_KEY_X
|
||||
}
|
||||
|
||||
static WinSplit win_split_dir(win_T *win)
|
||||
@@ -381,10 +385,56 @@ static int win_split_flags(WinSplit split, bool toplevel)
|
||||
return flags;
|
||||
}
|
||||
|
||||
static bool win_config_split(win_T *win, Dict(win_config) *config, WinConfig *fconfig, Error *err)
|
||||
/// Checks if window `wp` can be moved to tabpage `tp`.
|
||||
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;
|
||||
}
|
||||
// Like closing, moving windows between tabpages makes win_valid return false. Helpful when e.g:
|
||||
// walking the window list, as w_next/w_prev can unexpectedly refer to windows in another tabpage!
|
||||
// Check related locks, in case they were set to avoid checking win_valid.
|
||||
if (win_locked(wp)) {
|
||||
api_set_error(err, kErrorTypeException, "Cannot move window to another tabpage whilst in use");
|
||||
return false;
|
||||
}
|
||||
if (window_layout_locked_err(CMD_SIZE, err)) {
|
||||
return false; // error already set
|
||||
}
|
||||
if (textlock || expr_map_locked()) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_textlock);
|
||||
return false;
|
||||
}
|
||||
if (is_aucmd_win(wp)) {
|
||||
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
|
||||
return false;
|
||||
}
|
||||
// Can't move the cmdwin or its old curwin to a different tabpage.
|
||||
if (wp == cmdwin_win || wp == cmdwin_old_curwin) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key)
|
||||
bool was_split = !win->w_floating;
|
||||
bool has_split = HAS_KEY_X(config, split);
|
||||
bool has_vertical = HAS_KEY_X(config, vertical);
|
||||
@@ -423,14 +473,8 @@ static bool win_config_split(win_T *win, Dict(win_config) *config, WinConfig *fc
|
||||
api_set_error(err, kErrorTypeException, "Cannot split a floating window");
|
||||
return false;
|
||||
}
|
||||
if (is_aucmd_win(win) && win_tp != parent_tp) {
|
||||
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
|
||||
return false;
|
||||
}
|
||||
// Can't move the cmdwin or its old curwin to a different tabpage.
|
||||
if ((win == cmdwin_win || win == cmdwin_old_curwin) && win_tp != parent_tp) {
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
|
||||
return false;
|
||||
if (win_tp != parent_tp && !win_can_move_tp(win, win_tp, err)) {
|
||||
return false; // error already set
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,24 +487,13 @@ static bool win_config_split(win_T *win, Dict(win_config) *config, WinConfig *fc
|
||||
// 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) {
|
||||
api_set_error(err, kErrorTypeException, "Failed to switch away from window %d",
|
||||
win->handle);
|
||||
api_set_error(err, kErrorTypeException, "Failed to switch away from window %d", win->handle);
|
||||
return false;
|
||||
}
|
||||
win_tp = win_find_tabpage(win);
|
||||
@@ -608,7 +641,98 @@ resize:
|
||||
}
|
||||
merge_win_config(&win->w_config, *fconfig);
|
||||
return true;
|
||||
#undef HAS_KEY_X
|
||||
}
|
||||
|
||||
/// Configures `win` into a float, also moving it to another tabpage if requested.
|
||||
static bool win_config_float_tp(win_T *win, const Dict(win_config) *config,
|
||||
const WinConfig *fconfig, Error *err)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
tabpage_T *win_tp = win_find_tabpage(win);
|
||||
win_T *parent = win;
|
||||
tabpage_T *parent_tp = win_tp;
|
||||
if (HAS_KEY_X(config, win)) {
|
||||
parent = find_window_by_handle(fconfig->window, err);
|
||||
if (!parent) {
|
||||
return false; // error already set
|
||||
}
|
||||
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, 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) {
|
||||
curwin_moving_tp = true;
|
||||
win_goto(altwin);
|
||||
|
||||
// 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 false;
|
||||
}
|
||||
win_tp = win_find_tabpage(win);
|
||||
parent_tp = win_find_tabpage(parent);
|
||||
|
||||
if (!win_tp || !parent_tp) {
|
||||
api_set_error(err, kErrorTypeException, "Target windows were closed");
|
||||
goto restore_curwin;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Reconfigures the layout and properties of a window.
|
||||
@@ -631,7 +755,6 @@ resize:
|
||||
void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
||||
FUNC_API_SINCE(6)
|
||||
{
|
||||
#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key)
|
||||
win_T *win = find_window_by_handle(window, err);
|
||||
if (!win) {
|
||||
return;
|
||||
@@ -645,24 +768,21 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
||||
WinConfig fconfig = win->w_config;
|
||||
|
||||
bool to_split = config->relative.size == 0
|
||||
&& !(HAS_KEY_X(config, external) ? config->external : fconfig.external)
|
||||
&& !(HAS_KEY_X(config, external) && config->external)
|
||||
&& (has_split || has_vertical || was_split);
|
||||
|
||||
if (!parse_win_config(win, config, &fconfig, !was_split || to_split, err)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (was_split && !to_split) {
|
||||
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 {
|
||||
win_config_float(win, fconfig);
|
||||
if (!win_config_float_tp(win, config, &fconfig, err)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fconfig.style == kWinStyleMinimal && old_style != fconfig.style) {
|
||||
@@ -675,7 +795,6 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
|
||||
} else if (win == cmdline_win && fconfig._cmdline_offset == INT_MAX) {
|
||||
cmdline_win = NULL;
|
||||
}
|
||||
#undef HAS_KEY_X
|
||||
}
|
||||
|
||||
#define PUT_KEY_X(d, key, value) PUT_KEY(d, win_config, key, value)
|
||||
@@ -1144,7 +1263,6 @@ bool parse_winborder(WinConfig *fconfig, char *border_opt, Error *err)
|
||||
static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fconfig, bool reconf,
|
||||
Error *err)
|
||||
{
|
||||
#define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key)
|
||||
bool has_relative = false, relative_is_win = false, is_split = false;
|
||||
if (config->relative.size > 0) {
|
||||
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
||||
@@ -1167,6 +1285,7 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
} else if (!config->external) {
|
||||
if (HAS_KEY_X(config, vertical) || HAS_KEY_X(config, split)) {
|
||||
is_split = true;
|
||||
fconfig->external = false;
|
||||
} else if (wp == NULL) { // new win
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Must specify 'relative' or 'external' when creating a float");
|
||||
@@ -1258,36 +1377,6 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (relative_is_win || is_split) {
|
||||
if (reconf && relative_is_win) {
|
||||
win_T *target_win = find_window_by_handle(config->win, err);
|
||||
if (!target_win) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (target_win == wp) {
|
||||
api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
fconfig->window = curwin->handle;
|
||||
if (HAS_KEY_X(config, win)) {
|
||||
if (config->win > 0) {
|
||||
fconfig->window = config->win;
|
||||
}
|
||||
}
|
||||
} else if (HAS_KEY_X(config, win)) {
|
||||
if (has_relative) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"'win' key is only valid with relative='win' and relative=''");
|
||||
goto fail;
|
||||
} else if (!is_split) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"non-float with 'win' requires at least 'split' or 'vertical'");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, external)) {
|
||||
fconfig->external = config->external;
|
||||
if (has_relative && fconfig->external) {
|
||||
@@ -1301,6 +1390,38 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, win) && fconfig->external) {
|
||||
api_set_error(err, kErrorTypeValidation, "external window cannot have 'win'");
|
||||
goto fail;
|
||||
}
|
||||
if (relative_is_win || (HAS_KEY_X(config, win) && !is_split && wp && wp->w_floating
|
||||
&& fconfig->relative == kFloatRelativeWindow)) {
|
||||
// When relative=win is given, missing win field means win=0.
|
||||
win_T *target_win = find_window_by_handle(config->win, err);
|
||||
if (!target_win) {
|
||||
goto fail;
|
||||
}
|
||||
if (target_win == wp) {
|
||||
api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself");
|
||||
goto fail;
|
||||
}
|
||||
fconfig->window = target_win->handle;
|
||||
} else {
|
||||
// Handle is not validated here, as win_config_split can accept negative values.
|
||||
if (HAS_KEY_X(config, win)) {
|
||||
if (!is_split && !has_relative && (!wp || !wp->w_floating)) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"non-float with 'win' requires at least 'split' or 'vertical'");
|
||||
goto fail;
|
||||
}
|
||||
fconfig->window = config->win;
|
||||
}
|
||||
// Resolve, but skip validating. E.g: win_config_split accepts negative "win".
|
||||
if (fconfig->window == 0) {
|
||||
fconfig->window = curwin->handle;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, focusable)) {
|
||||
fconfig->focusable = config->focusable;
|
||||
fconfig->mouse = config->focusable;
|
||||
@@ -1422,5 +1543,4 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
fail:
|
||||
merge_win_config(fconfig, wp != NULL ? wp->w_config : WIN_CONFIG_INIT);
|
||||
return false;
|
||||
#undef HAS_KEY_X
|
||||
}
|
||||
|
||||
@@ -1116,7 +1116,7 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
last_curwin = curwin;
|
||||
last_curtab = curtab;
|
||||
// lastwin may be aucmd_win
|
||||
win_enter(lastwin_nofloating(), false);
|
||||
win_enter(lastwin_nofloating(NULL), false);
|
||||
|
||||
// Open up to "count" windows.
|
||||
arg_all_open_windows(&aall, count);
|
||||
|
||||
@@ -3692,7 +3692,7 @@ void ex_buffer_all(exarg_T *eap)
|
||||
// Don't execute Win/Buf Enter/Leave autocommands here.
|
||||
autocmd_no_enter++;
|
||||
// lastwin may be aucmd_win
|
||||
win_enter(lastwin_nofloating(), false);
|
||||
win_enter(lastwin_nofloating(NULL), false);
|
||||
autocmd_no_leave++;
|
||||
for (buf_T *buf = firstbuf; buf != NULL && open_wins < count; buf = buf->b_next) {
|
||||
// Check if this buffer needs a window
|
||||
|
||||
@@ -4062,7 +4062,7 @@ void compute_cmdrow(void)
|
||||
if (exmode_active || msg_scrolled != 0) {
|
||||
cmdline_row = Rows - 1;
|
||||
} else {
|
||||
win_T *wp = lastwin_nofloating();
|
||||
win_T *wp = lastwin_nofloating(NULL);
|
||||
cmdline_row = wp->w_winrow + wp->w_height
|
||||
+ wp->w_hsep_height + wp->w_status_height + global_stl_height();
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ void win_redr_winbar(win_T *wp)
|
||||
void redraw_ruler(void)
|
||||
{
|
||||
static int did_ruler_col = -1;
|
||||
win_T *wp = curwin->w_status_height == 0 ? curwin : lastwin_nofloating();
|
||||
win_T *wp = curwin->w_status_height == 0 ? curwin : lastwin_nofloating(NULL);
|
||||
bool is_stl_global = global_stl_height() > 0;
|
||||
|
||||
// Check if ruler should be drawn, clear if it was drawn before.
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "nvim/eval/window.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
#include "nvim/ex_cmds_defs.h"
|
||||
#include "nvim/ex_docmd.h"
|
||||
#include "nvim/ex_eval.h"
|
||||
#include "nvim/ex_getln.h"
|
||||
@@ -143,12 +142,26 @@ bool frames_locked(void)
|
||||
/// error message. When closing window(s) and the command isn't easy to know,
|
||||
/// passing CMD_SIZE will also work.
|
||||
bool window_layout_locked(cmdidx_T cmd)
|
||||
{
|
||||
Error err = ERROR_INIT;
|
||||
const bool locked = window_layout_locked_err(cmd, &err);
|
||||
if (ERROR_SET(&err)) {
|
||||
emsg(_(err.msg));
|
||||
api_clear_error(&err);
|
||||
}
|
||||
return locked;
|
||||
}
|
||||
|
||||
/// Like `window_layout_locked`, but set `err` to the (untranslated) error message when locked.
|
||||
/// @see window_layout_locked
|
||||
bool window_layout_locked_err(cmdidx_T cmd, Error *err)
|
||||
{
|
||||
if (split_disallowed > 0 || close_disallowed > 0) {
|
||||
if (close_disallowed == 0 && cmd == CMD_tabnew) {
|
||||
emsg(_(e_cannot_split_window_when_closing_buffer));
|
||||
api_set_error(err, kErrorTypeException, "%s", e_cannot_split_window_when_closing_buffer);
|
||||
} else {
|
||||
emsg(_(e_not_allowed_to_change_window_layout_in_this_autocmd));
|
||||
api_set_error(err, kErrorTypeException, "%s",
|
||||
e_not_allowed_to_change_window_layout_in_this_autocmd);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -505,7 +518,7 @@ newwindow:
|
||||
// cursor to bottom-right window
|
||||
case 'b':
|
||||
case Ctrl_B:
|
||||
win_goto(lastwin_nofloating());
|
||||
win_goto(lastwin_nofloating(NULL));
|
||||
break;
|
||||
|
||||
// cursor to last accessed (previous) window
|
||||
@@ -1158,7 +1171,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl
|
||||
oldwin = firstwin;
|
||||
} else if (flags & WSP_BOT || curwin->w_floating) {
|
||||
// can't split float, use last nonfloating window instead
|
||||
oldwin = lastwin_nofloating();
|
||||
oldwin = lastwin_nofloating(NULL);
|
||||
} else {
|
||||
oldwin = curwin;
|
||||
}
|
||||
@@ -4800,7 +4813,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab)
|
||||
if (wp->w_floating) {
|
||||
if (wp->w_config.external) {
|
||||
win_remove(wp, old_curtab);
|
||||
win_append(lastwin_nofloating(), wp, NULL);
|
||||
win_append(lastwin_nofloating(NULL), wp, NULL);
|
||||
} else {
|
||||
ui_comp_remove_grid(&wp->w_grid_alloc);
|
||||
}
|
||||
@@ -6237,7 +6250,7 @@ static void frame_setheight(frame_T *curfrp, int height)
|
||||
if (curfrp->fr_width != Columns) {
|
||||
room_cmdline = 0;
|
||||
} else {
|
||||
win_T *wp = lastwin_nofloating();
|
||||
win_T *wp = lastwin_nofloating(NULL);
|
||||
room_cmdline = Rows - (int)p_ch - global_stl_height()
|
||||
- (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height);
|
||||
room_cmdline = MAX(room_cmdline, 0);
|
||||
@@ -7051,7 +7064,7 @@ void command_height(void)
|
||||
int old_p_ch = (int)curtab->tp_ch_used;
|
||||
|
||||
// Find bottom frame with width of screen.
|
||||
frame_T *frp = lastwin_nofloating()->w_frame;
|
||||
frame_T *frp = lastwin_nofloating(NULL)->w_frame;
|
||||
while (frp->fr_width != Columns && frp->fr_parent != NULL) {
|
||||
frp = frp->fr_parent;
|
||||
}
|
||||
@@ -7804,9 +7817,11 @@ void win_ui_flush(bool validate)
|
||||
msg_ui_flush();
|
||||
}
|
||||
|
||||
win_T *lastwin_nofloating(void)
|
||||
/// @return last non-floating window in `tp`, or NULL for current tabpage.
|
||||
win_T *lastwin_nofloating(tabpage_T *tp)
|
||||
{
|
||||
win_T *res = lastwin;
|
||||
assert(tp != curtab || !tp);
|
||||
win_T *res = tp ? tp->tp_lastwin : lastwin;
|
||||
while (res->w_floating) {
|
||||
res = res->w_prev;
|
||||
}
|
||||
|
||||
@@ -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!
|
||||
@@ -46,7 +45,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|
||||
{
|
||||
if (wp == NULL) {
|
||||
tabpage_T *tp = NULL;
|
||||
win_T *tp_last = last ? lastwin : lastwin_nofloating();
|
||||
win_T *tp_last = last ? lastwin : lastwin_nofloating(NULL);
|
||||
if (fconfig.window != 0) {
|
||||
assert(!last);
|
||||
win_T *parent_wp = find_window_by_handle(fconfig.window, err);
|
||||
@@ -57,10 +56,7 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|
||||
if (!tp) {
|
||||
return NULL;
|
||||
}
|
||||
tp_last = tp == curtab ? lastwin : tp->tp_lastwin;
|
||||
while (tp_last->w_floating && tp_last->w_prev) {
|
||||
tp_last = tp_last->w_prev;
|
||||
}
|
||||
tp_last = lastwin_nofloating(tp == curtab ? NULL : tp);
|
||||
}
|
||||
wp = win_alloc(tp_last, false);
|
||||
win_init(wp, curwin, 0);
|
||||
@@ -77,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() == 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;
|
||||
@@ -100,12 +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_comp_pos(); // recompute window positions
|
||||
win_remove(wp, NULL);
|
||||
win_append(lastwin_nofloating(), 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
|
||||
|
||||
@@ -2561,60 +2561,88 @@ describe('API/win', function()
|
||||
eq(win, layout[2][2][2])
|
||||
end)
|
||||
|
||||
it('moves splits to other tabpages', function()
|
||||
local curtab = api.nvim_get_current_tabpage()
|
||||
it('moves windows to other tabpages', function()
|
||||
local first_tab = api.nvim_get_current_tabpage()
|
||||
local first_win = api.nvim_get_current_win()
|
||||
local win = api.nvim_open_win(0, false, { split = 'left' })
|
||||
command('tabnew')
|
||||
local tabnr = api.nvim_get_current_tabpage()
|
||||
command('tabprev') -- return to the initial tab
|
||||
|
||||
api.nvim_win_set_config(win, {
|
||||
split = 'right',
|
||||
win = api.nvim_tabpage_get_win(tabnr),
|
||||
})
|
||||
|
||||
eq(tabnr, api.nvim_win_get_tabpage(win))
|
||||
local new_tab = api.nvim_get_current_tabpage()
|
||||
local tab2_win = api.nvim_get_current_win()
|
||||
api.nvim_set_current_tabpage(first_tab)
|
||||
-- move new win to new tabpage
|
||||
api.nvim_win_set_config(win, { split = 'right', win = api.nvim_tabpage_get_win(new_tab) })
|
||||
eq(new_tab, api.nvim_win_get_tabpage(win))
|
||||
-- we are changing the config, the current tabpage should not change
|
||||
eq(curtab, api.nvim_get_current_tabpage())
|
||||
eq(first_tab, api.nvim_get_current_tabpage())
|
||||
|
||||
command('tabnext') -- switch to the new tabpage so we can get the layout
|
||||
api.nvim_set_current_tabpage(new_tab)
|
||||
local layout = fn.winlayout()
|
||||
|
||||
eq({
|
||||
'row',
|
||||
{
|
||||
{ 'leaf', api.nvim_tabpage_get_win(tabnr) },
|
||||
{ 'leaf', api.nvim_tabpage_get_win(new_tab) },
|
||||
{ 'leaf', win },
|
||||
},
|
||||
}, layout)
|
||||
|
||||
-- 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 })
|
||||
api.nvim_set_current_tabpage(first_tab)
|
||||
-- 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, 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()
|
||||
local curtab = api.nvim_get_current_tabpage()
|
||||
local tab1 = api.nvim_get_current_tabpage()
|
||||
local tab1_win = api.nvim_get_current_win()
|
||||
command('tabnew')
|
||||
local tab2 = api.nvim_get_current_tabpage()
|
||||
local tab2_win = api.nvim_get_current_win()
|
||||
|
||||
command('tabprev') -- return to the initial tab
|
||||
|
||||
local neighbor = api.nvim_get_current_win()
|
||||
|
||||
api.nvim_set_current_tabpage(tab1) -- return to the initial tab
|
||||
-- create and enter a new split
|
||||
local win = api.nvim_open_win(0, true, {
|
||||
vertical = false,
|
||||
})
|
||||
|
||||
eq(curtab, api.nvim_win_get_tabpage(win))
|
||||
|
||||
eq({ win, neighbor }, api.nvim_tabpage_list_wins(curtab))
|
||||
eq(tab1, api.nvim_win_get_tabpage(win))
|
||||
eq({ win, tab1_win }, api.nvim_tabpage_list_wins(tab1))
|
||||
|
||||
-- move the current win to a different tabpage
|
||||
api.nvim_win_set_config(win, {
|
||||
split = 'right',
|
||||
win = api.nvim_tabpage_get_win(tab2),
|
||||
})
|
||||
|
||||
eq(curtab, api.nvim_get_current_tabpage())
|
||||
eq(tab1, api.nvim_get_current_tabpage())
|
||||
|
||||
-- win should have moved to tab2
|
||||
eq(tab2, api.nvim_win_get_tabpage(win))
|
||||
@@ -2622,10 +2650,18 @@ describe('API/win', function()
|
||||
eq(tab2_win, api.nvim_tabpage_get_win(tab2))
|
||||
-- win lists should be correct
|
||||
eq({ tab2_win, win }, api.nvim_tabpage_list_wins(tab2))
|
||||
eq({ neighbor }, api.nvim_tabpage_list_wins(curtab))
|
||||
|
||||
eq({ tab1_win }, api.nvim_tabpage_list_wins(tab1))
|
||||
-- current win should have moved to neighboring win
|
||||
eq(neighbor, api.nvim_tabpage_get_win(curtab))
|
||||
eq(tab1_win, api.nvim_tabpage_get_win(tab1))
|
||||
|
||||
api.nvim_set_current_tabpage(tab2)
|
||||
-- convert new win to float
|
||||
api.nvim_win_set_config(win, { relative = 'editor', row = 2, col = 2, height = 2, width = 2 })
|
||||
api.nvim_set_current_win(win)
|
||||
api.nvim_win_set_config(win, { relative = 'win', win = tab1_win, row = 3, col = 3 })
|
||||
eq(tab1, api.nvim_win_get_tabpage(win))
|
||||
eq(tab2, api.nvim_get_current_tabpage())
|
||||
eq({ tab1_win, win }, api.nvim_tabpage_list_wins(tab1))
|
||||
end)
|
||||
|
||||
it('splits windows in non-current tabpage', function()
|
||||
@@ -2752,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()
|
||||
@@ -2797,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()
|
||||
@@ -2834,18 +2865,35 @@ describe('API/win', function()
|
||||
eq({ 'Leave', win, 'Enter', new_curwin }, eval('result'))
|
||||
end)
|
||||
|
||||
it('no autocmds when moving window within same tabpage', function()
|
||||
it('no autocmds when moving window in same or other tabpage', function()
|
||||
local parent = api.nvim_get_current_win()
|
||||
exec([[
|
||||
split
|
||||
let result = []
|
||||
autocmd WinEnter * let result += ["Enter", win_getid()]
|
||||
autocmd WinLeave * let result += ["Leave", win_getid()]
|
||||
autocmd WinNew * let result += ["New", win_getid()]
|
||||
let g:result = []
|
||||
autocmd WinEnter * let g:result += ["Enter", win_getid()]
|
||||
autocmd WinLeave * let g:result += ["Leave", win_getid()]
|
||||
autocmd WinNew * let g:result += ["New", win_getid()]
|
||||
]])
|
||||
api.nvim_win_set_config(0, { win = parent, split = 'left' })
|
||||
-- Shouldn't see any of those events, as we remain in the same window.
|
||||
eq({}, eval('result'))
|
||||
eq({}, eval('g:result'))
|
||||
|
||||
-- move float window from tab2 to tab1
|
||||
command('tabdo only')
|
||||
local tab1 = api.nvim_get_current_tabpage()
|
||||
local tab1_win1 = api.nvim_get_current_win()
|
||||
command('tabnew')
|
||||
local fwin = api.nvim_open_win(0, false, {
|
||||
relative = 'editor',
|
||||
row = 2,
|
||||
col = 2,
|
||||
height = 2,
|
||||
width = 2,
|
||||
})
|
||||
api.nvim_set_current_tabpage(tab1)
|
||||
api.nvim_set_var('result', {})
|
||||
api.nvim_win_set_config(fwin, { win = tab1_win1 })
|
||||
eq({}, eval('g:result'))
|
||||
end)
|
||||
|
||||
it('checks if splitting disallowed', function()
|
||||
@@ -3120,7 +3168,6 @@ describe('API/win', function()
|
||||
)
|
||||
command('quit!')
|
||||
|
||||
-- Can't switch away from window before moving it to a different tabpage during textlock.
|
||||
exec(([[
|
||||
new
|
||||
call setline(1, 'foo')
|
||||
@@ -3132,6 +3179,41 @@ describe('API/win', function()
|
||||
pcall_err(command, 'normal! ==')
|
||||
)
|
||||
eq(cur_win, api.nvim_get_current_win())
|
||||
exec(([[
|
||||
wincmd p
|
||||
call setline(1, 'bar')
|
||||
setlocal indentexpr=nvim_win_set_config(win_getid(winnr('#')),#{split:'left',win:%d})
|
||||
]]):format(t2_win))
|
||||
neq(cur_win, api.nvim_get_current_win())
|
||||
matches(
|
||||
'E565: Not allowed to change text or change window$',
|
||||
pcall_err(command, 'normal! ==')
|
||||
)
|
||||
-- expr_map_lock
|
||||
exec(([[
|
||||
nnoremap <expr> @ nvim_win_set_config(win_getid(winnr('#')),#{split:'left',win:%d})
|
||||
]]):format(t2_win))
|
||||
neq(cur_win, api.nvim_get_current_win())
|
||||
matches(
|
||||
'E565: Not allowed to change text or change window$',
|
||||
pcall_err(fn.feedkeys, '@', 'x')
|
||||
)
|
||||
|
||||
exec(([[
|
||||
wincmd p
|
||||
autocmd WinNewPre * ++once call nvim_win_set_config(0, #{relative:'editor', win:%d, row:0, col:0, width:1, height:1})
|
||||
]]):format(t2_win))
|
||||
matches(
|
||||
'E1312: Not allowed to change the window layout in this autocmd$',
|
||||
pcall_err(command, 'split')
|
||||
)
|
||||
eq(cur_win, api.nvim_get_current_win()) -- :split didn't enter new window due to error
|
||||
|
||||
exec(([[
|
||||
autocmd WinLeave * ++once call nvim_win_set_config(0, #{relative:'editor', win:%d, row:0, col:0, width:1, height:1})
|
||||
]]):format(t2_win))
|
||||
matches('Cannot move window to another tabpage whilst in use$', pcall_err(command, 'quit'))
|
||||
eq(cur_win, api.nvim_get_current_win()) -- :quit didn't close window due to error
|
||||
end)
|
||||
|
||||
it('updates statusline when moving bottom split', function()
|
||||
@@ -3190,6 +3272,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()
|
||||
@@ -3203,6 +3314,64 @@ describe('API/win', function()
|
||||
pcall_err(api.nvim_win_set_config, win, cfg)
|
||||
)
|
||||
end)
|
||||
|
||||
it('removes last statusline if needed', function()
|
||||
local screen = Screen.new(30, 9)
|
||||
command('set laststatus=1 | botright split')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*2
|
||||
{2:[No Name] }|
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
{3:[No Name] }|
|
||||
|
|
||||
]])
|
||||
api.nvim_win_set_config(0, { relative = 'editor', row = 0, col = 0, width = 4, height = 4 })
|
||||
screen:expect([[
|
||||
{4:^ } |
|
||||
{11:~ }{1: }|*3
|
||||
{1:~ }|*4
|
||||
|
|
||||
]])
|
||||
command('quit | set laststatus=2 | botright split')
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }|*2
|
||||
{2:[No Name] }|
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
{3:[No Name] }|
|
||||
|
|
||||
]])
|
||||
api.nvim_win_set_config(0, { relative = 'editor', row = 1, col = 5, width = 4, height = 4 })
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }{4:^ }{1: }|
|
||||
{1:~ }{11:~ }{1: }|*3
|
||||
{1:~ }|*2
|
||||
{2:[No Name] }|
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('can convert external window to non-external', function()
|
||||
Screen.new(20, 7, { ext_multigrid = true }) -- multigrid needed for external windows
|
||||
api.nvim_open_win(0, true, { external = true, width = 5, height = 5 })
|
||||
eq(true, api.nvim_win_get_config(0).external)
|
||||
api.nvim_win_set_config(0, { split = 'below', win = fn.win_getid(1) })
|
||||
eq(false, api.nvim_win_get_config(0).external)
|
||||
|
||||
api.nvim_win_set_config(0, { external = true, width = 5, height = 5 })
|
||||
eq(true, api.nvim_win_get_config(0).external)
|
||||
api.nvim_win_set_config(0, { relative = 'editor', row = 3, col = 3 })
|
||||
eq(false, api.nvim_win_get_config(0).external)
|
||||
|
||||
api.nvim_win_set_config(0, { external = true, width = 5, height = 5 })
|
||||
eq(true, api.nvim_win_get_config(0).external)
|
||||
api.nvim_win_set_config(0, { external = false })
|
||||
eq(false, api.nvim_win_get_config(0).external)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_config', function()
|
||||
@@ -3542,20 +3711,25 @@ describe('API/win', function()
|
||||
end)
|
||||
|
||||
it('cannot move autocmd window between tabpages', function()
|
||||
local win_type, split_ok, err = exec_lua(function()
|
||||
local win_type, split_ok, split_err, float_ok, float_err = exec_lua(function()
|
||||
local other_tp_win = vim.api.nvim_get_current_win()
|
||||
vim.cmd.tabnew()
|
||||
|
||||
local win_type, split_ok, err
|
||||
local win_type, split_ok, split_err, float_ok, float_err
|
||||
vim.api.nvim_buf_call(vim.api.nvim_create_buf(true, true), function()
|
||||
win_type = vim.fn.win_gettype()
|
||||
split_ok, err =
|
||||
|
||||
split_ok, split_err =
|
||||
pcall(vim.api.nvim_win_set_config, 0, { win = other_tp_win, split = 'right' })
|
||||
|
||||
float_ok, float_err = pcall(vim.api.nvim_win_set_config, 0, { win = other_tp_win })
|
||||
end)
|
||||
return win_type, split_ok, err
|
||||
return win_type, split_ok, split_err, float_ok, float_err
|
||||
end)
|
||||
|
||||
eq('autocmd', win_type)
|
||||
eq({ false, 'Cannot move autocmd window to another tabpage' }, { split_ok, err })
|
||||
eq({ false, 'Cannot move autocmd window to another tabpage' }, { split_ok, split_err })
|
||||
eq({ false, 'Cannot move autocmd window to another tabpage' }, { float_ok, float_err })
|
||||
end)
|
||||
|
||||
it('cannot move cmdwin between tabpages', function()
|
||||
@@ -3656,5 +3830,35 @@ describe('API/win', function()
|
||||
api.nvim_open_win(0, true, { split = 'below', style = 'minimal' })
|
||||
command('quit')
|
||||
end)
|
||||
|
||||
it('preserve current floating window when moving fails', function()
|
||||
local buf = api.nvim_create_buf(false, true)
|
||||
local float_win = api.nvim_open_win(buf, true, {
|
||||
relative = 'editor',
|
||||
row = 1,
|
||||
col = 1,
|
||||
width = 10,
|
||||
height = 5,
|
||||
})
|
||||
command('tabnew')
|
||||
local tab2_win = api.nvim_get_current_win()
|
||||
command('tabprev')
|
||||
api.nvim_set_current_win(float_win)
|
||||
command('autocmd WinLeave * ++once call nvim_win_close(' .. tab2_win .. ', v:true)')
|
||||
eq(
|
||||
'Target windows were closed',
|
||||
pcall_err(api.nvim_win_set_config, float_win, { win = tab2_win })
|
||||
)
|
||||
eq(float_win, api.nvim_get_current_win())
|
||||
|
||||
command('tabnew')
|
||||
local tab3_win = api.nvim_get_current_win()
|
||||
command('tabprev | autocmd WinEnter * ++once wincmd p')
|
||||
eq(
|
||||
('Failed to switch away from window %d'):format(float_win),
|
||||
pcall_err(api.nvim_win_set_config, float_win, { win = tab3_win })
|
||||
)
|
||||
eq(float_win, api.nvim_get_current_win())
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -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(
|
||||
"'win' key is only valid with relative='win' and relative=''",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, 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 })
|
||||
@@ -3824,6 +3821,18 @@ describe('float window', function()
|
||||
)
|
||||
eq("Must specify 'width'", pcall_err(api.nvim_open_win, buf, false, { relative = 'editor', row = 0, col = 0 }))
|
||||
eq("Must specify 'height'", pcall_err(api.nvim_open_win, buf, false, { relative = 'editor', row = 0, col = 0, width = 2 }))
|
||||
|
||||
if multigrid then
|
||||
eq(
|
||||
"external window cannot have 'win'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { external = true, win = 0, width = 10, height = 10 })
|
||||
)
|
||||
api.nvim_open_win(buf, true, { external = true, width = 10, height = 10 })
|
||||
eq("external window cannot have 'win'", pcall_err(api.nvim_win_set_config, 0, { win = 0 }))
|
||||
-- OK to include "win" if external window is also reconfigured to a normal float.
|
||||
api.nvim_win_set_config(0, { relative = 'editor', win = 0, row = 0, col = 0, width = 5, height = 5 })
|
||||
eq('editor', api.nvim_win_get_config(0).relative)
|
||||
end
|
||||
end)
|
||||
|
||||
it('can be placed relative window or cursor', function()
|
||||
@@ -7758,12 +7767,11 @@ describe('float window', function()
|
||||
screen:expect {
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*5
|
||||
{5:[No Name] [+] }|
|
||||
[2:----------------------------------------]|*6
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
x |
|
||||
{0:~ }|*4
|
||||
{0:~ }|*5
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
@@ -11191,6 +11199,19 @@ describe('float window', function()
|
||||
local winid = api.nvim_open_win(buf, false, config)
|
||||
api.nvim_set_current_win(winid)
|
||||
eq('floating window cannot be relative to itself', pcall_err(api.nvim_win_set_config, winid, config))
|
||||
eq('floating window cannot be relative to itself', pcall_err(api.nvim_win_set_config, winid, { win = winid }))
|
||||
-- Don't assume win=0 if no win given for existing relative=win float; so no error.
|
||||
api.nvim_win_set_config(winid, { width = 7 })
|
||||
eq(7, api.nvim_win_get_config(winid).width)
|
||||
-- Don't expect the error when configuring to something other than relative=win, as win=self
|
||||
-- is fine in those cases. (though maybe pointless) Other errors might be expected, though.
|
||||
eq('Cannot split a floating window', pcall_err(api.nvim_win_set_config, winid, { split = 'above', win = winid }))
|
||||
eq('win', api.nvim_win_get_config(winid).relative)
|
||||
api.nvim_win_set_config(winid, { relative = 'editor', win = winid, row = 3, col = 3 })
|
||||
eq('editor', api.nvim_win_get_config(winid).relative)
|
||||
-- An error when configuring split into relative=win float.
|
||||
command('split')
|
||||
eq('floating window cannot be relative to itself', pcall_err(api.nvim_win_set_config, 0, config))
|
||||
end)
|
||||
|
||||
it('bufpos out of range', function()
|
||||
@@ -11869,6 +11890,485 @@ describe('float window', function()
|
||||
]])
|
||||
end
|
||||
end)
|
||||
|
||||
it('redrawn after moving tabpages via nvim_win_set_config()', function()
|
||||
local tab1_win = api.nvim_get_current_win()
|
||||
fn.setline(1, 'hello')
|
||||
command('tab split')
|
||||
local tab2_win = api.nvim_get_current_win()
|
||||
-- Schedule an UPD_NOT_VALID redraw, but in one event move the float out of curtab before it's
|
||||
-- handled. Do not flush before then.
|
||||
local float = exec_lua(function()
|
||||
local float = vim.api.nvim_open_win(0, true, { relative = 'editor', width = 10, height = 5, row = 1, col = 1 })
|
||||
vim.api.nvim__redraw({ valid = false, flush = false })
|
||||
vim.api.nvim_win_set_config(float, { win = tab1_win })
|
||||
return float
|
||||
end)
|
||||
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
{9: }{10:2}{9:+ [No Name] }{3: + [No Name] }{5: }{9:X}|
|
||||
[4:----------------------------------------]|*5
|
||||
[3:----------------------------------------]|
|
||||
## grid 2 (hidden)
|
||||
hello |
|
||||
{0:~ }|*5
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
^hello |
|
||||
{0:~ }|*4
|
||||
]],
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{9: }{10:2}{9:+ [No Name] }{3: + [No Name] }{5: }{9:X}|
|
||||
^hello |
|
||||
{0:~ }|*4
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
-- Importantly, want tabline redrawn and float's hl attribs to be correct here.
|
||||
api.nvim_win_set_config(float, { win = 0 })
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
{9: + [No Name] }{3: }{11:2}{3:+ [No Name] }{5: }{9:X}|
|
||||
[4:----------------------------------------]|*5
|
||||
[3:----------------------------------------]|
|
||||
## grid 2 (hidden)
|
||||
hello |
|
||||
{0:~ }|*5
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
^hello |
|
||||
{0:~ }|*4
|
||||
## grid 5
|
||||
{1:hello }|
|
||||
{2:~ }|*4
|
||||
]],
|
||||
float_pos = {
|
||||
[5] = { 1002, 'NW', 1, 1, 1, true, 50, 1, 1, 1 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{9: + [No Name] }{3: }{11:2}{3:+ [No Name] }{5: }{9:X}|
|
||||
^h{1:hello } |
|
||||
{0:~}{2:~ }{0: }|*4
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
-- Autocommand runs within the first tabpage, but won't refresh grids when switching to it due
|
||||
-- to switch_win_noblock having no_display set.
|
||||
command(
|
||||
('autocmd OptionSet rightleft ++once call nvim_win_set_config(%d, #{relative: "win", win: %d, row: 0, col: 0})'):format(
|
||||
float,
|
||||
tab1_win
|
||||
)
|
||||
)
|
||||
api.nvim_set_option_value('rightleft', true, { win = tab1_win })
|
||||
-- Stale grids should not have caused issues with removing the float's grid.
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
{9: }{10:2}{9:+ [No Name] }{3: + [No Name] }{5: }{9:X}|
|
||||
[4:----------------------------------------]|*5
|
||||
[3:----------------------------------------]|
|
||||
## grid 2 (hidden)
|
||||
hello |
|
||||
{0:~ }|*5
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
^hello |
|
||||
{0:~ }|*4
|
||||
## grid 5 (hidden)
|
||||
{1:hello }|
|
||||
{2:~ }|*4
|
||||
]],
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{9: }{10:2}{9:+ [No Name] }{3: + [No Name] }{5: }{9:X}|
|
||||
^hello |
|
||||
{0:~ }|*4
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
command('tabfirst')
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
{3: }{11:2}{3:+ [No Name] }{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
|
||||
{1:hello }|
|
||||
{2:~ }|*4
|
||||
]],
|
||||
float_pos = {
|
||||
[5] = { 1002, 'NW', 2, 0, 0, true, 50, 1, 1, 0 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{3: }{11:2}{3:+ [No Name] }{9: + [No Name] }{5: }{9:X}|
|
||||
{1:hello } olle^h|
|
||||
{2:~ }{0: ~}|*4
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
-- 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 = [[
|
||||
## grid 1
|
||||
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{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
|
||||
]],
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{9: }{10:2}{9:+ No Name] }{3: [No Name] }{9: + [No Name] }{5: }{9:X}|
|
||||
^ |
|
||||
{0: ~}|*4
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
api.nvim_win_set_config(float, { win = tab2_win })
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
{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
|
||||
]],
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
{9: + [No Name] }{3: [No Name] }{9: }{10:2}{9:+ No Name] }{5: }{9:X}|
|
||||
^ |
|
||||
{0: ~}|*4
|
||||
|
|
||||
]])
|
||||
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
|
||||
|
||||
describe('with ext_multigrid and actual mouse grid', function()
|
||||
|
||||
@@ -2346,8 +2346,7 @@ describe('ui/ext_messages', function()
|
||||
screen:expect([[
|
||||
|
|
||||
{1:~ }{4:^ }{1: }|
|
||||
{1:~ }|*21
|
||||
{2:[No Name] }|
|
||||
{1:~ }|*22
|
||||
]])
|
||||
end)
|
||||
|
||||
|
||||
@@ -1795,9 +1795,14 @@ local function fmt_ext_state(name, state)
|
||||
elseif name == 'float_pos' then
|
||||
local str = '{\n'
|
||||
for k, v in pairs(state) do
|
||||
str = str .. ' [' .. k .. '] = {' .. v[1]
|
||||
for i = 2, #v do
|
||||
str = str .. ', ' .. inspect(v[i])
|
||||
str = str .. ' [' .. k .. '] = {'
|
||||
if v.external then
|
||||
str = str .. ' external = true '
|
||||
else
|
||||
str = str .. v[1]
|
||||
for i = 2, #v do
|
||||
str = str .. ', ' .. inspect(v[i])
|
||||
end
|
||||
end
|
||||
str = str .. '};\n'
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user