mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(api): make nvim_open_win support non-floating windows (#25550)
Adds support to `nvim_open_win` and `nvim_win_set_config` for creating and manipulating split (non-floating) windows.
This commit is contained in:
parent
8fa67fdae5
commit
6bba4beced
@ -3093,18 +3093,28 @@ nvim_win_text_height({window}, {*opts}) *nvim_win_text_height()*
|
|||||||
Win_Config Functions *api-win_config*
|
Win_Config Functions *api-win_config*
|
||||||
|
|
||||||
nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
|
nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
|
||||||
Open a new window.
|
Opens a new split window, or a floating window if `relative` is specified,
|
||||||
|
or an external window (managed by the UI) if `external` is specified.
|
||||||
|
|
||||||
Currently this is used to open floating and external windows. Floats are
|
Floats are windows that are drawn above the split layout, at some anchor
|
||||||
windows that are drawn above the split layout, at some anchor position in
|
position in some other window. Floats can be drawn internally or by
|
||||||
some other window. Floats can be drawn internally or by external GUI with
|
external GUI with the |ui-multigrid| extension. External windows are only
|
||||||
the |ui-multigrid| extension. External windows are only supported with
|
supported with multigrid GUIs, and are displayed as separate top-level
|
||||||
multigrid GUIs, and are displayed as separate top-level windows.
|
windows.
|
||||||
|
|
||||||
For a general overview of floats, see |api-floatwin|.
|
For a general overview of floats, see |api-floatwin|.
|
||||||
|
|
||||||
Exactly one of `external` and `relative` must be specified. The `width`
|
The `width` and `height` of the new window must be specified when opening
|
||||||
and `height` of the new window must be specified.
|
a floating window, but are optional for normal windows.
|
||||||
|
|
||||||
|
If `relative` and `external` are omitted, a normal "split" window is
|
||||||
|
created. The `win` property determines which window will be split. If no
|
||||||
|
`win` is provided or `win == 0`, a window will be created adjacent to the
|
||||||
|
current window. If -1 is provided, a top-level split will be created.
|
||||||
|
`vertical` and `split` are only valid for normal windows, and are used to
|
||||||
|
control split direction. For `vertical`, the exact direction is determined
|
||||||
|
by |'splitright'| and |'splitbelow'|. Split windows cannot have
|
||||||
|
`bufpos`/`row`/`col`/`border`/`title`/`footer` properties.
|
||||||
|
|
||||||
With relative=editor (row=0,col=0) refers to the top-left corner of the
|
With relative=editor (row=0,col=0) refers to the top-left corner of the
|
||||||
screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
||||||
@ -3127,6 +3137,13 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
|
|||||||
{relative='win', width=12, height=3, bufpos={100,10}})
|
{relative='win', width=12, height=3, bufpos={100,10}})
|
||||||
<
|
<
|
||||||
|
|
||||||
|
Example (Lua): vertical split left of the current window >lua
|
||||||
|
vim.api.nvim_open_win(0, false, {
|
||||||
|
split = 'left',
|
||||||
|
win = 0
|
||||||
|
})
|
||||||
|
<
|
||||||
|
|
||||||
Attributes: ~
|
Attributes: ~
|
||||||
not allowed when |textlock| is active
|
not allowed when |textlock| is active
|
||||||
|
|
||||||
@ -3142,7 +3159,8 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
|
|||||||
• "cursor" Cursor position in current window.
|
• "cursor" Cursor position in current window.
|
||||||
• "mouse" Mouse position
|
• "mouse" Mouse position
|
||||||
|
|
||||||
• win: |window-ID| for relative="win".
|
• win: |window-ID| window to split, or relative window when
|
||||||
|
creating a float (relative="win").
|
||||||
• anchor: Decides which corner of the float to place at
|
• anchor: Decides which corner of the float to place at
|
||||||
(row,col):
|
(row,col):
|
||||||
• "NW" northwest (default)
|
• "NW" northwest (default)
|
||||||
@ -3239,6 +3257,8 @@ nvim_open_win({buffer}, {enter}, {*config}) *nvim_open_win()*
|
|||||||
• fixed: If true when anchor is NW or SW, the float window
|
• fixed: If true when anchor is NW or SW, the float window
|
||||||
would be kept fixed even if the window would be truncated.
|
would be kept fixed even if the window would be truncated.
|
||||||
• hide: If true the floating window will be hidden.
|
• hide: If true the floating window will be hidden.
|
||||||
|
• vertical: Split vertically |:vertical|.
|
||||||
|
• split: Split direction: "left", "right", "above", "below".
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
Window handle, or 0 on error
|
Window handle, or 0 on error
|
||||||
|
@ -406,6 +406,9 @@ The following changes to existing APIs or features add new behavior.
|
|||||||
• |:checkhealth| buffer can now be opened in a split window using modifiers like
|
• |:checkhealth| buffer can now be opened in a split window using modifiers like
|
||||||
|:vertical|, |:horizontal| and |:botright|.
|
|:vertical|, |:horizontal| and |:botright|.
|
||||||
|
|
||||||
|
• |nvim_open_win()| and |nvim_win_set_config()| now support opening normal (split)
|
||||||
|
windows, and moving floating windows into split windows.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
REMOVED FEATURES *news-removed*
|
REMOVED FEATURES *news-removed*
|
||||||
|
|
||||||
|
39
runtime/lua/vim/_meta/api.lua
generated
39
runtime/lua/vim/_meta/api.lua
generated
@ -1483,15 +1483,24 @@ function vim.api.nvim_notify(msg, log_level, opts) end
|
|||||||
--- @return integer
|
--- @return integer
|
||||||
function vim.api.nvim_open_term(buffer, opts) end
|
function vim.api.nvim_open_term(buffer, opts) end
|
||||||
|
|
||||||
--- Open a new window.
|
--- Opens a new split window, or a floating window if `relative` is specified,
|
||||||
--- Currently this is used to open floating and external windows. Floats are
|
--- or an external window (managed by the UI) if `external` is specified.
|
||||||
--- windows that are drawn above the split layout, at some anchor position in
|
--- Floats are windows that are drawn above the split layout, at some anchor
|
||||||
--- some other window. Floats can be drawn internally or by external GUI with
|
--- position in some other window. Floats can be drawn internally or by
|
||||||
--- the `ui-multigrid` extension. External windows are only supported with
|
--- external GUI with the `ui-multigrid` extension. External windows are only
|
||||||
--- multigrid GUIs, and are displayed as separate top-level windows.
|
--- supported with multigrid GUIs, and are displayed as separate top-level
|
||||||
|
--- windows.
|
||||||
--- For a general overview of floats, see `api-floatwin`.
|
--- For a general overview of floats, see `api-floatwin`.
|
||||||
--- Exactly one of `external` and `relative` must be specified. The `width`
|
--- The `width` and `height` of the new window must be specified when opening
|
||||||
--- and `height` of the new window must be specified.
|
--- a floating window, but are optional for normal windows.
|
||||||
|
--- If `relative` and `external` are omitted, a normal "split" window is
|
||||||
|
--- created. The `win` property determines which window will be split. If no
|
||||||
|
--- `win` is provided or `win == 0`, a window will be created adjacent to the
|
||||||
|
--- current window. If -1 is provided, a top-level split will be created.
|
||||||
|
--- `vertical` and `split` are only valid for normal windows, and are used to
|
||||||
|
--- control split direction. For `vertical`, the exact direction is determined
|
||||||
|
--- by `'splitright'` and `'splitbelow'`. Split windows cannot have
|
||||||
|
--- `bufpos`/`row`/`col`/`border`/`title`/`footer` properties.
|
||||||
--- With relative=editor (row=0,col=0) refers to the top-left corner of the
|
--- With relative=editor (row=0,col=0) refers to the top-left corner of the
|
||||||
--- screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
--- screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
||||||
--- corner. Fractional values are allowed, but the builtin implementation
|
--- corner. Fractional values are allowed, but the builtin implementation
|
||||||
@ -1515,6 +1524,15 @@ function vim.api.nvim_open_term(buffer, opts) end
|
|||||||
--- {relative='win', width=12, height=3, bufpos={100,10}})
|
--- {relative='win', width=12, height=3, bufpos={100,10}})
|
||||||
--- ```
|
--- ```
|
||||||
---
|
---
|
||||||
|
--- Example (Lua): vertical split left of the current window
|
||||||
|
---
|
||||||
|
--- ```lua
|
||||||
|
--- vim.api.nvim_open_win(0, false, {
|
||||||
|
--- split = 'left',
|
||||||
|
--- win = 0
|
||||||
|
--- })
|
||||||
|
--- ```
|
||||||
|
---
|
||||||
--- @param buffer integer Buffer to display, or 0 for current buffer
|
--- @param buffer integer Buffer to display, or 0 for current buffer
|
||||||
--- @param enter boolean Enter the window (make it the current window)
|
--- @param enter boolean Enter the window (make it the current window)
|
||||||
--- @param config vim.api.keyset.float_config Map defining the window configuration. Keys:
|
--- @param config vim.api.keyset.float_config Map defining the window configuration. Keys:
|
||||||
@ -1526,7 +1544,8 @@ function vim.api.nvim_open_term(buffer, opts) end
|
|||||||
--- • "cursor" Cursor position in current window.
|
--- • "cursor" Cursor position in current window.
|
||||||
--- • "mouse" Mouse position
|
--- • "mouse" Mouse position
|
||||||
---
|
---
|
||||||
--- • win: `window-ID` for relative="win".
|
--- • win: `window-ID` window to split, or relative window when
|
||||||
|
--- creating a float (relative="win").
|
||||||
--- • anchor: Decides which corner of the float to place at
|
--- • anchor: Decides which corner of the float to place at
|
||||||
--- (row,col):
|
--- (row,col):
|
||||||
--- • "NW" northwest (default)
|
--- • "NW" northwest (default)
|
||||||
@ -1623,6 +1642,8 @@ function vim.api.nvim_open_term(buffer, opts) end
|
|||||||
--- • fixed: If true when anchor is NW or SW, the float window
|
--- • fixed: If true when anchor is NW or SW, the float window
|
||||||
--- would be kept fixed even if the window would be truncated.
|
--- would be kept fixed even if the window would be truncated.
|
||||||
--- • hide: If true the floating window will be hidden.
|
--- • hide: If true the floating window will be hidden.
|
||||||
|
--- • vertical: Split vertically `:vertical`.
|
||||||
|
--- • split: Split direction: "left", "right", "above", "below".
|
||||||
--- @return integer
|
--- @return integer
|
||||||
function vim.api.nvim_open_win(buffer, enter, config) end
|
function vim.api.nvim_open_win(buffer, enter, config) end
|
||||||
|
|
||||||
|
2
runtime/lua/vim/_meta/api_keysets.lua
generated
2
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -118,10 +118,12 @@ error('Cannot require a meta file')
|
|||||||
--- @field height? integer
|
--- @field height? integer
|
||||||
--- @field anchor? string
|
--- @field anchor? string
|
||||||
--- @field relative? string
|
--- @field relative? string
|
||||||
|
--- @field split? string
|
||||||
--- @field win? integer
|
--- @field win? integer
|
||||||
--- @field bufpos? any[]
|
--- @field bufpos? any[]
|
||||||
--- @field external? boolean
|
--- @field external? boolean
|
||||||
--- @field focusable? boolean
|
--- @field focusable? boolean
|
||||||
|
--- @field vertical? boolean
|
||||||
--- @field zindex? integer
|
--- @field zindex? integer
|
||||||
--- @field border? any
|
--- @field border? any
|
||||||
--- @field title? any
|
--- @field title? any
|
||||||
|
@ -115,10 +115,12 @@ typedef struct {
|
|||||||
Integer height;
|
Integer height;
|
||||||
String anchor;
|
String anchor;
|
||||||
String relative;
|
String relative;
|
||||||
|
String split;
|
||||||
Window win;
|
Window win;
|
||||||
Array bufpos;
|
Array bufpos;
|
||||||
Boolean external;
|
Boolean external;
|
||||||
Boolean focusable;
|
Boolean focusable;
|
||||||
|
Boolean vertical;
|
||||||
Integer zindex;
|
Integer zindex;
|
||||||
Object border;
|
Object border;
|
||||||
Object title;
|
Object title;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "nvim/api/private/defs.h"
|
#include "nvim/api/private/defs.h"
|
||||||
#include "nvim/api/private/dispatch.h"
|
#include "nvim/api/private/dispatch.h"
|
||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
|
#include "nvim/api/tabpage.h"
|
||||||
#include "nvim/api/win_config.h"
|
#include "nvim/api/win_config.h"
|
||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/autocmd.h"
|
#include "nvim/autocmd.h"
|
||||||
@ -15,6 +16,8 @@
|
|||||||
#include "nvim/decoration.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/decoration_defs.h"
|
#include "nvim/decoration_defs.h"
|
||||||
#include "nvim/drawscreen.h"
|
#include "nvim/drawscreen.h"
|
||||||
|
#include "nvim/eval/window.h"
|
||||||
|
#include "nvim/extmark_defs.h"
|
||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/grid_defs.h"
|
#include "nvim/grid_defs.h"
|
||||||
#include "nvim/highlight_group.h"
|
#include "nvim/highlight_group.h"
|
||||||
@ -22,12 +25,15 @@
|
|||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
|
#include "nvim/option_vars.h"
|
||||||
#include "nvim/pos_defs.h"
|
#include "nvim/pos_defs.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
#include "nvim/ui.h"
|
#include "nvim/ui.h"
|
||||||
|
#include "nvim/ui_compositor.h"
|
||||||
#include "nvim/ui_defs.h"
|
#include "nvim/ui_defs.h"
|
||||||
|
#include "nvim/vim_defs.h"
|
||||||
#include "nvim/window.h"
|
#include "nvim/window.h"
|
||||||
#include "nvim/winfloat.h"
|
#include "nvim/winfloat.h"
|
||||||
|
|
||||||
@ -35,9 +41,9 @@
|
|||||||
# include "api/win_config.c.generated.h"
|
# include "api/win_config.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Open a new window.
|
/// Opens a new split window, or a floating window if `relative` is specified,
|
||||||
|
/// or an external window (managed by the UI) if `external` is specified.
|
||||||
///
|
///
|
||||||
/// Currently this is used to open floating and external windows.
|
|
||||||
/// Floats are windows that are drawn above the split layout, at some anchor
|
/// Floats are windows that are drawn above the split layout, at some anchor
|
||||||
/// position in some other window. Floats can be drawn internally or by external
|
/// position in some other window. Floats can be drawn internally or by external
|
||||||
/// GUI with the |ui-multigrid| extension. External windows are only supported
|
/// GUI with the |ui-multigrid| extension. External windows are only supported
|
||||||
@ -45,8 +51,17 @@
|
|||||||
///
|
///
|
||||||
/// For a general overview of floats, see |api-floatwin|.
|
/// For a general overview of floats, see |api-floatwin|.
|
||||||
///
|
///
|
||||||
/// Exactly one of `external` and `relative` must be specified. The `width` and
|
/// The `width` and `height` of the new window must be specified when opening
|
||||||
/// `height` of the new window must be specified.
|
/// a floating window, but are optional for normal windows.
|
||||||
|
///
|
||||||
|
/// If `relative` and `external` are omitted, a normal "split" window is created.
|
||||||
|
/// The `win` property determines which window will be split. If no `win` is
|
||||||
|
/// provided or `win == 0`, a window will be created adjacent to the current window.
|
||||||
|
/// If -1 is provided, a top-level split will be created. `vertical` and `split` are
|
||||||
|
/// only valid for normal windows, and are used to control split direction. For `vertical`,
|
||||||
|
/// the exact direction is determined by |'splitright'| and |'splitbelow'|.
|
||||||
|
/// Split windows cannot have `bufpos`/`row`/`col`/`border`/`title`/`footer`
|
||||||
|
/// properties.
|
||||||
///
|
///
|
||||||
/// With relative=editor (row=0,col=0) refers to the top-left corner of the
|
/// With relative=editor (row=0,col=0) refers to the top-left corner of the
|
||||||
/// screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
/// screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right
|
||||||
@ -73,6 +88,15 @@
|
|||||||
/// {relative='win', width=12, height=3, bufpos={100,10}})
|
/// {relative='win', width=12, height=3, bufpos={100,10}})
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// Example (Lua): vertical split left of the current window
|
||||||
|
///
|
||||||
|
/// ```lua
|
||||||
|
/// vim.api.nvim_open_win(0, false, {
|
||||||
|
/// split = 'left',
|
||||||
|
/// win = 0
|
||||||
|
/// })
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// @param buffer Buffer to display, or 0 for current buffer
|
/// @param buffer Buffer to display, or 0 for current buffer
|
||||||
/// @param enter Enter the window (make it the current window)
|
/// @param enter Enter the window (make it the current window)
|
||||||
/// @param config Map defining the window configuration. Keys:
|
/// @param config Map defining the window configuration. Keys:
|
||||||
@ -82,7 +106,8 @@
|
|||||||
/// - "win" Window given by the `win` field, or current window.
|
/// - "win" Window given by the `win` field, or current window.
|
||||||
/// - "cursor" Cursor position in current window.
|
/// - "cursor" Cursor position in current window.
|
||||||
/// - "mouse" Mouse position
|
/// - "mouse" Mouse position
|
||||||
/// - win: |window-ID| for relative="win".
|
/// - win: |window-ID| window to split, or relative window when creating a
|
||||||
|
/// float (relative="win").
|
||||||
/// - anchor: Decides which corner of the float to place at (row,col):
|
/// - anchor: Decides which corner of the float to place at (row,col):
|
||||||
/// - "NW" northwest (default)
|
/// - "NW" northwest (default)
|
||||||
/// - "NE" northeast
|
/// - "NE" northeast
|
||||||
@ -169,13 +194,14 @@
|
|||||||
/// - fixed: If true when anchor is NW or SW, the float window
|
/// - fixed: If true when anchor is NW or SW, the float window
|
||||||
/// would be kept fixed even if the window would be truncated.
|
/// would be kept fixed even if the window would be truncated.
|
||||||
/// - hide: If true the floating window will be hidden.
|
/// - hide: If true the floating window will be hidden.
|
||||||
|
/// - vertical: Split vertically |:vertical|.
|
||||||
|
/// - split: Split direction: "left", "right", "above", "below".
|
||||||
///
|
///
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
///
|
///
|
||||||
/// @return Window handle, or 0 on error
|
/// @return Window handle, or 0 on error
|
||||||
Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err)
|
Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err)
|
||||||
FUNC_API_SINCE(6)
|
FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||||
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
|
||||||
{
|
{
|
||||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
@ -190,22 +216,67 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E
|
|||||||
if (!parse_float_config(config, &fconfig, false, true, err)) {
|
if (!parse_float_config(config, &fconfig, false, true, err)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
win_T *wp = win_new_float(NULL, false, fconfig, err);
|
|
||||||
|
bool is_split = HAS_KEY(config, float_config, split) || HAS_KEY(config, float_config, vertical);
|
||||||
|
|
||||||
|
win_T *wp = NULL;
|
||||||
|
tabpage_T *tp = curtab;
|
||||||
|
if (is_split) {
|
||||||
|
win_T *parent = NULL;
|
||||||
|
if (!HAS_KEY(config, float_config, win) || config->win != -1) {
|
||||||
|
parent = find_window_by_handle(fconfig.window, err);
|
||||||
|
if (!parent) {
|
||||||
|
// find_window_by_handle has already set the error
|
||||||
|
return 0;
|
||||||
|
} else if (parent->w_floating) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Cannot split a floating window");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY(config, float_config, vertical) && !HAS_KEY(config, float_config, split)) {
|
||||||
|
if (config->vertical) {
|
||||||
|
fconfig.split = p_spr ? kWinSplitRight : kWinSplitLeft;
|
||||||
|
} else {
|
||||||
|
fconfig.split = p_sb ? kWinSplitBelow : kWinSplitAbove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER;
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
wp = win_split_ins(0, flags, NULL, 0);
|
||||||
|
} else {
|
||||||
|
tp = win_find_tabpage(parent);
|
||||||
|
switchwin_T switchwin;
|
||||||
|
// `parent` is valid in `tp`, so switch_win should not fail.
|
||||||
|
const int result = switch_win(&switchwin, parent, tp, true);
|
||||||
|
(void)result;
|
||||||
|
assert(result == OK);
|
||||||
|
wp = win_split_ins(0, flags, NULL, 0);
|
||||||
|
restore_win(&switchwin, true);
|
||||||
|
}
|
||||||
|
if (wp) {
|
||||||
|
wp->w_float_config = fconfig;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wp = win_new_float(NULL, false, fconfig, err);
|
||||||
|
}
|
||||||
if (!wp) {
|
if (!wp) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to create window");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
switchwin_T switchwin;
|
||||||
|
if (switch_win_noblock(&switchwin, wp, tp, true) == OK) {
|
||||||
|
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
|
||||||
|
}
|
||||||
|
restore_win_noblock(&switchwin, true);
|
||||||
if (enter) {
|
if (enter) {
|
||||||
win_enter(wp, false);
|
goto_tabpage_win(tp, wp);
|
||||||
}
|
}
|
||||||
// autocmds in win_enter or win_set_buf below may close the window
|
if (win_valid_any_tab(wp) && buf != wp->w_buffer) {
|
||||||
if (win_valid(wp) && buffer > 0) {
|
win_set_buf(wp, buf, !enter || fconfig.noautocmd, err);
|
||||||
Boolean noautocmd = !enter || fconfig.noautocmd;
|
|
||||||
win_set_buf(wp, buf, noautocmd, err);
|
|
||||||
if (!fconfig.noautocmd) {
|
|
||||||
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!win_valid(wp)) {
|
if (!win_valid_any_tab(wp)) {
|
||||||
api_set_error(err, kErrorTypeException, "Window was closed immediately");
|
api_set_error(err, kErrorTypeException, "Window was closed immediately");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -217,6 +288,36 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E
|
|||||||
return wp->handle;
|
return wp->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static WinSplit win_split_dir(win_T *win)
|
||||||
|
{
|
||||||
|
if (win->w_frame == NULL || win->w_frame->fr_parent == NULL) {
|
||||||
|
return kWinSplitLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
char layout = win->w_frame->fr_parent->fr_layout;
|
||||||
|
if (layout == FR_COL) {
|
||||||
|
return win->w_frame->fr_next ? kWinSplitAbove : kWinSplitBelow;
|
||||||
|
} else {
|
||||||
|
return win->w_frame->fr_next ? kWinSplitLeft : kWinSplitRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int win_split_flags(WinSplit split, bool toplevel)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
if (split == kWinSplitAbove || split == kWinSplitBelow) {
|
||||||
|
flags |= WSP_HOR;
|
||||||
|
} else {
|
||||||
|
flags |= WSP_VERT;
|
||||||
|
}
|
||||||
|
if (split == kWinSplitAbove || split == kWinSplitLeft) {
|
||||||
|
flags |= toplevel ? WSP_TOP : WSP_ABOVE;
|
||||||
|
} else {
|
||||||
|
flags |= toplevel ? WSP_BOT : WSP_BELOW;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
/// Configures window layout. Currently only for floating and external windows
|
/// Configures window layout. Currently only for floating and external windows
|
||||||
/// (including changing a split window to those layouts).
|
/// (including changing a split window to those layouts).
|
||||||
///
|
///
|
||||||
@ -236,18 +337,195 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
|
|||||||
if (!win) {
|
if (!win) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool new_float = !win->w_floating;
|
tabpage_T *win_tp = win_find_tabpage(win);
|
||||||
|
bool was_split = !win->w_floating;
|
||||||
|
bool has_split = HAS_KEY(config, float_config, split);
|
||||||
|
bool has_vertical = HAS_KEY(config, float_config, vertical);
|
||||||
// reuse old values, if not overridden
|
// reuse old values, if not overridden
|
||||||
FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config;
|
FloatConfig fconfig = win->w_float_config;
|
||||||
|
|
||||||
if (!parse_float_config(config, &fconfig, !new_float, false, err)) {
|
bool to_split = (!HAS_KEY(config, float_config, relative) || striequal(config->relative.data, ""))
|
||||||
|
&& ((!HAS_KEY(config, float_config, external) && !fconfig.external)
|
||||||
|
|| !config->external)
|
||||||
|
&& (has_split || has_vertical || was_split);
|
||||||
|
|
||||||
|
if (!parse_float_config(config, &fconfig, !was_split || to_split, false, err)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (new_float) {
|
if (was_split && !to_split) {
|
||||||
if (!win_new_float(win, false, fconfig, err)) {
|
if (!win_new_float(win, false, fconfig, err)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
redraw_later(win, UPD_NOT_VALID);
|
redraw_later(win, UPD_NOT_VALID);
|
||||||
|
} else if (to_split) {
|
||||||
|
win_T *parent = NULL;
|
||||||
|
if (!HAS_KEY(config, float_config, win) || config->win != -1) {
|
||||||
|
parent = find_window_by_handle(fconfig.window, err);
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
} else if (parent->w_floating) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Cannot split a floating window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WinSplit old_split = win_split_dir(win);
|
||||||
|
if (has_vertical && !has_split) {
|
||||||
|
if (config->vertical) {
|
||||||
|
if (old_split == kWinSplitRight || p_spr) {
|
||||||
|
fconfig.split = kWinSplitRight;
|
||||||
|
} else {
|
||||||
|
fconfig.split = kWinSplitLeft;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (old_split == kWinSplitBelow || p_sb) {
|
||||||
|
fconfig.split = kWinSplitBelow;
|
||||||
|
} else {
|
||||||
|
fconfig.split = kWinSplitAbove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
win->w_float_config = fconfig;
|
||||||
|
|
||||||
|
// If there's no vertical or split set, or if the split is the same as the old split,
|
||||||
|
// then we can just change the size of the window.
|
||||||
|
if ((!has_vertical && !has_split)
|
||||||
|
|| (was_split
|
||||||
|
&& !HAS_KEY(config, float_config,
|
||||||
|
win) && ((!has_split && !has_vertical) || old_split == fconfig.split))) {
|
||||||
|
if (HAS_KEY(config, float_config, width)) {
|
||||||
|
win_setwidth_win(fconfig.width, win);
|
||||||
|
}
|
||||||
|
if (HAS_KEY(config, float_config, height)) {
|
||||||
|
win_setheight_win(fconfig.height, win);
|
||||||
|
}
|
||||||
|
redraw_later(win, UPD_NOT_VALID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (was_split) {
|
||||||
|
win_T *new_curwin = NULL;
|
||||||
|
|
||||||
|
// If the window is the last in the tabpage or `fconfig.win` is
|
||||||
|
// a handle to itself, we can't split it.
|
||||||
|
if (win->w_frame->fr_parent == NULL) {
|
||||||
|
// FIXME(willothy): if the window is the last in the tabpage but there is another tabpage
|
||||||
|
// and the target window is in that other tabpage, should we move the window to that
|
||||||
|
// tabpage and close the previous one, or just error?
|
||||||
|
api_set_error(err, kErrorTypeValidation, "Cannot move last window");
|
||||||
|
return;
|
||||||
|
} else if (parent != NULL && parent->handle == win->handle) {
|
||||||
|
int n_frames = 0;
|
||||||
|
for (frame_T *fr = win->w_frame->fr_parent->fr_child; fr != NULL; fr = fr->fr_next) {
|
||||||
|
n_frames++;
|
||||||
|
}
|
||||||
|
|
||||||
|
win_T *neighbor = NULL;
|
||||||
|
|
||||||
|
if (n_frames > 2) {
|
||||||
|
// There are three or more windows in the frame, we need to split a neighboring window.
|
||||||
|
frame_T *frame = win->w_frame->fr_parent;
|
||||||
|
|
||||||
|
if (frame->fr_parent) {
|
||||||
|
// ┌──────────────┐
|
||||||
|
// │ A │
|
||||||
|
// ├────┬────┬────┤
|
||||||
|
// │ B │ C │ D │
|
||||||
|
// └────┴────┴────┘
|
||||||
|
// ||
|
||||||
|
// \/
|
||||||
|
// ┌───────────────────┐
|
||||||
|
// │ A │
|
||||||
|
// ├─────────┬─────────┤
|
||||||
|
// │ │ C │
|
||||||
|
// │ B ├─────────┤
|
||||||
|
// │ │ D │
|
||||||
|
// └─────────┴─────────┘
|
||||||
|
if (fconfig.split == kWinSplitAbove || fconfig.split == kWinSplitLeft) {
|
||||||
|
neighbor = win->w_next;
|
||||||
|
} else {
|
||||||
|
neighbor = win->w_prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the frame doesn't have a parent, the old frame
|
||||||
|
// was the root frame and we need to create a top-level split.
|
||||||
|
int dir;
|
||||||
|
new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp);
|
||||||
|
} else if (n_frames == 2) {
|
||||||
|
// There are two windows in the frame, we can just rotate it.
|
||||||
|
int dir;
|
||||||
|
neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp);
|
||||||
|
new_curwin = neighbor;
|
||||||
|
} else {
|
||||||
|
// There is only one window in the frame, we can't split it.
|
||||||
|
api_set_error(err, kErrorTypeValidation, "Cannot split window into itself");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Set the parent to whatever the correct
|
||||||
|
// neighbor window was determined to be.
|
||||||
|
parent = neighbor;
|
||||||
|
} else {
|
||||||
|
int dir;
|
||||||
|
new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp);
|
||||||
|
}
|
||||||
|
// move to neighboring window if we're moving the current window to a new tabpage
|
||||||
|
if (curwin == win && parent != NULL && new_curwin != NULL
|
||||||
|
&& win_tp != win_find_tabpage(parent)) {
|
||||||
|
win_enter(new_curwin, true);
|
||||||
|
}
|
||||||
|
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
||||||
|
} else {
|
||||||
|
win_remove(win, win_tp == curtab ? NULL : win_tp);
|
||||||
|
ui_comp_remove_grid(&win->w_grid_alloc);
|
||||||
|
if (win->w_float_config.external) {
|
||||||
|
for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
|
||||||
|
if (tp == curtab) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tp->tp_curwin == win) {
|
||||||
|
tp->tp_curwin = tp->tp_firstwin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
win->w_pos_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = win_split_flags(fconfig.split, parent == NULL);
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
if (!win_split_ins(0, flags, win, 0)) {
|
||||||
|
// TODO(willothy): What should this error message say?
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to split window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
win_execute_T args;
|
||||||
|
|
||||||
|
tabpage_T *tp = win_find_tabpage(parent);
|
||||||
|
if (!win_execute_before(&args, parent, tp)) {
|
||||||
|
// TODO(willothy): how should we handle this / what should the message be?
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to switch to tabpage %d", tp->handle);
|
||||||
|
win_execute_after(&args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// This should return the same ptr to `win`, but we check for
|
||||||
|
// NULL to detect errors.
|
||||||
|
win_T *res = win_split_ins(0, flags, win, 0);
|
||||||
|
win_execute_after(&args);
|
||||||
|
if (!res) {
|
||||||
|
// TODO(willothy): What should this error message say?
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to split window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (HAS_KEY(config, float_config, width)) {
|
||||||
|
win_setwidth_win(fconfig.width, win);
|
||||||
|
}
|
||||||
|
if (HAS_KEY(config, float_config, height)) {
|
||||||
|
win_setheight_win(fconfig.height, win);
|
||||||
|
}
|
||||||
|
redraw_later(win, UPD_NOT_VALID);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
win_config_float(win, fconfig);
|
win_config_float(win, fconfig);
|
||||||
win->w_pos_changed = true;
|
win->w_pos_changed = true;
|
||||||
@ -317,6 +595,9 @@ Dictionary nvim_win_get_config(Window window, Error *err)
|
|||||||
/// Keep in sync with FloatRelative in buffer_defs.h
|
/// Keep in sync with FloatRelative in buffer_defs.h
|
||||||
static const char *const float_relative_str[] = { "editor", "win", "cursor", "mouse" };
|
static const char *const float_relative_str[] = { "editor", "win", "cursor", "mouse" };
|
||||||
|
|
||||||
|
/// Keep in sync with WinSplit in buffer_defs.h
|
||||||
|
static const char *const win_split_str[] = { "left", "right", "above", "below" };
|
||||||
|
|
||||||
Dictionary rv = ARRAY_DICT_INIT;
|
Dictionary rv = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
win_T *wp = find_window_by_handle(window, err);
|
win_T *wp = find_window_by_handle(window, err);
|
||||||
@ -373,11 +654,18 @@ Dictionary nvim_win_get_config(Window window, Error *err)
|
|||||||
rv = config_put_bordertext(rv, config, kBorderTextFooter);
|
rv = config_put_bordertext(rv, config, kBorderTextFooter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (!config->external) {
|
||||||
|
PUT(rv, "width", INTEGER_OBJ(wp->w_width));
|
||||||
|
PUT(rv, "height", INTEGER_OBJ(wp->w_height));
|
||||||
|
WinSplit split = win_split_dir(wp);
|
||||||
|
PUT(rv, "split", CSTR_TO_OBJ(win_split_str[split]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *rel = (wp->w_floating && !config->external
|
if (wp->w_floating && !config->external) {
|
||||||
? float_relative_str[config->relative] : "");
|
PUT(rv, "relative", CSTR_TO_OBJ(float_relative_str[config->relative]));
|
||||||
PUT(rv, "relative", CSTR_TO_OBJ(rel));
|
} else {
|
||||||
|
PUT(rv, "relative", CSTR_TO_OBJ(""));
|
||||||
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -419,10 +707,26 @@ static bool parse_float_relative(String relative, FloatRelative *out)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_config_split(String split, WinSplit *out)
|
||||||
|
{
|
||||||
|
char *str = split.data;
|
||||||
|
if (striequal(str, "left")) {
|
||||||
|
*out = kWinSplitLeft;
|
||||||
|
} else if (striequal(str, "right")) {
|
||||||
|
*out = kWinSplitRight;
|
||||||
|
} else if (striequal(str, "above")) {
|
||||||
|
*out = kWinSplitAbove;
|
||||||
|
} else if (striequal(str, "below")) {
|
||||||
|
*out = kWinSplitBelow;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool parse_float_bufpos(Array bufpos, lpos_T *out)
|
static bool parse_float_bufpos(Array bufpos, lpos_T *out)
|
||||||
{
|
{
|
||||||
if (bufpos.size != 2
|
if (bufpos.size != 2 || bufpos.items[0].type != kObjectTypeInteger
|
||||||
|| bufpos.items[0].type != kObjectTypeInteger
|
|
||||||
|| bufpos.items[1].type != kObjectTypeInteger) {
|
|| bufpos.items[1].type != kObjectTypeInteger) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -529,7 +833,7 @@ static bool parse_bordertext_pos(String bordertext_pos, BorderTextType bordertex
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -544,7 +848,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
|||||||
{ NULL, { { NUL } }, false },
|
{ NULL, { { NUL } }, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
char (*chars)[MAX_SCHAR_SIZE] = fconfig->border_chars;
|
char(*chars)[MAX_SCHAR_SIZE] = fconfig->border_chars;
|
||||||
int *hl_ids = fconfig->border_hl_ids;
|
int *hl_ids = fconfig->border_hl_ids;
|
||||||
|
|
||||||
fconfig->border = true;
|
fconfig->border = true;
|
||||||
@ -553,8 +857,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
|||||||
Array arr = style.data.array;
|
Array arr = style.data.array;
|
||||||
size_t size = arr.size;
|
size_t size = arr.size;
|
||||||
if (!size || size > 8 || (size & (size - 1))) {
|
if (!size || size > 8 || (size & (size - 1))) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation, "invalid number of border chars");
|
||||||
"invalid number of border chars");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
@ -584,10 +887,8 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
|||||||
api_set_error(err, kErrorTypeValidation, "invalid border char");
|
api_set_error(err, kErrorTypeValidation, "invalid border char");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (string.size
|
if (string.size && mb_string2cells_len(string.data, string.size) > 1) {
|
||||||
&& mb_string2cells_len(string.data, string.size) > 1) {
|
api_set_error(err, kErrorTypeValidation, "border chars must be one cell");
|
||||||
api_set_error(err, kErrorTypeValidation,
|
|
||||||
"border chars must be one cell");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size_t len = MIN(string.size, sizeof(*chars) - 1);
|
size_t len = MIN(string.size, sizeof(*chars) - 1);
|
||||||
@ -606,8 +907,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
|||||||
|| (chars[1][0] && chars[3][0] && !chars[2][0])
|
|| (chars[1][0] && chars[3][0] && !chars[2][0])
|
||||||
|| (chars[3][0] && chars[5][0] && !chars[4][0])
|
|| (chars[3][0] && chars[5][0] && !chars[4][0])
|
||||||
|| (chars[5][0] && chars[7][0] && !chars[6][0])) {
|
|| (chars[5][0] && chars[7][0] && !chars[6][0])) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation, "corner between used edges must be specified");
|
||||||
"corner between used edges must be specified");
|
|
||||||
}
|
}
|
||||||
} else if (style.type == kObjectTypeString) {
|
} else if (style.type == kObjectTypeString) {
|
||||||
String str = style.data.string;
|
String str = style.data.string;
|
||||||
@ -634,8 +934,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation, "invalid border style \"%s\"", str.data);
|
||||||
"invalid border style \"%s\"", str.data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,17 +942,16 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
bool new_win, Error *err)
|
bool new_win, Error *err)
|
||||||
{
|
{
|
||||||
#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key)
|
#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key)
|
||||||
bool has_relative = false, relative_is_win = false;
|
bool has_relative = false, relative_is_win = false, is_split = false;
|
||||||
// ignore empty string, to match nvim_win_get_config
|
if (HAS_KEY_X(config, relative) && !striequal(config->relative.data, "")) {
|
||||||
if (HAS_KEY_X(config, relative) && config->relative.size > 0) {
|
|
||||||
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(HAS_KEY_X(config, row) && HAS_KEY_X(config, col)) && !HAS_KEY_X(config, bufpos)) {
|
if (config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col))
|
||||||
api_set_error(err, kErrorTypeValidation,
|
&& !HAS_KEY_X(config, bufpos)) {
|
||||||
"'relative' requires 'row'/'col' or 'bufpos'");
|
api_set_error(err, kErrorTypeValidation, "'relative' requires 'row'/'col' or 'bufpos'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,6 +961,32 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
relative_is_win = true;
|
relative_is_win = true;
|
||||||
fconfig->bufpos.lnum = -1;
|
fconfig->bufpos.lnum = -1;
|
||||||
}
|
}
|
||||||
|
} else if (!HAS_KEY_X(config, external) || !config->external) {
|
||||||
|
if (HAS_KEY_X(config, vertical) || HAS_KEY_X(config, split)) {
|
||||||
|
is_split = true;
|
||||||
|
} else if (new_win) {
|
||||||
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
"Must specify 'relative' or 'external' when creating a float");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY_X(config, vertical)) {
|
||||||
|
if (!is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAS_KEY_X(config, split)) {
|
||||||
|
if (!is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!parse_config_split(config->split, &fconfig->split)) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, anchor)) {
|
if (HAS_KEY_X(config, anchor)) {
|
||||||
@ -673,7 +997,7 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, row)) {
|
if (HAS_KEY_X(config, row)) {
|
||||||
if (!has_relative) {
|
if (!has_relative || is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -681,7 +1005,7 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, col)) {
|
if (HAS_KEY_X(config, col)) {
|
||||||
if (!has_relative) {
|
if (!has_relative || is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -689,7 +1013,7 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, bufpos)) {
|
if (HAS_KEY_X(config, bufpos)) {
|
||||||
if (!has_relative) {
|
if (!has_relative || is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'");
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@ -714,7 +1038,7 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
|
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!reconf) {
|
} else if (!reconf && !is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
|
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -726,21 +1050,22 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
|
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!reconf) {
|
} else if (!reconf && !is_split) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
|
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relative_is_win) {
|
if (relative_is_win || is_split) {
|
||||||
fconfig->window = curwin->handle;
|
fconfig->window = curwin->handle;
|
||||||
if (HAS_KEY_X(config, win)) {
|
if (HAS_KEY_X(config, win)) {
|
||||||
if (config->win > 0) {
|
if (config->win > 0) {
|
||||||
fconfig->window = config->win;
|
fconfig->window = config->win;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (has_relative) {
|
||||||
if (HAS_KEY_X(config, win)) {
|
if (HAS_KEY_X(config, win)) {
|
||||||
api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win'");
|
api_set_error(err, kErrorTypeValidation,
|
||||||
|
"'win' key is only valid with relative='win' and relative=''");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,23 +1078,20 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (fconfig->external && !ui_has(kUIMultigrid)) {
|
if (fconfig->external && !ui_has(kUIMultigrid)) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows");
|
||||||
"UI doesn't support external windows");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reconf && (!has_relative && !fconfig->external)) {
|
|
||||||
api_set_error(err, kErrorTypeValidation,
|
|
||||||
"One of 'relative' and 'external' must be used");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HAS_KEY_X(config, focusable)) {
|
if (HAS_KEY_X(config, focusable)) {
|
||||||
fconfig->focusable = config->focusable;
|
fconfig->focusable = config->focusable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, zindex)) {
|
if (HAS_KEY_X(config, zindex)) {
|
||||||
|
if (is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'zindex'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (config->zindex > 0) {
|
if (config->zindex > 0) {
|
||||||
fconfig->zindex = (int)config->zindex;
|
fconfig->zindex = (int)config->zindex;
|
||||||
} else {
|
} else {
|
||||||
@ -779,6 +1101,10 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, title)) {
|
if (HAS_KEY_X(config, title)) {
|
||||||
|
if (is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// title only work with border
|
// title only work with border
|
||||||
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
||||||
api_set_error(err, kErrorTypeException, "title requires border to be set");
|
api_set_error(err, kErrorTypeException, "title requires border to be set");
|
||||||
@ -802,6 +1128,10 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, footer)) {
|
if (HAS_KEY_X(config, footer)) {
|
||||||
|
if (is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// footer only work with border
|
// footer only work with border
|
||||||
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
if (!HAS_KEY_X(config, border) && !fconfig->border) {
|
||||||
api_set_error(err, kErrorTypeException, "footer requires border to be set");
|
api_set_error(err, kErrorTypeException, "footer requires border to be set");
|
||||||
@ -825,6 +1155,10 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY_X(config, border)) {
|
if (HAS_KEY_X(config, border)) {
|
||||||
|
if (is_split) {
|
||||||
|
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
parse_border_style(config->border, fconfig, err);
|
parse_border_style(config->border, fconfig, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -889,6 +889,14 @@ typedef enum {
|
|||||||
kFloatRelativeMouse = 3,
|
kFloatRelativeMouse = 3,
|
||||||
} FloatRelative;
|
} FloatRelative;
|
||||||
|
|
||||||
|
/// Keep in sync with win_split_str[] in nvim_win_get_config() (api/win_config.c)
|
||||||
|
typedef enum {
|
||||||
|
kWinSplitLeft = 0,
|
||||||
|
kWinSplitRight = 1,
|
||||||
|
kWinSplitAbove = 2,
|
||||||
|
kWinSplitBelow = 3,
|
||||||
|
} WinSplit;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kWinStyleUnused = 0,
|
kWinStyleUnused = 0,
|
||||||
kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
|
kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
|
||||||
@ -914,6 +922,7 @@ typedef struct {
|
|||||||
FloatRelative relative;
|
FloatRelative relative;
|
||||||
bool external;
|
bool external;
|
||||||
bool focusable;
|
bool focusable;
|
||||||
|
WinSplit split;
|
||||||
int zindex;
|
int zindex;
|
||||||
WinStyle style;
|
WinStyle style;
|
||||||
bool border;
|
bool border;
|
||||||
@ -939,6 +948,7 @@ typedef struct {
|
|||||||
.row = 0, .col = 0, .anchor = 0, \
|
.row = 0, .col = 0, .anchor = 0, \
|
||||||
.relative = 0, .external = false, \
|
.relative = 0, .external = false, \
|
||||||
.focusable = true, \
|
.focusable = true, \
|
||||||
|
.split = 0, \
|
||||||
.zindex = kZIndexFloatDefault, \
|
.zindex = kZIndexFloatDefault, \
|
||||||
.style = kWinStyleUnused, \
|
.style = kWinStyleUnused, \
|
||||||
.noautocmd = false, \
|
.noautocmd = false, \
|
||||||
|
@ -713,7 +713,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switchwin_T switchwin;
|
switchwin_T switchwin;
|
||||||
if (switch_win_noblock(&switchwin, win, tab, false) == FAIL) {
|
if (switch_win_noblock(&switchwin, win, tab, true) == FAIL) {
|
||||||
api_set_error(err,
|
api_set_error(err,
|
||||||
kErrorTypeException,
|
kErrorTypeException,
|
||||||
"Failed to switch to window %d",
|
"Failed to switch to window %d",
|
||||||
@ -733,7 +733,7 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err)
|
|||||||
// So do it now.
|
// So do it now.
|
||||||
validate_cursor();
|
validate_cursor();
|
||||||
|
|
||||||
restore_win_noblock(&switchwin, false);
|
restore_win_noblock(&switchwin, true);
|
||||||
if (noautocmd) {
|
if (noautocmd) {
|
||||||
unblock_autocmds();
|
unblock_autocmds();
|
||||||
}
|
}
|
||||||
@ -928,6 +928,7 @@ static int check_split_disallowed(void)
|
|||||||
// WSP_TOP: open window at the top-left of the screen (help window).
|
// WSP_TOP: open window at the top-left of the screen (help window).
|
||||||
// WSP_BOT: open window at the bottom-right of the screen (quickfix window).
|
// WSP_BOT: open window at the bottom-right of the screen (quickfix window).
|
||||||
// WSP_HELP: creating the help window, keep layout snapshot
|
// WSP_HELP: creating the help window, keep layout snapshot
|
||||||
|
// WSP_NOENTER: do not enter the new window or trigger WinNew autocommands
|
||||||
//
|
//
|
||||||
// return FAIL for failure, OK otherwise
|
// return FAIL for failure, OK otherwise
|
||||||
int win_split(int size, int flags)
|
int win_split(int size, int flags)
|
||||||
@ -956,20 +957,20 @@ int win_split(int size, int flags)
|
|||||||
clear_snapshot(curtab, SNAP_HELP_IDX);
|
clear_snapshot(curtab, SNAP_HELP_IDX);
|
||||||
}
|
}
|
||||||
|
|
||||||
return win_split_ins(size, flags, NULL, 0);
|
return win_split_ins(size, flags, NULL, 0) == NULL ? FAIL : OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When "new_wp" is NULL: split the current window in two.
|
/// When "new_wp" is NULL: split the current window in two.
|
||||||
/// When "new_wp" is not NULL: insert this window at the far
|
/// When "new_wp" is not NULL: insert this window at the far
|
||||||
/// top/left/right/bottom.
|
/// top/left/right/bottom.
|
||||||
/// @return FAIL for failure, OK otherwise
|
/// @return NULL for failure, or pointer to new window
|
||||||
int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||||
{
|
{
|
||||||
win_T *wp = new_wp;
|
win_T *wp = new_wp;
|
||||||
|
|
||||||
// aucmd_win[] should always remain floating
|
// aucmd_win[] should always remain floating
|
||||||
if (new_wp != NULL && is_aucmd_win(new_wp)) {
|
if (new_wp != NULL && is_aucmd_win(new_wp)) {
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
win_T *oldwin;
|
win_T *oldwin;
|
||||||
@ -985,22 +986,24 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
int need_status = 0;
|
int need_status = 0;
|
||||||
int new_size = size;
|
int new_size = size;
|
||||||
bool new_in_layout = (new_wp == NULL || new_wp->w_floating);
|
bool new_in_layout = (new_wp == NULL || new_wp->w_floating);
|
||||||
|
bool vertical = flags & WSP_VERT;
|
||||||
|
bool toplevel = flags & (WSP_TOP | WSP_BOT);
|
||||||
|
|
||||||
// add a status line when p_ls == 1 and splitting the first window
|
// add a status line when p_ls == 1 and splitting the first window
|
||||||
if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) {
|
if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) {
|
||||||
if (oldwin->w_height <= p_wmh && new_in_layout) {
|
if (oldwin->w_height <= p_wmh && new_in_layout) {
|
||||||
emsg(_(e_noroom));
|
emsg(_(e_noroom));
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
need_status = STATUS_HEIGHT;
|
need_status = STATUS_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool do_equal = false;
|
bool do_equal = false;
|
||||||
int oldwin_height = 0;
|
int oldwin_height = 0;
|
||||||
const int layout = flags & WSP_VERT ? FR_ROW : FR_COL;
|
const int layout = vertical ? FR_ROW : FR_COL;
|
||||||
bool did_set_fraction = false;
|
bool did_set_fraction = false;
|
||||||
|
|
||||||
if (flags & WSP_VERT) {
|
if (vertical) {
|
||||||
// Check if we are able to split the current window and compute its
|
// Check if we are able to split the current window and compute its
|
||||||
// width.
|
// width.
|
||||||
// Current window requires at least 1 space.
|
// Current window requires at least 1 space.
|
||||||
@ -1011,7 +1014,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
int minwidth;
|
int minwidth;
|
||||||
int available;
|
int available;
|
||||||
if (flags & (WSP_BOT | WSP_TOP)) {
|
if (toplevel) {
|
||||||
minwidth = frame_minwidth(topframe, NOWIN);
|
minwidth = frame_minwidth(topframe, NOWIN);
|
||||||
available = topframe->fr_width;
|
available = topframe->fr_width;
|
||||||
needed += minwidth;
|
needed += minwidth;
|
||||||
@ -1039,7 +1042,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
if (available < needed && new_in_layout) {
|
if (available < needed && new_in_layout) {
|
||||||
emsg(_(e_noroom));
|
emsg(_(e_noroom));
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
new_size = oldwin->w_width / 2;
|
new_size = oldwin->w_width / 2;
|
||||||
@ -1092,7 +1095,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
int minheight;
|
int minheight;
|
||||||
int available;
|
int available;
|
||||||
if (flags & (WSP_BOT | WSP_TOP)) {
|
if (toplevel) {
|
||||||
minheight = frame_minheight(topframe, NOWIN) + need_status;
|
minheight = frame_minheight(topframe, NOWIN) + need_status;
|
||||||
available = topframe->fr_height;
|
available = topframe->fr_height;
|
||||||
needed += minheight;
|
needed += minheight;
|
||||||
@ -1119,7 +1122,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
if (available < needed && new_in_layout) {
|
if (available < needed && new_in_layout) {
|
||||||
emsg(_(e_noroom));
|
emsg(_(e_noroom));
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
oldwin_height = oldwin->w_height;
|
oldwin_height = oldwin->w_height;
|
||||||
if (need_status) {
|
if (need_status) {
|
||||||
@ -1182,7 +1185,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
&& ((flags & WSP_BOT)
|
&& ((flags & WSP_BOT)
|
||||||
|| (flags & WSP_BELOW)
|
|| (flags & WSP_BELOW)
|
||||||
|| (!(flags & WSP_ABOVE)
|
|| (!(flags & WSP_ABOVE)
|
||||||
&& ((flags & WSP_VERT) ? p_spr : p_sb)))) {
|
&& (vertical ? p_spr : p_sb)))) {
|
||||||
// new window below/right of current one
|
// new window below/right of current one
|
||||||
if (new_wp == NULL) {
|
if (new_wp == NULL) {
|
||||||
wp = win_alloc(oldwin, false);
|
wp = win_alloc(oldwin, false);
|
||||||
@ -1199,7 +1202,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
|
|
||||||
if (new_wp == NULL) {
|
if (new_wp == NULL) {
|
||||||
if (wp == NULL) {
|
if (wp == NULL) {
|
||||||
return FAIL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_frame(wp);
|
new_frame(wp);
|
||||||
@ -1218,9 +1221,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
frame_T *curfrp;
|
frame_T *curfrp;
|
||||||
|
|
||||||
// Reorganise the tree of frames to insert the new window.
|
// Reorganise the tree of frames to insert the new window.
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
|
if ((topframe->fr_layout == FR_COL && !vertical)
|
||||||
|| (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0)) {
|
|| (topframe->fr_layout == FR_ROW && vertical)) {
|
||||||
curfrp = topframe->fr_child;
|
curfrp = topframe->fr_child;
|
||||||
if (flags & WSP_BOT) {
|
if (flags & WSP_BOT) {
|
||||||
while (curfrp->fr_next != NULL) {
|
while (curfrp->fr_next != NULL) {
|
||||||
@ -1237,7 +1240,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
before = false;
|
before = false;
|
||||||
} else if (flags & WSP_ABOVE) {
|
} else if (flags & WSP_ABOVE) {
|
||||||
before = true;
|
before = true;
|
||||||
} else if (flags & WSP_VERT) {
|
} else if (vertical) {
|
||||||
before = !p_spr;
|
before = !p_spr;
|
||||||
} else {
|
} else {
|
||||||
before = !p_sb;
|
before = !p_sb;
|
||||||
@ -1285,14 +1288,14 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
wp->w_fraction = oldwin->w_fraction;
|
wp->w_fraction = oldwin->w_fraction;
|
||||||
|
|
||||||
if (flags & WSP_VERT) {
|
if (vertical) {
|
||||||
wp->w_p_scr = curwin->w_p_scr;
|
wp->w_p_scr = curwin->w_p_scr;
|
||||||
|
|
||||||
if (need_status) {
|
if (need_status) {
|
||||||
win_new_height(oldwin, oldwin->w_height - 1);
|
win_new_height(oldwin, oldwin->w_height - 1);
|
||||||
oldwin->w_status_height = need_status;
|
oldwin->w_status_height = need_status;
|
||||||
}
|
}
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
// set height and row of new window to full height
|
// set height and row of new window to full height
|
||||||
wp->w_winrow = tabline_height();
|
wp->w_winrow = tabline_height();
|
||||||
win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2));
|
win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2));
|
||||||
@ -1316,7 +1319,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
wp->w_vsep_width = oldwin->w_vsep_width;
|
wp->w_vsep_width = oldwin->w_vsep_width;
|
||||||
oldwin->w_vsep_width = 1;
|
oldwin->w_vsep_width = 1;
|
||||||
}
|
}
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
if (flags & WSP_BOT) {
|
if (flags & WSP_BOT) {
|
||||||
frame_add_vsep(curfrp);
|
frame_add_vsep(curfrp);
|
||||||
}
|
}
|
||||||
@ -1338,7 +1341,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
} else {
|
} else {
|
||||||
const bool is_stl_global = global_stl_height() > 0;
|
const bool is_stl_global = global_stl_height() > 0;
|
||||||
// width and column of new window is same as current window
|
// width and column of new window is same as current window
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
wp->w_wincol = 0;
|
wp->w_wincol = 0;
|
||||||
win_new_width(wp, Columns);
|
win_new_width(wp, Columns);
|
||||||
wp->w_vsep_width = 0;
|
wp->w_vsep_width = 0;
|
||||||
@ -1359,7 +1362,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
wp->w_hsep_height = oldwin->w_hsep_height;
|
wp->w_hsep_height = oldwin->w_hsep_height;
|
||||||
oldwin->w_hsep_height = is_stl_global ? 1 : 0;
|
oldwin->w_hsep_height = is_stl_global ? 1 : 0;
|
||||||
}
|
}
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
int new_fr_height = curfrp->fr_height - new_size;
|
int new_fr_height = curfrp->fr_height - new_size;
|
||||||
if (is_stl_global) {
|
if (is_stl_global) {
|
||||||
if (flags & WSP_BOT) {
|
if (flags & WSP_BOT) {
|
||||||
@ -1405,7 +1408,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
frame_fix_height(oldwin);
|
frame_fix_height(oldwin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & (WSP_TOP | WSP_BOT)) {
|
if (toplevel) {
|
||||||
win_comp_pos();
|
win_comp_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1426,7 +1429,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
|
|
||||||
// equalize the window sizes.
|
// equalize the window sizes.
|
||||||
if (do_equal || dir != 0) {
|
if (do_equal || dir != 0) {
|
||||||
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
|
win_equal(wp, true, vertical ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
|
||||||
} else if (!is_aucmd_win(wp)) {
|
} else if (!is_aucmd_win(wp)) {
|
||||||
win_fix_scroll(false);
|
win_fix_scroll(false);
|
||||||
}
|
}
|
||||||
@ -1447,10 +1450,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the new window the current window
|
if (!(flags & WSP_NOENTER)) {
|
||||||
win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS
|
// make the new window the current window
|
||||||
| WEE_TRIGGER_LEAVE_AUTOCMDS);
|
win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS
|
||||||
if (flags & WSP_VERT) {
|
| WEE_TRIGGER_LEAVE_AUTOCMDS);
|
||||||
|
}
|
||||||
|
if (vertical) {
|
||||||
p_wiw = i;
|
p_wiw = i;
|
||||||
} else {
|
} else {
|
||||||
p_wh = i;
|
p_wh = i;
|
||||||
@ -1461,7 +1466,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
oldwin->w_pos_changed = true;
|
oldwin->w_pos_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return wp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize window "newp" from window "oldp".
|
// Initialize window "newp" from window "oldp".
|
||||||
|
@ -21,15 +21,16 @@ enum {
|
|||||||
|
|
||||||
/// arguments for win_split()
|
/// arguments for win_split()
|
||||||
enum {
|
enum {
|
||||||
WSP_ROOM = 0x01, ///< require enough room
|
WSP_ROOM = 0x01, ///< require enough room
|
||||||
WSP_VERT = 0x02, ///< split/equalize vertically
|
WSP_VERT = 0x02, ///< split/equalize vertically
|
||||||
WSP_HOR = 0x04, ///< equalize horizontally
|
WSP_HOR = 0x04, ///< equalize horizontally
|
||||||
WSP_TOP = 0x08, ///< window at top-left of shell
|
WSP_TOP = 0x08, ///< window at top-left of shell
|
||||||
WSP_BOT = 0x10, ///< window at bottom-right of shell
|
WSP_BOT = 0x10, ///< window at bottom-right of shell
|
||||||
WSP_HELP = 0x20, ///< creating the help window
|
WSP_HELP = 0x20, ///< creating the help window
|
||||||
WSP_BELOW = 0x40, ///< put new window below/right
|
WSP_BELOW = 0x40, ///< put new window below/right
|
||||||
WSP_ABOVE = 0x80, ///< put new window above/left
|
WSP_ABOVE = 0x80, ///< put new window above/left
|
||||||
WSP_NEWLOC = 0x100, ///< don't copy location list
|
WSP_NEWLOC = 0x100, ///< don't copy location list
|
||||||
|
WSP_NOENTER = 0x200, ///< don't enter the new window
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -1232,6 +1232,437 @@ describe('API/win', function()
|
|||||||
)
|
)
|
||||||
eq(wins_before, api.nvim_list_wins())
|
eq(wins_before, api.nvim_list_wins())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('creates a split window', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
eq('', api.nvim_win_get_config(win).relative)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('creates split windows in the correct direction', function()
|
||||||
|
local initial_win = api.nvim_get_current_win()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
})
|
||||||
|
eq('', api.nvim_win_get_config(win).relative)
|
||||||
|
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("respects the 'split' option", function()
|
||||||
|
local initial_win = api.nvim_get_current_win()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
split = 'below',
|
||||||
|
})
|
||||||
|
eq('', api.nvim_win_get_config(win).relative)
|
||||||
|
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
{ 'leaf', win },
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it(
|
||||||
|
"doesn't change tp_curwin when splitting window in non-current tab with enter=false",
|
||||||
|
function()
|
||||||
|
local tab1 = api.nvim_get_current_tabpage()
|
||||||
|
local tab1_win = api.nvim_get_current_win()
|
||||||
|
|
||||||
|
helpers.command('tabnew')
|
||||||
|
local tab2 = api.nvim_get_current_tabpage()
|
||||||
|
local tab2_win = api.nvim_get_current_win()
|
||||||
|
|
||||||
|
eq({ tab1_win, tab2_win }, api.nvim_list_wins())
|
||||||
|
eq({ tab1, tab2 }, api.nvim_list_tabpages())
|
||||||
|
|
||||||
|
api.nvim_set_current_tabpage(tab1)
|
||||||
|
eq(tab1_win, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
local tab2_prevwin = fn.tabpagewinnr(tab2, '#')
|
||||||
|
|
||||||
|
-- split in tab2 whine in tab2, with enter = false
|
||||||
|
local tab2_win2 = api.nvim_open_win(api.nvim_create_buf(false, true), false, {
|
||||||
|
win = tab2_win,
|
||||||
|
split = 'right',
|
||||||
|
})
|
||||||
|
eq(tab1_win, api.nvim_get_current_win()) -- we should still be in the first tp
|
||||||
|
eq(tab1_win, api.nvim_tabpage_get_win(tab1))
|
||||||
|
|
||||||
|
eq(tab2_win, api.nvim_tabpage_get_win(tab2)) -- tab2's tp_curwin should not have changed
|
||||||
|
eq(tab2_prevwin, fn.tabpagewinnr(tab2, '#')) -- tab2's tp_prevwin should not have changed
|
||||||
|
eq({ tab1_win, tab2_win, tab2_win2 }, api.nvim_list_wins())
|
||||||
|
eq({ tab2_win, tab2_win2 }, api.nvim_tabpage_list_wins(tab2))
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
it('creates splits in the correct location', function()
|
||||||
|
local first_win = api.nvim_get_current_win()
|
||||||
|
-- specifying window 0 should create a split next to the current window
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', first_win },
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
-- not specifying a window should create a top-level split
|
||||||
|
local win2 = api.nvim_open_win(0, true, {
|
||||||
|
split = 'left',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
{
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', first_win },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
|
||||||
|
-- specifying a window should create a split next to that window
|
||||||
|
local win3 = api.nvim_open_win(0, true, {
|
||||||
|
win = win,
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
{
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win3 },
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', first_win },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('set_config', function()
|
||||||
|
it('moves a split into a float', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
eq('', api.nvim_win_get_config(win).relative)
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
width = 5,
|
||||||
|
height = 5,
|
||||||
|
})
|
||||||
|
eq('editor', api.nvim_win_get_config(win).relative)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('throws error when attempting to move the last window', function()
|
||||||
|
local err = pcall_err(api.nvim_win_set_config, 0, {
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
eq('Cannot move last window', err)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('passing retval of get_config results in no-op', function()
|
||||||
|
-- simple split layout
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
split = 'left',
|
||||||
|
})
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
local config = api.nvim_win_get_config(win)
|
||||||
|
api.nvim_win_set_config(win, config)
|
||||||
|
eq(layout, fn.winlayout())
|
||||||
|
|
||||||
|
-- nested split layout
|
||||||
|
local win2 = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
})
|
||||||
|
local win3 = api.nvim_open_win(0, true, {
|
||||||
|
win = win2,
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
config = api.nvim_win_get_config(win2)
|
||||||
|
api.nvim_win_set_config(win2, config)
|
||||||
|
eq(layout, fn.winlayout())
|
||||||
|
|
||||||
|
config = api.nvim_win_get_config(win3)
|
||||||
|
api.nvim_win_set_config(win3, config)
|
||||||
|
eq(layout, fn.winlayout())
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('moves a float into a split', function()
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
eq('leaf', layout[1])
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
width = 5,
|
||||||
|
height = 5,
|
||||||
|
})
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'below',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
eq('', api.nvim_win_get_config(win).relative)
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq('col', layout[1])
|
||||||
|
eq(2, #layout[2])
|
||||||
|
eq(win, layout[2][2][2])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('respects the "split" option', function()
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
eq('leaf', layout[1])
|
||||||
|
local first_win = layout[2]
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
relative = 'editor',
|
||||||
|
row = 5,
|
||||||
|
col = 5,
|
||||||
|
width = 5,
|
||||||
|
height = 5,
|
||||||
|
})
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'right',
|
||||||
|
win = first_win,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq('row', layout[1])
|
||||||
|
eq(2, #layout[2])
|
||||||
|
eq(win, layout[2][2][2])
|
||||||
|
local config = api.nvim_win_get_config(win)
|
||||||
|
eq('', config.relative)
|
||||||
|
eq('right', config.split)
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'below',
|
||||||
|
win = first_win,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq('col', layout[1])
|
||||||
|
eq(2, #layout[2])
|
||||||
|
eq(win, layout[2][2][2])
|
||||||
|
config = api.nvim_win_get_config(win)
|
||||||
|
eq('', config.relative)
|
||||||
|
eq('below', config.split)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('creates top-level splits', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = false,
|
||||||
|
})
|
||||||
|
local win2 = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
eq('row', layout[1])
|
||||||
|
eq(2, #layout[2])
|
||||||
|
eq(win2, layout[2][1][2])
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'below',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
layout = fn.winlayout()
|
||||||
|
eq('col', layout[1])
|
||||||
|
eq(2, #layout[2])
|
||||||
|
eq('row', layout[2][1][1])
|
||||||
|
eq(win, layout[2][2][2])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('moves splits to other tabpages', function()
|
||||||
|
local curtab = api.nvim_get_current_tabpage()
|
||||||
|
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))
|
||||||
|
-- we are changing the config, the current tabpage should not change
|
||||||
|
eq(curtab, api.nvim_get_current_tabpage())
|
||||||
|
|
||||||
|
command('tabnext') -- switch to the new tabpage so we can get the layout
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', api.nvim_tabpage_get_win(tabnr) },
|
||||||
|
{ 'leaf', win },
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('correctly moves curwin when moving curwin to a different tabpage', function()
|
||||||
|
local curtab = api.nvim_get_current_tabpage()
|
||||||
|
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()
|
||||||
|
|
||||||
|
-- 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))
|
||||||
|
|
||||||
|
-- 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())
|
||||||
|
|
||||||
|
-- win should have moved to tab2
|
||||||
|
eq(tab2, api.nvim_win_get_tabpage(win))
|
||||||
|
-- tp_curwin of tab2 should not have changed
|
||||||
|
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))
|
||||||
|
|
||||||
|
-- current win should have moved to neighboring win
|
||||||
|
eq(neighbor, api.nvim_tabpage_get_win(curtab))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('splits windows in non-current tabpage', function()
|
||||||
|
local curtab = api.nvim_get_current_tabpage()
|
||||||
|
command('tabnew')
|
||||||
|
local tabnr = api.nvim_get_current_tabpage()
|
||||||
|
command('tabprev') -- return to the initial tab
|
||||||
|
|
||||||
|
local win = api.nvim_open_win(0, false, {
|
||||||
|
vertical = false,
|
||||||
|
win = api.nvim_tabpage_get_win(tabnr),
|
||||||
|
})
|
||||||
|
|
||||||
|
eq(tabnr, api.nvim_win_get_tabpage(win))
|
||||||
|
-- since enter = false, the current tabpage should not change
|
||||||
|
eq(curtab, api.nvim_get_current_tabpage())
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('moves the current split window', function()
|
||||||
|
local initial_win = api.nvim_get_current_win()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
})
|
||||||
|
local win2 = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
})
|
||||||
|
api.nvim_set_current_win(win)
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
},
|
||||||
|
}, fn.winlayout())
|
||||||
|
|
||||||
|
api.nvim_win_set_config(0, {
|
||||||
|
vertical = false,
|
||||||
|
win = 0,
|
||||||
|
})
|
||||||
|
eq(win, api.nvim_get_current_win())
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, fn.winlayout())
|
||||||
|
|
||||||
|
api.nvim_set_current_win(win2)
|
||||||
|
local win3 = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
})
|
||||||
|
eq(win3, api.nvim_get_current_win())
|
||||||
|
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win3 },
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, fn.winlayout())
|
||||||
|
|
||||||
|
api.nvim_win_set_config(0, {
|
||||||
|
vertical = false,
|
||||||
|
win = 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
eq(win3, api.nvim_get_current_win())
|
||||||
|
eq({
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win3 },
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, fn.winlayout())
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('get_config', function()
|
describe('get_config', function()
|
||||||
@ -1292,6 +1723,154 @@ describe('API/win', function()
|
|||||||
eq(title, cfg.title)
|
eq(title, cfg.title)
|
||||||
eq(footer, cfg.footer)
|
eq(footer, cfg.footer)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('includes split for normal windows', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
vertical = true,
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
eq('left', api.nvim_win_get_config(win).split)
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
vertical = false,
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
eq('above', api.nvim_win_get_config(win).split)
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'below',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
eq('below', api.nvim_win_get_config(win).split)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('includes split when splitting with ex commands', function()
|
||||||
|
local win = api.nvim_get_current_win()
|
||||||
|
eq('left', api.nvim_win_get_config(win).split)
|
||||||
|
|
||||||
|
command('vsplit')
|
||||||
|
local win2 = api.nvim_get_current_win()
|
||||||
|
|
||||||
|
-- initial window now be marked as right split
|
||||||
|
-- since it was split with a vertical split
|
||||||
|
-- and 'splitright' is false by default
|
||||||
|
eq('right', api.nvim_win_get_config(win).split)
|
||||||
|
eq('left', api.nvim_win_get_config(win2).split)
|
||||||
|
|
||||||
|
api.nvim_set_option_value('splitbelow', true, {
|
||||||
|
scope = 'global',
|
||||||
|
})
|
||||||
|
api.nvim_win_close(win, true)
|
||||||
|
command('split')
|
||||||
|
local win3 = api.nvim_get_current_win()
|
||||||
|
eq('below', api.nvim_win_get_config(win3).split)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("includes the correct 'split' option in complex layouts", function()
|
||||||
|
local initial_win = api.nvim_get_current_win()
|
||||||
|
local win = api.nvim_open_win(0, false, {
|
||||||
|
split = 'right',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
|
||||||
|
local win2 = api.nvim_open_win(0, false, {
|
||||||
|
split = 'below',
|
||||||
|
win = win,
|
||||||
|
})
|
||||||
|
|
||||||
|
api.nvim_win_set_config(win2, {
|
||||||
|
width = 50,
|
||||||
|
})
|
||||||
|
|
||||||
|
api.nvim_win_set_config(win, {
|
||||||
|
split = 'left',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
|
||||||
|
local win3 = api.nvim_open_win(0, false, {
|
||||||
|
split = 'above',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
local float = api.nvim_open_win(0, false, {
|
||||||
|
relative = 'editor',
|
||||||
|
width = 40,
|
||||||
|
height = 20,
|
||||||
|
col = 20,
|
||||||
|
row = 10,
|
||||||
|
})
|
||||||
|
api.nvim_win_set_config(float, {
|
||||||
|
split = 'right',
|
||||||
|
win = -1,
|
||||||
|
})
|
||||||
|
|
||||||
|
local layout = fn.winlayout()
|
||||||
|
|
||||||
|
eq({
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{
|
||||||
|
'col',
|
||||||
|
{
|
||||||
|
{ 'leaf', win3 },
|
||||||
|
{
|
||||||
|
'row',
|
||||||
|
{
|
||||||
|
{ 'leaf', win },
|
||||||
|
{ 'leaf', initial_win },
|
||||||
|
{ 'leaf', win2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'leaf',
|
||||||
|
float,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, layout)
|
||||||
|
|
||||||
|
eq('above', api.nvim_win_get_config(win3).split)
|
||||||
|
eq('left', api.nvim_win_get_config(win).split)
|
||||||
|
eq('left', api.nvim_win_get_config(initial_win).split)
|
||||||
|
eq('right', api.nvim_win_get_config(win2).split)
|
||||||
|
eq('right', api.nvim_win_get_config(float).split)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('set_config', function()
|
||||||
|
it('no crash with invalid title', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
width = 10,
|
||||||
|
height = 10,
|
||||||
|
relative = 'editor',
|
||||||
|
row = 10,
|
||||||
|
col = 10,
|
||||||
|
title = { { 'test' } },
|
||||||
|
border = 'single',
|
||||||
|
})
|
||||||
|
eq(
|
||||||
|
'title/footer cannot be an empty array',
|
||||||
|
pcall_err(api.nvim_win_set_config, win, { title = {} })
|
||||||
|
)
|
||||||
|
command('redraw!')
|
||||||
|
assert_alive()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('no crash with invalid footer', function()
|
||||||
|
local win = api.nvim_open_win(0, true, {
|
||||||
|
width = 10,
|
||||||
|
height = 10,
|
||||||
|
relative = 'editor',
|
||||||
|
row = 10,
|
||||||
|
col = 10,
|
||||||
|
footer = { { 'test' } },
|
||||||
|
border = 'single',
|
||||||
|
})
|
||||||
|
eq(
|
||||||
|
'title/footer cannot be an empty array',
|
||||||
|
pcall_err(api.nvim_win_set_config, win, { footer = {} })
|
||||||
|
)
|
||||||
|
command('redraw!')
|
||||||
|
assert_alive()
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('set_config', function()
|
describe('set_config', function()
|
||||||
|
@ -104,14 +104,20 @@ describe('float window', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('open with WinNew autocmd', function()
|
it('open with WinNew autocmd', function()
|
||||||
local res = exec_lua([[
|
local new_triggered_before_enter, new_curwin, win = unpack(exec_lua([[
|
||||||
local triggerd = false
|
local enter_triggered = false
|
||||||
|
local new_triggered_before_enter = false
|
||||||
|
local new_curwin
|
||||||
local buf = vim.api.nvim_create_buf(true, true)
|
local buf = vim.api.nvim_create_buf(true, true)
|
||||||
|
vim.api.nvim_create_autocmd('WinEnter', {
|
||||||
|
callback = function()
|
||||||
|
enter_triggered = true
|
||||||
|
end
|
||||||
|
})
|
||||||
vim.api.nvim_create_autocmd('WinNew', {
|
vim.api.nvim_create_autocmd('WinNew', {
|
||||||
callback = function(opt)
|
callback = function()
|
||||||
if opt.buf == buf then
|
new_triggered_before_enter = not enter_triggered
|
||||||
triggerd = true
|
new_curwin = vim.api.nvim_get_current_win()
|
||||||
end
|
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
local opts = {
|
local opts = {
|
||||||
@ -120,10 +126,11 @@ describe('float window', function()
|
|||||||
width = 1, height = 1,
|
width = 1, height = 1,
|
||||||
noautocmd = false,
|
noautocmd = false,
|
||||||
}
|
}
|
||||||
vim.api.nvim_open_win(buf, true, opts)
|
local win = vim.api.nvim_open_win(buf, true, opts)
|
||||||
return triggerd
|
return {new_triggered_before_enter, new_curwin, win}
|
||||||
]])
|
]]))
|
||||||
eq(true, res)
|
eq(true, new_triggered_before_enter)
|
||||||
|
eq(win, new_curwin)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('opened with correct height', function()
|
it('opened with correct height', function()
|
||||||
@ -1095,7 +1102,7 @@ describe('float window', function()
|
|||||||
local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false}
|
local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false}
|
||||||
eq(expected, api.nvim_win_get_config(win))
|
eq(expected, api.nvim_win_get_config(win))
|
||||||
|
|
||||||
eq({relative='', external=false, focusable=true, hide=false}, api.nvim_win_get_config(0))
|
eq({external=false, focusable=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0))
|
||||||
|
|
||||||
if multigrid then
|
if multigrid then
|
||||||
api.nvim_win_set_config(win, {external=true, width=10, height=1})
|
api.nvim_win_set_config(win, {external=true, width=10, height=1})
|
||||||
@ -2878,27 +2885,31 @@ 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'",
|
eq("Invalid key: 'bork'",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=2,bork=true}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,bork=true}))
|
||||||
eq("'win' key is only valid with relative='win'",
|
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}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='editor',row=0,col=0,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}))
|
||||||
|
eq("floating windows cannot have 'split'",
|
||||||
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='editor',row=0,col=0,split="left"}))
|
||||||
eq("Only one of 'relative' and 'external' must be used",
|
eq("Only one of 'relative' and 'external' must be used",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,external=true}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='editor',row=0,col=0,external=true}))
|
||||||
eq("Invalid value of 'relative' key",
|
eq("Invalid value of 'relative' key",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=2,relative='shell',row=0,col=0}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='shell',row=0,col=0}))
|
||||||
eq("Invalid value of 'anchor' key",
|
eq("Invalid value of 'anchor' key",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,anchor='bottom'}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='editor',row=0,col=0,anchor='bottom'}))
|
||||||
eq("'relative' requires 'row'/'col' or 'bufpos'",
|
eq("'relative' requires 'row'/'col' or 'bufpos'",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=2,relative='editor'}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=2,relative='editor'}))
|
||||||
eq("'width' key must be a positive Integer",
|
eq("'width' key must be a positive Integer",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=-1,height=2,relative='editor', row=0, col=0}))
|
pcall_err(api.nvim_open_win, buf, false, {width=-1,height=2,relative='editor', row=0, col=0}))
|
||||||
eq("'height' key must be a positive Integer",
|
eq("'height' key must be a positive Integer",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=-1,relative='editor', row=0, col=0}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=-1,relative='editor', row=0, col=0}))
|
||||||
eq("'height' key must be a positive Integer",
|
eq("'height' key must be a positive Integer",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {width=20,height=0,relative='editor', row=0, col=0}))
|
pcall_err(api.nvim_open_win, buf, false, {width=20,height=0,relative='editor', row=0, col=0}))
|
||||||
eq("Must specify 'width'",
|
eq("Must specify 'width'",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {relative='editor', row=0, col=0}))
|
pcall_err(api.nvim_open_win, buf, false, {relative='editor', row=0, col=0}))
|
||||||
eq("Must specify 'height'",
|
eq("Must specify 'height'",
|
||||||
pcall_err(api.nvim_open_win,buf, false, {relative='editor', row=0, col=0, width=2}))
|
pcall_err(api.nvim_open_win, buf, false, {relative='editor', row=0, col=0, width=2}))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can be placed relative window or cursor', function()
|
it('can be placed relative window or cursor', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user