mirror of
https://github.com/neovim/neovim.git
synced 2026-08-26 09:01:57 +00:00
Merge #38309 from justinmk/doc2
This commit is contained in:
@@ -36,6 +36,8 @@ Reporting problems
|
||||
Developer guidelines
|
||||
--------------------
|
||||
|
||||
- New functionality should generally be implemented in Lua, not C. PRs [#37757](https://github.com/neovim/neovim/pull/37757), [#37831](https://github.com/neovim/neovim/pull/37831)
|
||||
are excellent examples of this.
|
||||
- Read [:help dev-quickstart](https://neovim.io/doc/user/dev_tools.html#dev-quickstart) to see how to run tests and start hacking on the codebase.
|
||||
- Read [:help dev](https://neovim.io/doc/user/dev.html#dev) and [:help dev-doc][dev-doc-guide] if you are working on Nvim core.
|
||||
- Read [:help dev-ui](https://neovim.io/doc/user/dev.html#dev-ui) if you are developing a UI.
|
||||
@@ -195,7 +197,7 @@ Coding
|
||||
You can run the linter locally by:
|
||||
|
||||
```bash
|
||||
make lint
|
||||
make lint # or lintc, lintlua, lintquery, lintdoc
|
||||
```
|
||||
|
||||
### Style
|
||||
@@ -206,7 +208,6 @@ make lint
|
||||
```
|
||||
This will format changed C, Lua, and treesitter query files with all
|
||||
appropriate flags set.
|
||||
|
||||
- Style rules are (mostly) defined by `src/uncrustify.cfg` which tries to match
|
||||
the [style-guide]. To use the Nvim `gq` command with `uncrustify`:
|
||||
```vim
|
||||
@@ -214,8 +215,8 @@ make lint
|
||||
setlocal formatprg=uncrustify\ -q\ -l\ C\ -c\ src/uncrustify.cfg\ --no-backup
|
||||
endif
|
||||
```
|
||||
- There is also `.clang-format` which has drifted from the [style-guide], but
|
||||
is available for reference. To use the Nvim `gq` command with `clang-format`:
|
||||
- There is also `.clang-format` which is "mostly" aligned with uncrustify.
|
||||
To use the Nvim `gq` command with `clang-format`:
|
||||
```vim
|
||||
if !empty(findfile('.clang-format', ';'))
|
||||
setlocal formatprg=clang-format\ -style=file
|
||||
|
||||
@@ -261,7 +261,6 @@ Call |nvim_buf_attach()| to receive these events on the channel:
|
||||
|
||||
*nvim_buf_lines_event*
|
||||
nvim_buf_lines_event[{buf}, {changedtick}, {firstline}, {lastline}, {linedata}, {more}]
|
||||
|
||||
When the buffer text between {firstline} and {lastline} (end-exclusive,
|
||||
zero-indexed) were changed to the new text in the {linedata} list. The
|
||||
granularity is a line, i.e. if a single character is changed in the
|
||||
@@ -271,45 +270,41 @@ nvim_buf_lines_event[{buf}, {changedtick}, {firstline}, {lastline}, {linedata},
|
||||
changed but not the buffer contents. {linedata} contains the changed
|
||||
screen lines. This happens when 'inccommand' shows a buffer preview.
|
||||
|
||||
Properties: ~
|
||||
{buf} API buffer handle (buffer number)
|
||||
|
||||
{changedtick} value of |b:changedtick| for the buffer. If you send an
|
||||
API command back to nvim you can check the value of |b:changedtick| as
|
||||
part of your request to ensure that no other changes have been made.
|
||||
|
||||
{firstline} integer line number of the first line that was replaced.
|
||||
Zero-indexed: if line 1 was replaced then {firstline} will be zero,
|
||||
not one. {firstline} is always less than or equal to the number of
|
||||
lines that were in the buffer before the lines were replaced.
|
||||
|
||||
{lastline} integer line number of the first line that was not replaced
|
||||
(i.e. the range {firstline}, {lastline} is end-exclusive).
|
||||
Zero-indexed: if line numbers 2 to 5 were replaced, this will be 5
|
||||
instead of 6. {lastline} is always be less than or equal to the number
|
||||
of lines that were in the buffer before the lines were replaced.
|
||||
{lastline} will be -1 if the event is part of the initial update after
|
||||
attaching.
|
||||
|
||||
{linedata} list of strings containing the contents of the new buffer
|
||||
lines. Newline characters are omitted; empty lines are sent as empty
|
||||
strings.
|
||||
|
||||
{more} boolean, true for a "multipart" change notification: the
|
||||
current change was chunked into multiple |nvim_buf_lines_event|
|
||||
notifications (e.g. because it was too big).
|
||||
Parameters: ~
|
||||
• {buf} (`integer`) Buffer id
|
||||
• {changedtick} (`integer`) Value of |b:changedtick|. If you send an API
|
||||
command back to Nvim you can check |b:changedtick| as
|
||||
part of your request to ensure that no other changes
|
||||
have been made.
|
||||
• {firstline} (`integer`) The first line that was replaced.
|
||||
Zero-indexed: if line 1 was replaced then {firstline}
|
||||
will be zero, not one. Always less than or equal to
|
||||
the number of lines that were in the buffer before the
|
||||
lines were replaced.
|
||||
• {lastline} (`integer`) The first line that was not replaced (i.e.
|
||||
the range {firstline}, {lastline} is end-exclusive).
|
||||
Zero-indexed: if line numbers 2 to 5 were replaced,
|
||||
this will be 5 instead of 6. Always less than or equal
|
||||
to the number of lines that were in the buffer before
|
||||
the lines were replaced. Will be -1 if the event is
|
||||
part of the initial update after attaching.
|
||||
• {linedata} (`string[]`) Contents of the new buffer lines. Newline
|
||||
characters are omitted; empty lines are sent as empty
|
||||
strings.
|
||||
• {more} (`boolean`) true for a "multipart" change notification:
|
||||
the current change was chunked into multiple
|
||||
|nvim_buf_lines_event| notifications (e.g. because it
|
||||
was too big).
|
||||
|
||||
nvim_buf_changedtick_event[{buf}, {changedtick}] *nvim_buf_changedtick_event*
|
||||
|
||||
When |b:changedtick| was incremented but no text was changed. Relevant for
|
||||
undo/redo.
|
||||
|
||||
Properties: ~
|
||||
{buf} API buffer handle (buffer number)
|
||||
{changedtick} new value of |b:changedtick| for the buffer
|
||||
Parameters: ~
|
||||
• {buf} (`integer`) Buffer id
|
||||
• {changedtick} (`integer`) New value of |b:changedtick|.
|
||||
|
||||
nvim_buf_detach_event[{buf}] *nvim_buf_detach_event*
|
||||
|
||||
When buffer is detached (i.e. updates are disabled). Triggered explicitly by
|
||||
|nvim_buf_detach()| or implicitly in these cases:
|
||||
- Buffer was |abandon|ed and 'hidden' is not set.
|
||||
@@ -317,8 +312,8 @@ nvim_buf_detach_event[{buf}] *nvim_buf_detach_event*
|
||||
|:checktime| or 'autoread'.
|
||||
- Generally: whenever the buffer contents are unloaded from memory.
|
||||
|
||||
Properties: ~
|
||||
{buf} API buffer handle (buffer number)
|
||||
Parameters: ~
|
||||
• {buf} (`integer`) Buffer id
|
||||
|
||||
|
||||
EXAMPLE ~
|
||||
@@ -409,7 +404,7 @@ after adding them, the returned |extmark| id can be used. >lua
|
||||
See also |vim.hl.range()|.
|
||||
|
||||
==============================================================================
|
||||
Floating windows *api-floatwin* *floating-windows*
|
||||
Floating windows *api-floatwin* *floating-windows*
|
||||
|
||||
Floating windows ("floats") are displayed on top of normal windows. This is
|
||||
useful to implement simple widgets, such as tooltips displayed next to the
|
||||
@@ -3982,6 +3977,8 @@ nvim_win_set_config({window}, {config}) *nvim_win_set_config()*
|
||||
Reconfigures the layout and properties of a window.
|
||||
• Updates only the given keys; unspecified (`nil`) keys will not be
|
||||
changed.
|
||||
• Can move a window to another tabpage.
|
||||
• Can transform a window to/from a float.
|
||||
• Keys `row` / `col` / `relative` must be specified together.
|
||||
• Cannot move the last window in a tabpage to a different one.
|
||||
|
||||
@@ -4191,8 +4188,8 @@ nvim_win_set_buf({window}, {buffer}) *nvim_win_set_buf()*
|
||||
• {buffer} (`integer`) Buffer id
|
||||
|
||||
nvim_win_set_cursor({window}, {pos}) *nvim_win_set_cursor()*
|
||||
Sets the (1,0)-indexed cursor position in the window. |api-indexing| This
|
||||
scrolls the window even if it is not the current one.
|
||||
Sets the (1,0)-indexed cursor position (byte offset) in the window.
|
||||
|api-indexing| This scrolls the window even if it is not the current one.
|
||||
|
||||
Attributes: ~
|
||||
Since: 0.1.0
|
||||
|
||||
@@ -301,15 +301,15 @@ all loaded. For example, if this command: >
|
||||
|
||||
set runtimepath
|
||||
|
||||
produces this output:
|
||||
produces this output: >
|
||||
|
||||
runtimepath=/etc/vim,~/.config/nvim,/usr/local/share/vim/vim82 ~
|
||||
runtimepath=/etc/vim,~/.config/nvim,/usr/local/share/vim/vim82
|
||||
|
||||
then Vim will load all plugins in these directories and below:
|
||||
then Vim will load all plugins in these directories and below: >
|
||||
|
||||
/etc/vim/plugin/ ~
|
||||
~/.config/nvim/plugin/ ~
|
||||
/usr/local/share/vim/vim82/plugin/ ~
|
||||
/etc/vim/plugin/
|
||||
~/.config/nvim/plugin/
|
||||
/usr/local/share/vim/vim82/plugin/
|
||||
|
||||
Note that the last one is the value of $VIMRUNTIME which has been expanded.
|
||||
|
||||
@@ -323,9 +323,9 @@ happens when Vim starts up by using the |-V| argument: >
|
||||
vim -V2
|
||||
|
||||
You will see a lot of messages, in between them is a remark about loading the
|
||||
plugins. It starts with:
|
||||
plugins. It starts with: >
|
||||
|
||||
Searching for "plugin/**/*.vim" in ~
|
||||
Searching for "plugin/**/*.vim" in
|
||||
|
||||
There you can see where Vim looks for your plugin scripts.
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ API
|
||||
• |nvim_open_tabpage()| can open a new |tab-page|.
|
||||
• |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.
|
||||
• |nvim_win_set_config()| can move |floating-windows| to other tabpages.
|
||||
• 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.
|
||||
|
||||
@@ -6902,10 +6902,11 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
*'title'* *'notitle'*
|
||||
'title' boolean (default off)
|
||||
global
|
||||
When on, the title of the window will be set to the value of
|
||||
'titlestring' (if it is not empty), or to:
|
||||
If enabled, Nvim will update the (GUI or terminal) window title. The
|
||||
format is configured by 'titlestring'. By default it looks like: >
|
||||
filename [+=-] (path) - Nvim
|
||||
Where:
|
||||
<
|
||||
where: >
|
||||
filename the name of the file being edited
|
||||
- indicates the file cannot be modified, 'ma' off
|
||||
+ indicates the file was modified
|
||||
@@ -6913,6 +6914,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
=+ indicates the file is read-only and modified
|
||||
(path) is the path of the file being edited
|
||||
- Nvim the server name |v:servername| or "Nvim"
|
||||
<
|
||||
|
||||
*'titlelen'*
|
||||
'titlelen' number (default 85)
|
||||
@@ -6938,32 +6940,32 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
*'titlestring'*
|
||||
'titlestring' string (default "")
|
||||
global
|
||||
When this option is not empty, it will be used for the title of the
|
||||
window. This happens only when the 'title' option is on.
|
||||
Formats the window title, enabled by the 'title' option.
|
||||
|
||||
When this option contains printf-style '%' items, they will be
|
||||
expanded according to the rules used for 'statusline'. If it contains
|
||||
an invalid '%' format, the value is used as-is and no error or warning
|
||||
will be given when the value is set.
|
||||
Contains printf-style "%" items, expanded according to the rules of
|
||||
'statusline'. If a "%" format is invalid, it is used as-is and no
|
||||
error will be given.
|
||||
|
||||
The default behaviour is equivalent to: >vim
|
||||
The default (empty) behaviour is equivalent to: >vim
|
||||
set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
|
||||
<
|
||||
This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
|
||||
Example: >vim
|
||||
auto BufEnter * let &titlestring = hostname() .. "/" .. expand("%:p")
|
||||
set title titlestring=%<%F%=%l/%L-%P titlelen=70
|
||||
< The value of 'titlelen' is used to align items in the middle or right
|
||||
of the available space.
|
||||
Some people prefer to have the file name first: >vim
|
||||
< The value of 'titlelen' is used to align items in the middle
|
||||
or right of the available space.
|
||||
|
||||
Example: to have the file name first: >vim
|
||||
set titlestring=%t%(\ %M%)%(\ (%{expand(\"%:~:.:h\")})%)%(\ %a%)
|
||||
< Note the use of "%{ }" and an expression to get the path of the file,
|
||||
without the file name. The "%( %)" constructs are used to add a
|
||||
< Note the use of "%{ }" and an expression to get the path of
|
||||
the file, without the file name. The "%( %)" constructs add a
|
||||
separating space only when needed.
|
||||
|
||||
NOTE: Use of special characters in 'titlestring' may cause the display
|
||||
to be garbled (e.g., when it contains a CR or NL character).
|
||||
|
||||
This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
|
||||
*'ttimeout'* *'nottimeout'*
|
||||
'ttimeout' boolean (default on)
|
||||
global
|
||||
|
||||
4
runtime/lua/vim/_meta/api.lua
generated
4
runtime/lua/vim/_meta/api.lua
generated
@@ -2507,6 +2507,8 @@ function vim.api.nvim_win_set_buf(window, buffer) end
|
||||
--- Reconfigures the layout and properties of a window.
|
||||
---
|
||||
--- - Updates only the given keys; unspecified (`nil`) keys will not be changed.
|
||||
--- - Can move a window to another tabpage.
|
||||
--- - Can transform a window to/from a float.
|
||||
--- - Keys `row` / `col` / `relative` must be specified together.
|
||||
--- - Cannot move the last window in a tabpage to a different one.
|
||||
---
|
||||
@@ -2522,7 +2524,7 @@ function vim.api.nvim_win_set_buf(window, buffer) end
|
||||
--- @param config vim.api.keyset.win_config Map defining the window configuration, see [nvim_open_win()]
|
||||
function vim.api.nvim_win_set_config(window, config) end
|
||||
|
||||
--- Sets the (1,0)-indexed cursor position in the window. `api-indexing`
|
||||
--- Sets the (1,0)-indexed cursor position (byte offset) in the window. `api-indexing`
|
||||
--- This scrolls the window even if it is not the current one.
|
||||
---
|
||||
--- @param window integer `window-ID`, or 0 for current window
|
||||
|
||||
40
runtime/lua/vim/_meta/options.lua
generated
40
runtime/lua/vim/_meta/options.lua
generated
@@ -7479,10 +7479,14 @@ vim.o.tm = vim.o.timeoutlen
|
||||
vim.go.timeoutlen = vim.o.timeoutlen
|
||||
vim.go.tm = vim.go.timeoutlen
|
||||
|
||||
--- When on, the title of the window will be set to the value of
|
||||
--- 'titlestring' (if it is not empty), or to:
|
||||
--- If enabled, Nvim will update the (GUI or terminal) window title. The
|
||||
--- format is configured by 'titlestring'. By default it looks like:
|
||||
--- ```
|
||||
--- filename [+=-] (path) - Nvim
|
||||
--- Where:
|
||||
--- ```
|
||||
---
|
||||
--- where:
|
||||
--- ```
|
||||
--- filename the name of the file being edited
|
||||
--- - indicates the file cannot be modified, 'ma' off
|
||||
--- + indicates the file was modified
|
||||
@@ -7490,6 +7494,8 @@ vim.go.tm = vim.go.timeoutlen
|
||||
--- =+ indicates the file is read-only and modified
|
||||
--- (path) is the path of the file being edited
|
||||
--- - Nvim the server name `v:servername` or "Nvim"
|
||||
--- ```
|
||||
---
|
||||
---
|
||||
--- @type boolean
|
||||
vim.o.title = false
|
||||
@@ -7518,41 +7524,41 @@ vim.go.titlelen = vim.o.titlelen
|
||||
vim.o.titleold = ""
|
||||
vim.go.titleold = vim.o.titleold
|
||||
|
||||
--- When this option is not empty, it will be used for the title of the
|
||||
--- window. This happens only when the 'title' option is on.
|
||||
--- Formats the window title, enabled by the 'title' option.
|
||||
---
|
||||
--- When this option contains printf-style '%' items, they will be
|
||||
--- expanded according to the rules used for 'statusline'. If it contains
|
||||
--- an invalid '%' format, the value is used as-is and no error or warning
|
||||
--- will be given when the value is set.
|
||||
--- Contains printf-style "%" items, expanded according to the rules of
|
||||
--- 'statusline'. If a "%" format is invalid, it is used as-is and no
|
||||
--- error will be given.
|
||||
---
|
||||
--- The default behaviour is equivalent to:
|
||||
--- The default (empty) behaviour is equivalent to:
|
||||
---
|
||||
--- ```vim
|
||||
--- set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
|
||||
--- ```
|
||||
---
|
||||
--- This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
---
|
||||
--- Example:
|
||||
---
|
||||
--- ```vim
|
||||
--- auto BufEnter * let &titlestring = hostname() .. "/" .. expand("%:p")
|
||||
--- set title titlestring=%<%F%=%l/%L-%P titlelen=70
|
||||
--- ```
|
||||
--- The value of 'titlelen' is used to align items in the middle or right
|
||||
--- of the available space.
|
||||
--- Some people prefer to have the file name first:
|
||||
--- The value of 'titlelen' is used to align items in the middle
|
||||
--- or right of the available space.
|
||||
---
|
||||
--- Example: to have the file name first:
|
||||
---
|
||||
--- ```vim
|
||||
--- set titlestring=%t%(\ %M%)%(\ (%{expand(\"%:~:.:h\")})%)%(\ %a%)
|
||||
--- ```
|
||||
--- Note the use of "%{ }" and an expression to get the path of the file,
|
||||
--- without the file name. The "%( %)" constructs are used to add a
|
||||
--- Note the use of "%{ }" and an expression to get the path of
|
||||
--- the file, without the file name. The "%( %)" constructs add a
|
||||
--- separating space only when needed.
|
||||
---
|
||||
--- NOTE: Use of special characters in 'titlestring' may cause the display
|
||||
--- to be garbled (e.g., when it contains a CR or NL character).
|
||||
---
|
||||
--- This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
---
|
||||
--- @type string
|
||||
vim.o.titlestring = ""
|
||||
vim.go.titlestring = vim.o.titlestring
|
||||
|
||||
@@ -193,11 +193,10 @@ ArrayOf(DictAs(get_autocmds__ret)) nvim_get_autocmds(Dict(get_autocmds) *opts, A
|
||||
buffers = arena_array(arena, 1);
|
||||
ADD_C(buffers, STRING_OBJ(pat));
|
||||
} else if (opts->buffer.type == kObjectTypeArray) {
|
||||
if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) {
|
||||
api_set_error(err, kErrorTypeValidation, "Too many buffers (maximum of %d)",
|
||||
AUCMD_MAX_PATTERNS);
|
||||
VALIDATE((opts->buffer.data.array.size <= AUCMD_MAX_PATTERNS),
|
||||
"Too many buffers (maximum of %d)", AUCMD_MAX_PATTERNS, {
|
||||
goto cleanup;
|
||||
}
|
||||
});
|
||||
|
||||
buffers = arena_array(arena, kv_size(opts->buffer.data.array));
|
||||
FOREACH_ITEM(opts->buffer.data.array, bufnr, {
|
||||
|
||||
@@ -60,10 +60,9 @@ void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *
|
||||
FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY
|
||||
{
|
||||
if (strequal("termresponse", event.data)) {
|
||||
if (value.type != kObjectTypeString) {
|
||||
api_set_error(err, kErrorTypeValidation, "termresponse must be a string");
|
||||
VALIDATE_T("termresponse", kObjectTypeString, value.type, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const String termresponse = value.data.string;
|
||||
set_vim_var_string(VV_TERMRESPONSE, termresponse.data, (ptrdiff_t)termresponse.size);
|
||||
|
||||
@@ -140,10 +140,9 @@ Object dict_get_value(dict_T *dict, String key, Arena *arena, Error *err)
|
||||
{
|
||||
dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
|
||||
|
||||
if (di == NULL) {
|
||||
api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data);
|
||||
VALIDATE(di != NULL, "Key not found: %s", key.data, {
|
||||
return (Object)OBJECT_INIT;
|
||||
}
|
||||
});
|
||||
|
||||
return vim_to_object(&di->di_tv, arena, true);
|
||||
}
|
||||
@@ -269,9 +268,9 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err)
|
||||
|
||||
buf_T *rv = handle_get_buffer(buffer);
|
||||
|
||||
if (!rv) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid buffer id: %d", buffer);
|
||||
}
|
||||
VALIDATE_INT(rv, "buffer id", buffer, {
|
||||
return NULL;
|
||||
});
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -284,9 +283,9 @@ win_T *find_window_by_handle(Window window, Error *err)
|
||||
|
||||
win_T *rv = handle_get_window(window);
|
||||
|
||||
if (!rv) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid window id: %d", window);
|
||||
}
|
||||
VALIDATE_INT(rv, "window id", window, {
|
||||
return NULL;
|
||||
});
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -299,9 +298,9 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err)
|
||||
|
||||
tabpage_T *rv = handle_get_tabpage(tabpage);
|
||||
|
||||
if (!rv) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid tabpage id: %d", tabpage);
|
||||
}
|
||||
VALIDATE_INT(rv, "tabpage id", tabpage, {
|
||||
return NULL;
|
||||
});
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -480,10 +479,9 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col
|
||||
{
|
||||
String rv = STRING_INIT;
|
||||
|
||||
if (lnum >= MAXLNUM) {
|
||||
api_set_error(err, kErrorTypeValidation, "Line index is too high");
|
||||
VALIDATE_RANGE((lnum < MAXLNUM), "line index", {
|
||||
return rv;
|
||||
}
|
||||
});
|
||||
|
||||
char *bufstr = ml_get_buf(buf, (linenr_T)lnum);
|
||||
colnr_T line_length = ml_get_buf_len(buf, (linenr_T)lnum);
|
||||
@@ -720,7 +718,7 @@ bool api_object_to_bool(Object obj, const char *what, bool nil_value, Error *err
|
||||
} else if (obj.type == kObjectTypeNil) {
|
||||
return nil_value; // caller decides what NIL (missing retval in Lua) means
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "%s is not a boolean", what);
|
||||
VALIDATE_EXP(false, what, "boolean", NULL, {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -734,7 +732,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
|
||||
int id = (int)obj.data.integer;
|
||||
return (1 <= id && id <= highlight_num_groups()) ? id : 0;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid hl_group: %s", what);
|
||||
VALIDATE_S(false, "hl_group", what, {});
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1010,14 +1008,12 @@ bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err)
|
||||
col = 0;
|
||||
deleting = true;
|
||||
} else {
|
||||
if (col > MAXCOL) {
|
||||
api_set_error(err, kErrorTypeValidation, "Column value outside range");
|
||||
VALIDATE_RANGE(!(col > MAXCOL), "column", {
|
||||
return res;
|
||||
}
|
||||
if (line < 1 || line > buf->b_ml.ml_line_count) {
|
||||
api_set_error(err, kErrorTypeValidation, "Line value outside range");
|
||||
});
|
||||
VALIDATE_RANGE(!(line < 1 || line > buf->b_ml.ml_line_count), "line", {
|
||||
return res;
|
||||
}
|
||||
});
|
||||
}
|
||||
assert(INT32_MIN <= line && line <= INT32_MAX);
|
||||
pos_T pos = { (linenr_T)line, (int)col, 0 };
|
||||
|
||||
@@ -57,6 +57,31 @@ void api_err_exp(Error *err, const char *name, const char *expected, const char
|
||||
name, expected, actual);
|
||||
}
|
||||
|
||||
/// Creates "Required: …" message and sets it on `err`.
|
||||
void api_err_required(Error *err, const char *name)
|
||||
{
|
||||
ErrorType errtype = kErrorTypeValidation;
|
||||
// Treat `name` without whitespace as a parameter (surround in quotes).
|
||||
// Treat `name` with whitespace as a description (no quotes).
|
||||
const char *has_space = strchr(name, ' ');
|
||||
|
||||
api_set_error(err, errtype, has_space ? "Required: %s" : "Required: '%s'", name);
|
||||
}
|
||||
|
||||
/// Creates "Conflict: … not allowed with …" message and sets it on `err`.
|
||||
void api_err_conflict(Error *err, const char *name, const char *name2)
|
||||
{
|
||||
ErrorType errtype = kErrorTypeValidation;
|
||||
// Treat `name` without whitespace as a parameter (surround in quotes).
|
||||
// Treat `name` with whitespace as a description (no quotes).
|
||||
const char *has_space2 = strchr(name2, ' ');
|
||||
|
||||
api_set_error(err, errtype, has_space2
|
||||
? "Conflict: '%s' not allowed with %s"
|
||||
: "Conflict: '%s' not allowed with '%s'",
|
||||
name, name2);
|
||||
}
|
||||
|
||||
bool check_string_array(Array arr, char *name, bool disallow_nl, Error *err)
|
||||
{
|
||||
snprintf(IObuff, sizeof(IObuff), "'%s' item", name);
|
||||
|
||||
@@ -16,6 +16,23 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VALIDATE_R(cond, name, code) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
api_err_required(err, name); \
|
||||
code; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/// Shows a "not allowed with" message, for mutually-exclusive args.
|
||||
#define VALIDATE_CON(cond, name, name2, code) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
api_err_conflict(err, name, name2); \
|
||||
code; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VALIDATE_INT(cond, name, val_, code) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
@@ -88,7 +105,4 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define VALIDATE_R(cond, name, code) \
|
||||
VALIDATE(cond, "Required: '%s'", name, code);
|
||||
|
||||
#include "api/private/validate.h.generated.h"
|
||||
|
||||
@@ -447,7 +447,9 @@ static void ui_set_option(RemoteUI *ui, bool init, String name, Object value, Er
|
||||
}
|
||||
}
|
||||
|
||||
api_set_error(err, kErrorTypeValidation, "No such UI option: %s", name.data);
|
||||
VALIDATE_S(false, "UI option", name.data, {
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
/// Tell Nvim to resize a grid. Triggers a grid_resize event with the requested
|
||||
@@ -495,8 +497,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
|
||||
}
|
||||
|
||||
if (!ui->ui_ext[kUIPopupmenu]) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"It must support the ext_popupmenu option");
|
||||
api_set_error(err, kErrorTypeValidation, "UI must support the ext_popupmenu option");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ void nvim_set_hl(uint64_t channel_id, Integer ns_id, String name, Dict(highlight
|
||||
|
||||
// Setting URLs directly through highlight attributes is not supported
|
||||
if (HAS_KEY(val, highlight, url)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid Key: 'url'");
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid key: 'url'");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "nvim/api/private/converter.h"
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/api/private/validate.h"
|
||||
#include "nvim/api/vimscript.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
@@ -303,8 +304,9 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
|
||||
object_to_vim(dict, &rettv, err);
|
||||
break;
|
||||
default:
|
||||
api_set_error(err, kErrorTypeValidation, "dict argument type must be String or Dict");
|
||||
return rv;
|
||||
VALIDATE_EXP(false, "dict argument", "String or Dict", NULL, {
|
||||
return rv;
|
||||
});
|
||||
}
|
||||
dict_T *self_dict = rettv.vval.v_dict;
|
||||
if (rettv.v_type != VAR_DICT || !self_dict) {
|
||||
@@ -314,29 +316,26 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
|
||||
|
||||
if (fn.data && fn.size > 0 && dict.type != kObjectTypeDict) {
|
||||
dictitem_T *const di = tv_dict_find(self_dict, fn.data, (ptrdiff_t)fn.size);
|
||||
if (di == NULL) {
|
||||
api_set_error(err, kErrorTypeValidation, "Not found: %s", fn.data);
|
||||
VALIDATE(di != NULL, "Not found: %s", fn.data, {
|
||||
goto end;
|
||||
}
|
||||
});
|
||||
if (di->di_tv.v_type == VAR_PARTIAL) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"partial function not supported");
|
||||
goto end;
|
||||
}
|
||||
if (di->di_tv.v_type != VAR_FUNC) {
|
||||
api_set_error(err, kErrorTypeValidation, "Not a function: %s", fn.data);
|
||||
VALIDATE((di->di_tv.v_type == VAR_FUNC), "Not a function: %s", fn.data, {
|
||||
goto end;
|
||||
}
|
||||
});
|
||||
fn = (String) {
|
||||
.data = di->di_tv.vval.v_string,
|
||||
.size = strlen(di->di_tv.vval.v_string),
|
||||
};
|
||||
}
|
||||
|
||||
if (!fn.data || fn.size < 1) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid (empty) function name");
|
||||
VALIDATE((fn.data && fn.size >= 1), "Invalid function name: %s", "(empty)", {
|
||||
goto end;
|
||||
}
|
||||
});
|
||||
|
||||
rv = _call_function(fn, args, self_dict, arena, err);
|
||||
end:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/dispatch.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/api/private/validate.h"
|
||||
#include "nvim/api/win_config.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/autocmd.h"
|
||||
@@ -738,6 +739,8 @@ restore_curwin:
|
||||
/// Reconfigures the layout and properties of a window.
|
||||
///
|
||||
/// - Updates only the given keys; unspecified (`nil`) keys will not be changed.
|
||||
/// - Can move a window to another tabpage.
|
||||
/// - Can transform a window to/from a float.
|
||||
/// - Keys `row` / `col` / `relative` must be specified together.
|
||||
/// - Cannot move the last window in a tabpage to a different one.
|
||||
///
|
||||
@@ -1010,15 +1013,15 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out)
|
||||
static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, WinConfig *fconfig,
|
||||
Error *err)
|
||||
{
|
||||
if (bordertext.type != kObjectTypeString && bordertext.type != kObjectTypeArray) {
|
||||
api_set_error(err, kErrorTypeValidation, "title/footer must be string or array");
|
||||
VALIDATE_EXP(!(bordertext.type != kObjectTypeString && bordertext.type != kObjectTypeArray),
|
||||
"title/footer", "String or Array", api_typename(bordertext.type), {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (bordertext.type == kObjectTypeArray && bordertext.data.array.size == 0) {
|
||||
api_set_error(err, kErrorTypeValidation, "title/footer cannot be an empty array");
|
||||
VALIDATE_EXP(!(bordertext.type == kObjectTypeArray && bordertext.data.array.size == 0),
|
||||
"title/footer", "non-empty Array", NULL, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
bool *is_present;
|
||||
VirtText *chunks;
|
||||
@@ -1084,15 +1087,9 @@ static bool parse_bordertext_pos(win_T *wp, String bordertext_pos, BorderTextTyp
|
||||
} else if (strequal(pos, "right")) {
|
||||
*align = kAlignRight;
|
||||
} else {
|
||||
switch (bordertext_type) {
|
||||
case kBorderTextTitle:
|
||||
api_set_error(err, kErrorTypeValidation, "invalid title_pos value");
|
||||
break;
|
||||
case kBorderTextFooter:
|
||||
api_set_error(err, kErrorTypeValidation, "invalid footer_pos value");
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
VALIDATE_S(false, (bordertext_type == kBorderTextTitle ? "title_pos" : "footer_pos"), pos, {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1121,24 +1118,22 @@ void parse_border_style(Object style, WinConfig *fconfig, Error *err)
|
||||
if (style.type == kObjectTypeArray) {
|
||||
Array arr = style.data.array;
|
||||
size_t size = arr.size;
|
||||
if (!size || size > 8 || (size & (size - 1))) {
|
||||
api_set_error(err, kErrorTypeValidation, "invalid number of border chars");
|
||||
VALIDATE_EXP(!(!size || size > 8 || (size & (size - 1))),
|
||||
"border", "1, 2, 4, or 8 chars", NULL, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
Object iytem = arr.items[i];
|
||||
String string;
|
||||
int hl_id = 0;
|
||||
if (iytem.type == kObjectTypeArray) {
|
||||
Array iarr = iytem.data.array;
|
||||
if (!iarr.size || iarr.size > 2) {
|
||||
api_set_error(err, kErrorTypeValidation, "invalid border char");
|
||||
VALIDATE_EXP(!(!iarr.size || iarr.size > 2), "border", "1 or 2-item Array", NULL, {
|
||||
return;
|
||||
}
|
||||
if (iarr.items[0].type != kObjectTypeString) {
|
||||
api_set_error(err, kErrorTypeValidation, "invalid border char");
|
||||
});
|
||||
VALIDATE_EXP(iarr.items[0].type == kObjectTypeString, "border", "Array of Strings", NULL, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
string = iarr.items[0].data.string;
|
||||
if (iarr.size == 2) {
|
||||
hl_id = object_to_hl_id(iarr.items[1], "border char highlight", err);
|
||||
@@ -1149,13 +1144,14 @@ void parse_border_style(Object style, WinConfig *fconfig, Error *err)
|
||||
} else if (iytem.type == kObjectTypeString) {
|
||||
string = iytem.data.string;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "invalid border char");
|
||||
return;
|
||||
VALIDATE_EXP(false, "border", "String or Array", api_typename(iytem.type), {
|
||||
return;
|
||||
});
|
||||
}
|
||||
if (string.size && mb_string2cells_len(string.data, string.size) > 1) {
|
||||
api_set_error(err, kErrorTypeValidation, "border chars must be one cell");
|
||||
VALIDATE_EXP(!(string.size && mb_string2cells_len(string.data, string.size) > 1),
|
||||
"border", "only one-cell chars", NULL, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
size_t len = MIN(string.size, sizeof(*chars) - 1);
|
||||
if (len) {
|
||||
memcpy(chars[i], string.data, len);
|
||||
@@ -1168,12 +1164,13 @@ void parse_border_style(Object style, WinConfig *fconfig, Error *err)
|
||||
memcpy(hl_ids + size, hl_ids, sizeof(*hl_ids) * size);
|
||||
size <<= 1;
|
||||
}
|
||||
if ((chars[7][0] && chars[1][0] && !chars[0][0])
|
||||
|| (chars[1][0] && chars[3][0] && !chars[2][0])
|
||||
|| (chars[3][0] && chars[5][0] && !chars[4][0])
|
||||
|| (chars[5][0] && chars[7][0] && !chars[6][0])) {
|
||||
api_set_error(err, kErrorTypeValidation, "corner between used edges must be specified");
|
||||
}
|
||||
VALIDATE_EXP(!((chars[7][0] && chars[1][0] && !chars[0][0])
|
||||
|| (chars[1][0] && chars[3][0] && !chars[2][0])
|
||||
|| (chars[3][0] && chars[5][0] && !chars[4][0])
|
||||
|| (chars[5][0] && chars[7][0] && !chars[6][0])), "border",
|
||||
"corner char between edge chars", NULL, {
|
||||
return;
|
||||
});
|
||||
} else if (style.type == kObjectTypeString) {
|
||||
String str = style.data.string;
|
||||
if (str.size == 0 || strequal(str.data, "none")) {
|
||||
@@ -1199,7 +1196,9 @@ void parse_border_style(Object style, WinConfig *fconfig, Error *err)
|
||||
return;
|
||||
}
|
||||
}
|
||||
api_set_error(err, kErrorTypeValidation, "invalid border style \"%s\"", str.data);
|
||||
VALIDATE_S(false, "border", str.data, {
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1207,10 +1206,10 @@ static void generate_api_error(win_T *wp, const char *attribute, Error *err)
|
||||
{
|
||||
if (wp != NULL && wp->w_floating) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Missing 'relative' field when reconfiguring floating window %d",
|
||||
"Required: 'relative' when reconfiguring floating window %d",
|
||||
wp->handle);
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have '%s'", attribute);
|
||||
VALIDATE_CON(false, attribute, "non-float window", {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,16 +1264,15 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
{
|
||||
bool has_relative = false, relative_is_win = false, is_split = false;
|
||||
if (config->relative.size > 0) {
|
||||
if (!parse_float_relative(config->relative, &fconfig->relative)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
|
||||
VALIDATE_S(parse_float_relative(config->relative, &fconfig->relative),
|
||||
"relative", config->relative.data, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
if (config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col))
|
||||
&& !HAS_KEY_X(config, bufpos)) {
|
||||
api_set_error(err, kErrorTypeValidation, "'relative' requires 'row'/'col' or 'bufpos'");
|
||||
VALIDATE_R(!(config->relative.size > 0 && !(HAS_KEY_X(config, row) && HAS_KEY_X(config, col))
|
||||
&& !HAS_KEY_X(config, bufpos)), "'relative' requires 'row'/'col' or 'bufpos'", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
has_relative = true;
|
||||
fconfig->external = false;
|
||||
@@ -1287,35 +1285,34 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
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");
|
||||
goto fail;
|
||||
VALIDATE_R(false, "'relative' or 'external' when creating a float", {
|
||||
goto fail;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, vertical)) {
|
||||
if (!is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
VALIDATE_CON(!(HAS_KEY_X(config, vertical) && !is_split), "vertical", "floating windows", {
|
||||
goto fail;
|
||||
});
|
||||
|
||||
VALIDATE_CON(!(HAS_KEY_X(config, split) && !is_split), "split", "floating windows", {
|
||||
goto fail;
|
||||
});
|
||||
|
||||
if (HAS_KEY_X(config, split)) {
|
||||
if (!is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'");
|
||||
VALIDATE_CON(is_split, "split", "floating windows", {
|
||||
goto fail;
|
||||
}
|
||||
if (!parse_config_split(config->split, &fconfig->split)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key");
|
||||
});
|
||||
VALIDATE_S(parse_config_split(config->split, &fconfig->split), "split", config->split.data, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, anchor)) {
|
||||
if (!parse_float_anchor(config->anchor, &fconfig->anchor)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key");
|
||||
VALIDATE_S(parse_float_anchor(config->anchor, &fconfig->anchor),
|
||||
"anchor", config->anchor.data, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, row)) {
|
||||
@@ -1339,10 +1336,10 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
generate_api_error(wp, "bufpos", err);
|
||||
goto fail;
|
||||
} else {
|
||||
if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
|
||||
VALIDATE_EXP(parse_float_bufpos(config->bufpos, &fconfig->bufpos),
|
||||
"bufpos", "[row, col] array", NULL, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
if (!HAS_KEY_X(config, row)) {
|
||||
fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1;
|
||||
@@ -1354,46 +1351,42 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, width)) {
|
||||
if (config->width > 0) {
|
||||
fconfig->width = (int)config->width;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
|
||||
VALIDATE_EXP((config->width > 0), "width", "positive Integer", NULL, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
fconfig->width = (int)config->width;
|
||||
} else if (!reconf && !is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
|
||||
goto fail;
|
||||
VALIDATE_R(false, "width", {
|
||||
goto fail;
|
||||
});
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, height)) {
|
||||
if (config->height > 0) {
|
||||
fconfig->height = (int)config->height;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
|
||||
VALIDATE_EXP((config->height > 0), "height", "positive Integer", NULL, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
fconfig->height = (int)config->height;
|
||||
} else if (!reconf && !is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
|
||||
goto fail;
|
||||
VALIDATE_R(false, "height", {
|
||||
goto fail;
|
||||
});
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, external)) {
|
||||
fconfig->external = config->external;
|
||||
if (has_relative && fconfig->external) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"Only one of 'relative' and 'external' must be used");
|
||||
VALIDATE_CON(!(has_relative && fconfig->external), "relative", "external", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
if (fconfig->external && !ui_has(kUIMultigrid)) {
|
||||
api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, win) && fconfig->external) {
|
||||
api_set_error(err, kErrorTypeValidation, "external window cannot have 'win'");
|
||||
VALIDATE_CON(!(HAS_KEY_X(config, win) && fconfig->external), "win", "external window", {
|
||||
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.
|
||||
@@ -1409,11 +1402,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
} 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'");
|
||||
VALIDATE_R(!(!is_split && !has_relative && (!wp || !wp->w_floating)),
|
||||
"non-float with 'win' requires 'split' or 'vertical'", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
fconfig->window = config->win;
|
||||
}
|
||||
// Resolve, but skip validating. E.g: win_config_split accepts negative "win".
|
||||
@@ -1432,23 +1425,19 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, zindex)) {
|
||||
if (is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'zindex'");
|
||||
VALIDATE_CON(!is_split, "zindex", "non-float window", {
|
||||
goto fail;
|
||||
}
|
||||
if (config->zindex > 0) {
|
||||
fconfig->zindex = (int)config->zindex;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
|
||||
});
|
||||
VALIDATE_EXP((config->zindex > 0), "zindex", "positive Integer", NULL, {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
fconfig->zindex = (int)config->zindex;
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, title)) {
|
||||
if (is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'");
|
||||
VALIDATE_CON(!is_split, "title", "non-float window", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
parse_bordertext(config->title, kBorderTextTitle, fconfig, err);
|
||||
if (ERROR_SET(err)) {
|
||||
@@ -1460,17 +1449,15 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (HAS_KEY_X(config, title_pos)) {
|
||||
api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
|
||||
VALIDATE_R(!HAS_KEY_X(config, title_pos), "'title' requires 'title_pos'", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, footer)) {
|
||||
if (is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'");
|
||||
VALIDATE_CON(!is_split, "footer", "non-float window", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
|
||||
parse_bordertext(config->footer, kBorderTextFooter, fconfig, err);
|
||||
if (ERROR_SET(err)) {
|
||||
@@ -1482,18 +1469,16 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (HAS_KEY_X(config, footer_pos)) {
|
||||
api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set");
|
||||
VALIDATE_R(!HAS_KEY_X(config, footer_pos), "'footer' requires 'footer_pos'", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object border_style = OBJECT_INIT;
|
||||
if (HAS_KEY_X(config, border)) {
|
||||
if (is_split) {
|
||||
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
|
||||
VALIDATE_CON(!is_split, "border", "non-float window", {
|
||||
goto fail;
|
||||
}
|
||||
});
|
||||
border_style = config->border;
|
||||
if (border_style.type != kObjectTypeNil) {
|
||||
parse_border_style(border_style, fconfig, err);
|
||||
@@ -1512,15 +1497,15 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
|
||||
} else if (striequal(config->style.data, "minimal")) {
|
||||
fconfig->style = kWinStyleMinimal;
|
||||
} else {
|
||||
api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
|
||||
goto fail;
|
||||
VALIDATE_S(false, "style", config->style.data, {
|
||||
goto fail;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_KEY_X(config, noautocmd)) {
|
||||
if (wp && config->noautocmd != fconfig->noautocmd) {
|
||||
api_set_error(err, kErrorTypeValidation,
|
||||
"'noautocmd' cannot be changed with existing windows");
|
||||
api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be changed on existing window");
|
||||
goto fail;
|
||||
}
|
||||
fconfig->noautocmd = config->noautocmd;
|
||||
|
||||
@@ -92,7 +92,7 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Arena *arena, Error *err)
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// Sets the (1,0)-indexed cursor position in the window. |api-indexing|
|
||||
/// Sets the (1,0)-indexed cursor position (byte offset) in the window. |api-indexing|
|
||||
/// This scrolls the window even if it is not the current one.
|
||||
///
|
||||
/// @param window |window-ID|, or 0 for current window
|
||||
@@ -107,26 +107,21 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger
|
||||
|| pos.items[1].type != kObjectTypeInteger) {
|
||||
api_set_error(err,
|
||||
kErrorTypeValidation,
|
||||
"Argument \"pos\" must be a [row, col] array");
|
||||
VALIDATE_EXP(!(pos.size != 2 || pos.items[0].type != kObjectTypeInteger
|
||||
|| pos.items[1].type != kObjectTypeInteger), "pos", "[row, col] array", NULL, {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
int64_t row = pos.items[0].data.integer;
|
||||
int64_t col = pos.items[1].data.integer;
|
||||
|
||||
if (row <= 0 || row > win->w_buffer->b_ml.ml_line_count) {
|
||||
api_set_error(err, kErrorTypeValidation, "Cursor position outside buffer");
|
||||
VALIDATE_RANGE(!(row <= 0 || row > win->w_buffer->b_ml.ml_line_count), "cursor line", {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (col > MAXCOL || col < 0) {
|
||||
api_set_error(err, kErrorTypeValidation, "Column value outside range");
|
||||
VALIDATE_RANGE(!(col > MAXCOL || col < 0), "cursor column", {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
win->w_cursor.lnum = (linenr_T)row;
|
||||
win->w_cursor.col = (colnr_T)col;
|
||||
@@ -450,9 +445,9 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err)
|
||||
}
|
||||
|
||||
// -1 is allowed as inherit global namespace
|
||||
if (ns_id < -1) {
|
||||
api_set_error(err, kErrorTypeValidation, "no such namespace");
|
||||
}
|
||||
VALIDATE_S((ns_id >= -1), "namespace", "", {
|
||||
return;
|
||||
});
|
||||
|
||||
win->w_ns_hl = (NS)ns_id;
|
||||
win->w_hl_needs_update = true;
|
||||
|
||||
@@ -9677,10 +9677,11 @@ local options = {
|
||||
cb = 'did_set_title_icon',
|
||||
defaults = false,
|
||||
desc = [=[
|
||||
When on, the title of the window will be set to the value of
|
||||
'titlestring' (if it is not empty), or to:
|
||||
If enabled, Nvim will update the (GUI or terminal) window title. The
|
||||
format is configured by 'titlestring'. By default it looks like: >
|
||||
filename [+=-] (path) - Nvim
|
||||
Where:
|
||||
<
|
||||
where: >
|
||||
filename the name of the file being edited
|
||||
- indicates the file cannot be modified, 'ma' off
|
||||
+ indicates the file was modified
|
||||
@@ -9688,6 +9689,7 @@ local options = {
|
||||
=+ indicates the file is read-only and modified
|
||||
(path) is the path of the file being edited
|
||||
- Nvim the server name |v:servername| or "Nvim"
|
||||
<
|
||||
]=],
|
||||
full_name = 'title',
|
||||
scope = { 'global' },
|
||||
@@ -9735,31 +9737,31 @@ local options = {
|
||||
cb = 'did_set_titlestring',
|
||||
defaults = '',
|
||||
desc = [=[
|
||||
When this option is not empty, it will be used for the title of the
|
||||
window. This happens only when the 'title' option is on.
|
||||
Formats the window title, enabled by the 'title' option.
|
||||
|
||||
When this option contains printf-style '%' items, they will be
|
||||
expanded according to the rules used for 'statusline'. If it contains
|
||||
an invalid '%' format, the value is used as-is and no error or warning
|
||||
will be given when the value is set.
|
||||
Contains printf-style "%" items, expanded according to the rules of
|
||||
'statusline'. If a "%" format is invalid, it is used as-is and no
|
||||
error will be given.
|
||||
|
||||
The default behaviour is equivalent to: >vim
|
||||
The default (empty) behaviour is equivalent to: >vim
|
||||
set titlestring=%t%(\ %M%)%(\ \(%{expand(\"%:~:h\")}\)%)%a\ -\ Nvim
|
||||
<
|
||||
This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
|
||||
Example: >vim
|
||||
auto BufEnter * let &titlestring = hostname() .. "/" .. expand("%:p")
|
||||
set title titlestring=%<%F%=%l/%L-%P titlelen=70
|
||||
< The value of 'titlelen' is used to align items in the middle or right
|
||||
of the available space.
|
||||
Some people prefer to have the file name first: >vim
|
||||
< The value of 'titlelen' is used to align items in the middle
|
||||
or right of the available space.
|
||||
|
||||
Example: to have the file name first: >vim
|
||||
set titlestring=%t%(\ %M%)%(\ (%{expand(\"%:~:.:h\")})%)%(\ %a%)
|
||||
< Note the use of "%{ }" and an expression to get the path of the file,
|
||||
without the file name. The "%( %)" constructs are used to add a
|
||||
< Note the use of "%{ }" and an expression to get the path of
|
||||
the file, without the file name. The "%( %)" constructs add a
|
||||
separating space only when needed.
|
||||
|
||||
NOTE: Use of special characters in 'titlestring' may cause the display
|
||||
to be garbled (e.g., when it contains a CR or NL character).
|
||||
|
||||
This option cannot be set in a modeline when 'modelineexpr' is off.
|
||||
]=],
|
||||
full_name = 'titlestring',
|
||||
modelineexpr = true,
|
||||
|
||||
@@ -119,6 +119,11 @@ end
|
||||
describe('API: buffer events:', function()
|
||||
before_each(clear)
|
||||
|
||||
it('validation', function()
|
||||
local b = editoriginal(false)
|
||||
eq("Invalid key: 'builtin'", pcall_err(api.nvim_buf_attach, b, false, { builtin = 'asfd' }))
|
||||
end)
|
||||
|
||||
it('when lines are added', function()
|
||||
local b, tick = editoriginal(true)
|
||||
|
||||
@@ -798,11 +803,6 @@ describe('API: buffer events:', function()
|
||||
expectn('nvim_buf_changedtick_event', { b, tick })
|
||||
end)
|
||||
|
||||
it('returns a proper error on nonempty options dict', function()
|
||||
local b = editoriginal(false)
|
||||
eq("Invalid key: 'builtin'", pcall_err(api.nvim_buf_attach, b, false, { builtin = 'asfd' }))
|
||||
end)
|
||||
|
||||
it('nvim_buf_attach returns response after delay #8634', function()
|
||||
sleep(250)
|
||||
-- response
|
||||
|
||||
@@ -143,7 +143,7 @@ describe('API/extmarks', function()
|
||||
)
|
||||
-- No memory leak with virt_text, virt_lines, sign_text
|
||||
eq(
|
||||
'right_gravity is not a boolean',
|
||||
"Invalid 'right_gravity': expected boolean",
|
||||
pcall_err(set_extmark, ns, marks[2], 0, 0, {
|
||||
virt_text = { { 'foo', 'Normal' } },
|
||||
virt_lines = { { { 'bar', 'Normal' } } },
|
||||
|
||||
@@ -116,6 +116,9 @@ describe('API: set highlight', function()
|
||||
"Invalid 'blend': expected Integer, got Array",
|
||||
pcall_err(api.nvim_set_hl, 0, 'Test_hl3', { fg = '#FF00FF', blend = {} })
|
||||
)
|
||||
-- 'url' is rejected. #38162
|
||||
eq("Invalid key: 'url'", pcall_err(api.nvim_set_hl, 0, 'Test', { url = 'https://example.com' }))
|
||||
assert_alive()
|
||||
end)
|
||||
|
||||
it('can set gui highlight', function()
|
||||
@@ -254,10 +257,6 @@ describe('API: set highlight', function()
|
||||
)
|
||||
assert_alive()
|
||||
end)
|
||||
it("'url' is rejected with an error #38162", function()
|
||||
eq("Invalid Key: 'url'", pcall_err(api.nvim_set_hl, 0, 'Test', { url = 'https://example.com' }))
|
||||
assert_alive()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('API: get highlight', function()
|
||||
|
||||
@@ -649,7 +649,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
|
||||
eq('Invalid mode shortname: "xnoremap"', pcall_err(api.nvim_del_keymap, 'xnoremap', 'lhs'))
|
||||
end)
|
||||
|
||||
it('error on invalid optnames', function()
|
||||
it('validation', function()
|
||||
eq(
|
||||
"Invalid key: 'silentt'",
|
||||
pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', { silentt = true })
|
||||
@@ -659,16 +659,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
|
||||
"Invalid key: 'nowaiT'",
|
||||
pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', { nowaiT = false })
|
||||
)
|
||||
end)
|
||||
|
||||
it('error on <buffer> option key', function()
|
||||
-- <buffer> option key
|
||||
eq(
|
||||
"Invalid key: 'buffer'",
|
||||
pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', { buffer = true })
|
||||
)
|
||||
end)
|
||||
|
||||
it('error when "replace_keycodes" is used without "expr"', function()
|
||||
eq(
|
||||
'"replace_keycodes" requires "expr"',
|
||||
pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', { replace_keycodes = true })
|
||||
@@ -681,7 +678,10 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
|
||||
it('throws an error when given non-boolean value for ' .. opt, function()
|
||||
local opts = {}
|
||||
opts[opt] = 'fooo'
|
||||
eq(opt .. ' is not a boolean', pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', opts))
|
||||
eq(
|
||||
("Invalid '%s': expected boolean"):format(opt),
|
||||
pcall_err(api.nvim_set_keymap, 'n', 'lhs', 'rhs', opts)
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('nvim_ui_attach()', function()
|
||||
end)
|
||||
|
||||
it('validation', function()
|
||||
eq('No such UI option: foo', pcall_err(api.nvim_ui_attach, 80, 24, { foo = { 'foo' } }))
|
||||
eq("Invalid UI option: 'foo'", pcall_err(api.nvim_ui_attach, 80, 24, { foo = { 'foo' } }))
|
||||
|
||||
eq(
|
||||
"Invalid 'ext_linegrid': expected Boolean, got Array",
|
||||
|
||||
@@ -729,7 +729,7 @@ describe('API', function()
|
||||
pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', { 1, 2 })
|
||||
)
|
||||
eq(
|
||||
'dict argument type must be String or Dict',
|
||||
'Invalid dict argument: expected String or Dict',
|
||||
pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 })
|
||||
)
|
||||
eq(
|
||||
@@ -738,7 +738,7 @@ describe('API', function()
|
||||
)
|
||||
eq('dict not found', pcall_err(request, 'nvim_call_dict_function', '42', 'f', { 1, 2 }))
|
||||
eq(
|
||||
'Invalid (empty) function name',
|
||||
'Invalid function name: (empty)',
|
||||
pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", '', { 1, 2 })
|
||||
)
|
||||
end)
|
||||
@@ -3791,7 +3791,7 @@ describe('API', function()
|
||||
'Invalid chunk: expected Array with 1 or 2 Strings',
|
||||
pcall_err(api.nvim_echo, { { '', '', '' } }, 1, {})
|
||||
)
|
||||
eq('Invalid hl_group: text highlight', pcall_err(api.nvim_echo, { { '', false } }, 1, {}))
|
||||
eq("Invalid 'hl_group': 'text highlight'", pcall_err(api.nvim_echo, { { '', false } }, 1, {}))
|
||||
end)
|
||||
|
||||
it('should clear cmdline message before echo', function()
|
||||
|
||||
@@ -2163,7 +2163,7 @@ describe('API/win', function()
|
||||
|
||||
it('no memory leak with valid title and invalid footer', function()
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_open_win, 0, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
@@ -2179,7 +2179,7 @@ describe('API/win', function()
|
||||
|
||||
it('no memory leak with invalid title and valid footer', function()
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_open_win, 0, false, {
|
||||
relative = 'editor',
|
||||
row = 10,
|
||||
@@ -2523,11 +2523,11 @@ describe('API/win', function()
|
||||
eq('below', config.split)
|
||||
|
||||
eq(
|
||||
"non-float with 'win' requires at least 'split' or 'vertical'",
|
||||
"Required: non-float with 'win' requires 'split' or 'vertical'",
|
||||
pcall_err(api.nvim_win_set_config, 0, { win = 0 })
|
||||
)
|
||||
eq(
|
||||
"non-float with 'win' requires at least 'split' or 'vertical'",
|
||||
"Required: non-float with 'win' requires 'split' or 'vertical'",
|
||||
pcall_err(api.nvim_win_set_config, 0, { win = 0, relative = '' })
|
||||
)
|
||||
|
||||
@@ -3310,7 +3310,7 @@ describe('API/win', function()
|
||||
eq(true, pcall(api.nvim_win_set_config, win, cfg))
|
||||
cfg.noautocmd = false
|
||||
eq(
|
||||
"'noautocmd' cannot be changed with existing windows",
|
||||
"'noautocmd' cannot be changed on existing window",
|
||||
pcall_err(api.nvim_win_set_config, win, cfg)
|
||||
)
|
||||
end)
|
||||
@@ -3596,13 +3596,13 @@ describe('API/win', function()
|
||||
border = 'single',
|
||||
})
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_win_set_config, win, { title = 0 })
|
||||
)
|
||||
command('redraw!')
|
||||
assert_alive()
|
||||
eq(
|
||||
'title/footer cannot be an empty array',
|
||||
"Invalid 'title/footer': expected non-empty Array",
|
||||
pcall_err(api.nvim_win_set_config, win, { title = {} })
|
||||
)
|
||||
command('redraw!')
|
||||
@@ -3620,13 +3620,13 @@ describe('API/win', function()
|
||||
border = 'single',
|
||||
})
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_win_set_config, win, { footer = 0 })
|
||||
)
|
||||
command('redraw!')
|
||||
assert_alive()
|
||||
eq(
|
||||
'title/footer cannot be an empty array',
|
||||
"Invalid 'title/footer': expected non-empty Array",
|
||||
pcall_err(api.nvim_win_set_config, win, { footer = {} })
|
||||
)
|
||||
command('redraw!')
|
||||
@@ -3651,7 +3651,7 @@ describe('API/win', function()
|
||||
|
||||
it('with valid title and invalid footer', function()
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_win_set_config, win, {
|
||||
title = { { 'NEW_TITLE' } },
|
||||
footer = 0,
|
||||
@@ -3664,7 +3664,7 @@ describe('API/win', function()
|
||||
|
||||
it('with invalid title and valid footer', function()
|
||||
eq(
|
||||
'title/footer must be string or array',
|
||||
"Invalid 'title/footer': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_win_set_config, win, {
|
||||
title = 0,
|
||||
footer = { { 'NEW_FOOTER' } },
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('luaeval(vim.api.…)', function()
|
||||
|
||||
it('transforms API error from nvim_win_set_cursor into lua error', function()
|
||||
eq(
|
||||
{ false, 'Argument "pos" must be a [row, col] array' },
|
||||
{ false, "Invalid 'pos': expected [row, col] array" },
|
||||
fn.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}')
|
||||
)
|
||||
-- Used to produce a memory leak due to a bug in nvim_win_set_cursor
|
||||
@@ -58,7 +58,7 @@ describe('luaeval(vim.api.…)', function()
|
||||
'transforms API error from nvim_win_set_cursor + same array as in first test into lua error',
|
||||
function()
|
||||
eq(
|
||||
{ false, 'Argument "pos" must be a [row, col] array' },
|
||||
{ false, "Invalid 'pos': expected [row, col] array" },
|
||||
fn.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}')
|
||||
)
|
||||
end
|
||||
|
||||
@@ -2465,7 +2465,7 @@ describe('extmark decorations', function()
|
||||
]])
|
||||
|
||||
eq(
|
||||
'Invalid hl_group: hl_group item',
|
||||
"Invalid 'hl_group': 'hl_group item'",
|
||||
pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_row = 1, hl_group = { 'Group1', 'Group2', { 'fail' } }, hl_eol = true })
|
||||
)
|
||||
end)
|
||||
|
||||
@@ -44,6 +44,169 @@ describe('float window', function()
|
||||
eq(1000, fn.win_getid())
|
||||
end)
|
||||
|
||||
it('validation', 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("Required: 'relative' or 'external' when creating a float", pcall_err(api.nvim_open_win, buf, false, { win = 0 }))
|
||||
eq(
|
||||
"Conflict: 'vertical' not allowed with floating windows",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, vertical = true })
|
||||
)
|
||||
eq(
|
||||
"Conflict: 'split' not allowed with floating windows",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, split = 'left' })
|
||||
)
|
||||
eq(
|
||||
"Conflict: 'relative' not allowed with 'external'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, external = true })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'relative': 'shell'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'shell', row = 0, col = 0 })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'anchor': 'bottom'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, anchor = 'bottom' })
|
||||
)
|
||||
eq(
|
||||
"Required: 'relative' requires 'row'/'col' or 'bufpos'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor' })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'width': expected positive Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = -1, height = 2, relative = 'editor', row = 0, col = 0 })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'height': expected positive Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = -1, relative = 'editor', row = 0, col = 0 })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'height': expected positive Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 0, relative = 'editor', row = 0, col = 0 })
|
||||
)
|
||||
eq("Required: 'width'", pcall_err(api.nvim_open_win, buf, false, { relative = 'editor', row = 0, col = 0 }))
|
||||
eq("Required: 'height'", pcall_err(api.nvim_open_win, buf, false, { relative = 'editor', row = 0, col = 0, width = 2 }))
|
||||
|
||||
eq("Invalid 'split': 'up'", pcall_err(api.nvim_open_win, buf, false, { split = 'up' }))
|
||||
eq(
|
||||
"Invalid 'bufpos': expected [row, col] array",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, bufpos = { 0 } })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'zindex': expected positive Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, zindex = 0 })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'zindex': expected positive Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, zindex = -1 })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'style': 'bogus'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, style = 'bogus' })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': 'bogus'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = 'bogus' })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected 1, 2, 4, or 8 chars",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { '', '', '' } })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected 1 or 2-item Array",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { { 'a', 'b', 'c' } } }
|
||||
)
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected Array of Strings",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { { 1 } } })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected String or Array, got Integer",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { 42 } })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected only one-cell chars",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { 'aa' } })
|
||||
)
|
||||
eq(
|
||||
"Invalid 'border': expected corner char between edge chars",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = { '', '-', '', '|', '', '-', '', '|' } }
|
||||
)
|
||||
)
|
||||
|
||||
-- title_pos/footer_pos validation
|
||||
eq(
|
||||
"Invalid 'title_pos': 'bogus'",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = 'single', title = 'T', title_pos = 'bogus' }
|
||||
)
|
||||
)
|
||||
eq(
|
||||
"Invalid 'footer_pos': 'bogus'",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ width = 20, height = 2, relative = 'editor', row = 0, col = 0, border = 'single', footer = 'F', footer_pos = 'bogus' }
|
||||
)
|
||||
)
|
||||
eq(
|
||||
"Required: 'footer' requires 'footer_pos'",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ relative = 'editor', width = 9, height = 2, row = 2, col = 5, border = 'single', footer_pos = 'left' }
|
||||
)
|
||||
)
|
||||
eq(
|
||||
"Required: 'title' requires 'title_pos'",
|
||||
pcall_err(
|
||||
api.nvim_open_win,
|
||||
buf,
|
||||
false,
|
||||
{ relative = 'editor', width = 9, height = 2, row = 2, col = 5, border = 'single', title_pos = 'left' }
|
||||
)
|
||||
)
|
||||
end)
|
||||
|
||||
it('validation: split window', function()
|
||||
local buf = api.nvim_create_buf(false, true)
|
||||
eq("Conflict: 'zindex' not allowed with non-float window", pcall_err(api.nvim_open_win, buf, false, { split = 'left', zindex = 100 }))
|
||||
eq("Conflict: 'title' not allowed with non-float window", pcall_err(api.nvim_open_win, buf, false, { split = 'left', title = 'T' }))
|
||||
eq("Conflict: 'footer' not allowed with non-float window", pcall_err(api.nvim_open_win, buf, false, { split = 'left', footer = 'F' }))
|
||||
eq(
|
||||
"Conflict: 'border' not allowed with non-float window",
|
||||
pcall_err(api.nvim_open_win, buf, false, { split = 'left', border = 'single' })
|
||||
)
|
||||
eq("Conflict: 'row' not allowed with non-float window", pcall_err(api.nvim_open_win, buf, true, { split = 'right', row = 10 }))
|
||||
eq("Conflict: 'col' not allowed with non-float window", pcall_err(api.nvim_open_win, buf, true, { split = 'right', col = 10 }))
|
||||
eq(
|
||||
"Conflict: 'bufpos' not allowed with non-float window",
|
||||
pcall_err(api.nvim_open_win, buf, true, { split = 'right', bufpos = { 0, 0 } })
|
||||
)
|
||||
|
||||
local winid = api.nvim_open_win(buf, true, { split = 'right' })
|
||||
eq("Conflict: 'row' not allowed with non-float window", pcall_err(api.nvim_win_set_config, winid, { split = 'right', row = 10 }))
|
||||
eq("Conflict: 'col' not allowed with non-float window", pcall_err(api.nvim_win_set_config, winid, { split = 'right', col = 10 }))
|
||||
eq(
|
||||
"Conflict: 'bufpos' not allowed with non-float window",
|
||||
pcall_err(api.nvim_win_set_config, winid, { split = 'right', bufpos = { 0, 0 } })
|
||||
)
|
||||
end)
|
||||
|
||||
it('win_execute() should work', function()
|
||||
local buf = api.nvim_create_buf(false, false)
|
||||
api.nvim_buf_set_lines(buf, 0, -1, true, { 'the floatwin', 'abc', 'def' })
|
||||
@@ -221,23 +384,12 @@ describe('float window', function()
|
||||
eq({ 14, 12 }, { pos[1], pos[2] })
|
||||
end)
|
||||
|
||||
it('error message when invalid field specified for split', function()
|
||||
local bufnr = api.nvim_create_buf(false, true)
|
||||
eq("non-float cannot have 'row'", pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', row = 10 }))
|
||||
eq("non-float cannot have 'col'", pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', col = 10 }))
|
||||
eq("non-float cannot have 'bufpos'", pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', bufpos = { 0, 0 } }))
|
||||
local winid = api.nvim_open_win(bufnr, true, { split = 'right' })
|
||||
eq("non-float cannot have 'row'", pcall_err(api.nvim_win_set_config, winid, { split = 'right', row = 10 }))
|
||||
eq("non-float cannot have 'col'", pcall_err(api.nvim_win_set_config, winid, { split = 'right', col = 10 }))
|
||||
eq("non-float cannot have 'bufpos'", pcall_err(api.nvim_win_set_config, winid, { split = 'right', bufpos = { 0, 0 } }))
|
||||
end)
|
||||
|
||||
it('error message when reconfig missing relative field', function()
|
||||
it('error when reconfig missing relative field', function()
|
||||
local bufnr = api.nvim_create_buf(false, true)
|
||||
local opts = { width = 10, height = 10, col = 5, row = 5, relative = 'editor', style = 'minimal' }
|
||||
local winid = api.nvim_open_win(bufnr, true, opts)
|
||||
eq(
|
||||
"Missing 'relative' field when reconfiguring floating window 1001",
|
||||
"Required: 'relative' when reconfiguring floating window 1001",
|
||||
pcall_err(api.nvim_win_set_config, winid, { width = 3, height = 3, row = 10, col = 10 })
|
||||
)
|
||||
end)
|
||||
@@ -2093,23 +2245,7 @@ describe('float window', function()
|
||||
end
|
||||
end)
|
||||
|
||||
it('validates title title_pos', function()
|
||||
local buf = api.nvim_create_buf(false, false)
|
||||
eq(
|
||||
'title_pos requires title to be set',
|
||||
pcall_err(api.nvim_open_win, buf, false, {
|
||||
relative = 'editor',
|
||||
width = 9,
|
||||
height = 2,
|
||||
row = 2,
|
||||
col = 5,
|
||||
border = 'single',
|
||||
title_pos = 'left',
|
||||
})
|
||||
)
|
||||
end)
|
||||
|
||||
it('validate title_pos in nvim_win_get_config', function()
|
||||
it('nvim_win_get_config.title_pos', function()
|
||||
local title_pos = exec_lua([[
|
||||
local bufnr = vim.api.nvim_create_buf(false, false)
|
||||
local opts = {
|
||||
@@ -2130,23 +2266,7 @@ describe('float window', function()
|
||||
eq('center', title_pos)
|
||||
end)
|
||||
|
||||
it('validates footer footer_pos', function()
|
||||
local buf = api.nvim_create_buf(false, false)
|
||||
eq(
|
||||
'footer_pos requires footer to be set',
|
||||
pcall_err(api.nvim_open_win, buf, false, {
|
||||
relative = 'editor',
|
||||
width = 9,
|
||||
height = 2,
|
||||
row = 2,
|
||||
col = 5,
|
||||
border = 'single',
|
||||
footer_pos = 'left',
|
||||
})
|
||||
)
|
||||
end)
|
||||
|
||||
it('validate footer_pos in nvim_win_get_config', function()
|
||||
it('nvim_win_get_config.footer_pos', function()
|
||||
local footer_pos = exec_lua([[
|
||||
local bufnr = vim.api.nvim_create_buf(false, false)
|
||||
local opts = {
|
||||
@@ -3779,56 +3899,15 @@ describe('float window', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
it('API has proper error messages', function()
|
||||
local buf = api.nvim_create_buf(false, false)
|
||||
eq("Invalid key: 'bork'", pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, bork = true }))
|
||||
eq("Must specify 'relative' or 'external' when creating a float", pcall_err(api.nvim_open_win, buf, false, { win = 0 }))
|
||||
eq(
|
||||
"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",
|
||||
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",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'shell', row = 0, col = 0 })
|
||||
)
|
||||
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' })
|
||||
)
|
||||
eq(
|
||||
"'relative' requires 'row'/'col' or 'bufpos'",
|
||||
pcall_err(api.nvim_open_win, buf, false, { width = 20, height = 2, relative = 'editor' })
|
||||
)
|
||||
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 })
|
||||
)
|
||||
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 })
|
||||
)
|
||||
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 })
|
||||
)
|
||||
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 }))
|
||||
|
||||
it('validation: multigrid', function()
|
||||
if multigrid then
|
||||
local buf = api.nvim_create_buf(false, false)
|
||||
eq(
|
||||
"external window cannot have 'win'",
|
||||
"Conflict: 'win' not allowed with external window",
|
||||
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 }))
|
||||
eq("Conflict: 'win' not allowed with external window", 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)
|
||||
|
||||
@@ -535,7 +535,7 @@ describe('ui/ext_popupmenu', function()
|
||||
it('an error occurs when ext_popupmenu is false', function()
|
||||
api.nvim_ui_pum_set_height(1)
|
||||
screen:set_option('ext_popupmenu', false)
|
||||
eq('It must support the ext_popupmenu option', pcall_err(api.nvim_ui_pum_set_height, 1))
|
||||
eq('UI must support the ext_popupmenu option', pcall_err(api.nvim_ui_pum_set_height, 1))
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user