aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/autocmd.c10
-rw-r--r--src/nvim/api/buffer.c28
-rw-r--r--src/nvim/api/command.c40
-rw-r--r--src/nvim/api/deprecated.c12
-rw-r--r--src/nvim/api/extmark.c191
-rw-r--r--src/nvim/api/extmark.h15
-rw-r--r--src/nvim/api/keysets_defs.h53
-rw-r--r--src/nvim/api/options.c23
-rw-r--r--src/nvim/api/private/converter.c43
-rw-r--r--src/nvim/api/private/defs.h24
-rw-r--r--src/nvim/api/private/helpers.c86
-rw-r--r--src/nvim/api/private/helpers.h10
-rw-r--r--src/nvim/api/private/validate.c2
-rw-r--r--src/nvim/api/private/validate.h8
-rw-r--r--src/nvim/api/ui.c52
-rw-r--r--src/nvim/api/vim.c233
-rw-r--r--src/nvim/api/vimscript.c48
-rw-r--r--src/nvim/api/win_config.c101
-rw-r--r--src/nvim/api/window.c8
19 files changed, 537 insertions, 450 deletions
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index ca8367b7ce..22932fd1a2 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -67,7 +67,7 @@ static int64_t next_autocmd_id = 1;
/// NOTE: When multiple patterns or events are provided, it will find all the autocommands that
/// match any combination of them.
///
-/// @param opts Dictionary with at least one of the following:
+/// @param opts Dict with at least one of the following:
/// - group (string|integer): the autocommand group name or id to match against.
/// - event (string|array): event or events to match against |autocmd-events|.
/// - pattern (string|array): pattern or patterns to match against |autocmd-pattern|.
@@ -270,7 +270,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
}
}
- Dictionary autocmd_info = arena_dict(arena, 11);
+ Dict autocmd_info = arena_dict(arena, 11);
if (ap->group != AUGROUP_DEFAULT) {
PUT_C(autocmd_info, "group", INTEGER_OBJ(ap->group));
@@ -334,7 +334,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
// PUT_C(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid));
// PUT_C(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum));
- kvi_push(autocmd_list, DICTIONARY_OBJ(autocmd_info));
+ kvi_push(autocmd_list, DICT_OBJ(autocmd_info));
}
}
@@ -621,7 +621,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Arena *arena, Error *err)
/// ```
///
/// @param name String: The name of the group
-/// @param opts Dictionary Parameters
+/// @param opts Dict Parameters
/// - clear (bool) optional: defaults to true. Clear existing
/// commands if the group already exists |autocmd-groups|.
/// @return Integer id of the created group.
@@ -686,7 +686,7 @@ void nvim_del_augroup_by_name(String name, Error *err)
/// Execute all autocommands for {event} that match the corresponding
/// {opts} |autocmd-execute|.
/// @param event (String|Array) The event or events to execute
-/// @param opts Dictionary of autocommand options:
+/// @param opts Dict of autocommand options:
/// - group (string|integer) optional: the autocommand group name or
/// id to match against. |autocmd-groups|.
/// - pattern (string|array) optional: defaults to "*" |autocmd-pattern|. Cannot be used
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 7e64808709..9480292d9a 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -462,12 +462,8 @@ end:
/// = row` and `start_col = end_col = col`. To delete the text in a range, use
/// `replacement = {}`.
///
-/// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines.
-///
-/// Prefer |nvim_put()| if you want to insert text at the cursor position.
-///
-/// @see |nvim_buf_set_lines()|
-/// @see |nvim_put()|
+/// @note Prefer |nvim_buf_set_lines()| (for performance) to add or delete entire lines.
+/// @note Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace) text at cursor.
///
/// @param channel_id
/// @param buffer Buffer handle, or 0 for current buffer
@@ -866,7 +862,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
/// @param[out] err Error details, if any
/// @returns Array of |maparg()|-like dictionaries describing mappings.
/// The "buffer" key holds the associated buffer handle.
-ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Arena *arena, Error *err)
+ArrayOf(Dict) nvim_buf_get_keymap(Buffer buffer, String mode, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1183,12 +1179,12 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Arena *arena,
return rv;
}
-/// call a function with buffer as temporary current buffer
+/// Call a function with buffer as temporary current buffer.
///
/// This temporarily switches current buffer to "buffer".
-/// If the current window already shows "buffer", the window is not switched
+/// If the current window already shows "buffer", the window is not switched.
/// If a window inside the current tabpage (including a float) already shows the
-/// buffer One of these windows will be set as current window temporarily.
+/// buffer, then one of these windows will be set as current window temporarily.
/// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used.
///
@@ -1221,14 +1217,14 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
}
/// @nodoc
-Dictionary nvim__buf_stats(Buffer buffer, Arena *arena, Error *err)
+Dict nvim__buf_stats(Buffer buffer, Arena *arena, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
- Dictionary rv = arena_dict(arena, 7);
+ Dict rv = arena_dict(arena, 7);
// Number of times the cached line was flushed.
// This should generally not increase while editing the same
// line in the same mode.
@@ -1375,7 +1371,7 @@ static inline void init_line_array(lua_State *lstate, Array *a, size_t size, Are
/// @param s String to push
/// @param len Size of string
/// @param idx 0-based index to place s (only used for Lua)
-/// @param replace_nl Replace newlines ('\n') with null ('\0')
+/// @param replace_nl Replace newlines ('\n') with null (NUL)
static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len, int idx,
bool replace_nl, Arena *arena)
{
@@ -1384,7 +1380,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
if (s && replace_nl && strchr(s, '\n')) {
// TODO(bfredl): could manage scratch space in the arena, for the NUL case
char *tmp = xmemdupz(s, len);
- strchrsub(tmp, '\n', '\0');
+ strchrsub(tmp, '\n', NUL);
lua_pushlstring(lstate, tmp, len);
xfree(tmp);
} else {
@@ -1397,7 +1393,7 @@ static void push_linestr(lua_State *lstate, Array *a, const char *s, size_t len,
str = CBUF_TO_ARENA_STR(arena, s, len);
if (replace_nl) {
// Vim represents NULs as NLs, but this may confuse clients.
- strchrsub(str.data, '\n', '\0');
+ strchrsub(str.data, '\n', NUL);
}
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 779e216c74..ab57d5c009 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -46,7 +46,7 @@
/// @param str Command line string to parse. Cannot contain "\n".
/// @param opts Optional parameters. Reserved for future use.
/// @param[out] err Error details, if any.
-/// @return Dictionary containing command information, with these keys:
+/// @return Dict containing command information, with these keys:
/// - cmd: (string) Command name.
/// - range: (array) (optional) Command range ([<line1>] [<line2>]).
/// Omitted if command doesn't accept a range.
@@ -63,13 +63,13 @@
/// - nargs: (string) Value of |:command-nargs|.
/// - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|.
/// Empty if there isn't a next command.
-/// - magic: (dictionary) Which characters have special meaning in the command arguments.
+/// - magic: (dict) Which characters have special meaning in the command arguments.
/// - file: (boolean) The command expands filenames. Which means characters such as "%",
/// "#" and wildcards are expanded.
/// - bar: (boolean) The "|" character is treated as a command separator and the double
/// quote character (") is treated as the start of a comment.
-/// - mods: (dictionary) |:command-modifiers|.
-/// - filter: (dictionary) |:filter|.
+/// - mods: (dict) |:command-modifiers|.
+/// - filter: (dict) |:filter|.
/// - pattern: (string) Filter pattern. Empty string if there is no filter.
/// - force: (boolean) Whether filter is inverted or not.
/// - silent: (boolean) |:silent|.
@@ -193,7 +193,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
} else {
nargs[0] = '0';
}
- nargs[1] = '\0';
+ nargs[1] = NUL;
PUT_KEY(result, cmd, nargs, CSTR_TO_ARENA_OBJ(arena, nargs));
char *addr;
@@ -230,12 +230,12 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
PUT_KEY(result, cmd, nextcmd, CSTR_AS_OBJ(ea.nextcmd));
// TODO(bfredl): nested keydict would be nice..
- Dictionary mods = arena_dict(arena, 20);
+ Dict mods = arena_dict(arena, 20);
- Dictionary filter = arena_dict(arena, 2);
+ Dict filter = arena_dict(arena, 2);
PUT_C(filter, "pattern", CSTR_TO_ARENA_OBJ(arena, cmdinfo.cmdmod.cmod_filter_pat));
PUT_C(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force));
- PUT_C(mods, "filter", DICTIONARY_OBJ(filter));
+ PUT_C(mods, "filter", DICT_OBJ(filter));
PUT_C(mods, "silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SILENT));
PUT_C(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_ERRSILENT));
@@ -272,7 +272,7 @@ Dict(cmd) nvim_parse_cmd(String str, Dict(empty) *opts, Arena *arena, Error *err
PUT_KEY(result, cmd, mods, mods);
- Dictionary magic = arena_dict(arena, 2);
+ Dict magic = arena_dict(arena, 2);
PUT_C(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file));
PUT_C(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar));
PUT_KEY(result, cmd, magic, magic);
@@ -284,7 +284,7 @@ end:
/// Executes an Ex command.
///
-/// Unlike |nvim_command()| this command takes a structured Dictionary instead of a String. This
+/// Unlike |nvim_command()| this command takes a structured Dict instead of a String. This
/// allows for easier construction and manipulation of an Ex command. This also allows for things
/// such as having spaces inside a command argument, expanding filenames in a command that otherwise
/// doesn't expand filenames, etc. Command arguments may also be Number, Boolean or String.
@@ -298,7 +298,7 @@ end:
/// @see |nvim_exec2()|
/// @see |nvim_command()|
///
-/// @param cmd Command to execute. Must be a Dictionary that can contain the same values as
+/// @param cmd Command to execute. Must be a Dict that can contain the same values as
/// the return value of |nvim_parse_cmd()| except "addr", "nargs" and "nextcmd"
/// which are ignored if provided. All values except for "cmd" are optional.
/// @param opts Optional parameters.
@@ -391,7 +391,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
case kObjectTypeBoolean:
data_str = arena_alloc(arena, 2, false);
data_str[0] = elem.data.boolean ? '1' : '0';
- data_str[1] = '\0';
+ data_str[1] = NUL;
ADD_C(args, CSTR_AS_OBJ(data_str));
break;
case kObjectTypeBuffer:
@@ -515,7 +515,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
if (HAS_KEY(cmd, cmd, magic)) {
Dict(cmd_magic) magic[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(magic, KeyDict_cmd_magic_get_field, cmd->magic, err)) {
+ if (!api_dict_to_keydict(magic, DictHash(cmd_magic), cmd->magic, err)) {
goto end;
}
@@ -533,14 +533,14 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
if (HAS_KEY(cmd, cmd, mods)) {
Dict(cmd_mods) mods[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(mods, KeyDict_cmd_mods_get_field, cmd->mods, err)) {
+ if (!api_dict_to_keydict(mods, DictHash(cmd_mods), cmd->mods, err)) {
goto end;
}
if (HAS_KEY(mods, cmd_mods, filter)) {
Dict(cmd_mods_filter) filter[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field,
+ if (!api_dict_to_keydict(&filter, DictHash(cmd_mods_filter),
mods->filter, err)) {
goto end;
}
@@ -1166,7 +1166,7 @@ err:
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
-Dictionary nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err)
+Dict nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
return nvim_buf_get_commands(-1, opts, arena, err);
@@ -1179,25 +1179,25 @@ Dictionary nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err)
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
-Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Arena *arena, Error *err)
+Dict nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
bool global = (buffer == -1);
if (ERROR_SET(err)) {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
if (global) {
if (opts->builtin) {
api_set_error(err, kErrorTypeValidation, "builtin=true not implemented");
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
return commands_array(NULL, arena);
}
buf_T *buf = find_buffer_by_handle(buffer, err);
if (opts->builtin || !buf) {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
return commands_array(buf, arena);
}
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index af3bfe2c03..6376011106 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -170,7 +170,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
DecorInline decor = { .ext = true, .data.ext.vt = vt, .data.ext.sh_idx = DECOR_ID_INVALID };
extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, 0, true,
- false, false, false, false, NULL);
+ false, false, false, NULL);
return src_id;
}
@@ -183,11 +183,11 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_name
-Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
+Dict nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
FUNC_API_DEPRECATED_SINCE(9)
{
- Dictionary dic = ARRAY_DICT_INIT;
+ Dict dic = ARRAY_DICT_INIT;
VALIDATE_INT((syn_get_final_id((int)hl_id) != 0), "highlight id", hl_id, {
return dic;
});
@@ -204,11 +204,11 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *er
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_id
-Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
+Dict nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
FUNC_API_DEPRECATED_SINCE(9)
{
- Dictionary result = ARRAY_DICT_INIT;
+ Dict result = ARRAY_DICT_INIT;
int id = syn_name2id(name.data);
VALIDATE_S((id != 0), "highlight name", name.data, {
@@ -515,7 +515,7 @@ static int64_t convert_index(int64_t index)
/// @param name Option name
/// @param[out] err Error details, if any
/// @return Option Information
-Dictionary nvim_get_option_info(String name, Arena *arena, Error *err)
+Dict nvim_get_option_info(String name, Arena *arena, Error *err)
FUNC_API_SINCE(7)
FUNC_API_DEPRECATED_SINCE(11)
{
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 85cce45560..7786c30624 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -18,6 +18,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
+#include "nvim/globals.h"
#include "nvim/grid.h"
#include "nvim/highlight_group.h"
#include "nvim/map_defs.h"
@@ -41,6 +42,7 @@ void api_extmark_free_all_mem(void)
xfree(name.data);
})
map_destroy(String, &namespace_ids);
+ set_destroy(uint32_t, &namespace_localscope);
}
/// Creates a new namespace or gets an existing one. [namespace]()
@@ -72,10 +74,10 @@ Integer nvim_create_namespace(String name)
/// Gets existing, non-anonymous |namespace|s.
///
/// @return dict that maps from names to namespace ids.
-Dictionary nvim_get_namespaces(Arena *arena)
+Dict nvim_get_namespaces(Arena *arena)
FUNC_API_SINCE(5)
{
- Dictionary retval = arena_dict(arena, map_size(&namespace_ids));
+ Dict retval = arena_dict(arena, map_size(&namespace_ids));
String name;
handle_T id;
@@ -156,7 +158,7 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
if (add_dict) {
// TODO(bfredl): coding the size like this is a bit fragile.
// We want ArrayOf(Dict(set_extmark)) as the return type..
- Dictionary dict = arena_dict(arena, ARRAY_SIZE(set_extmark_table));
+ Dict dict = arena_dict(arena, ARRAY_SIZE(set_extmark_table));
PUT_C(dict, "ns_id", INTEGER_OBJ((Integer)start.ns));
@@ -179,13 +181,9 @@ static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_na
PUT_C(dict, "invalid", BOOLEAN_OBJ(true));
}
- if (mt_scoped(start)) {
- PUT_C(dict, "scoped", BOOLEAN_OBJ(true));
- }
-
decor_to_dict_legacy(&dict, mt_decor(start), hl_name, arena);
- ADD_C(rv, DICTIONARY_OBJ(dict));
+ ADD_C(rv, DICT_OBJ(dict));
}
return rv;
@@ -489,8 +487,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// used together with virt_text.
/// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control
/// sequence is used to generate a clickable hyperlink to this URL.
-/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See
-/// |nvim__win_add_ns()|
///
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
@@ -575,7 +571,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
String c = opts->conceal;
if (c.size > 0) {
int ch;
- hl.conceal_char = utfc_ptr2schar_len(c.data, (int)c.size, &ch);
+ hl.conceal_char = utfc_ptr2schar(c.data, &ch);
if (!hl.conceal_char || !vim_isprintc(ch)) {
api_set_error(err, kErrorTypeValidation, "conceal char has to be printable");
goto error;
@@ -691,6 +687,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
if (HAS_KEY(opts, set_extmark, url)) {
url = string_to_cstr(opts->url);
+ has_hl = true;
}
if (opts->ui_watched) {
@@ -749,11 +746,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
- if (opts->scoped) {
- api_set_error(err, kErrorTypeException, "not yet implemented");
- goto error;
- }
-
int r = (int)line;
int c = (int)col;
if (line2 == -1) {
@@ -767,13 +759,9 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
if (kv_size(virt_lines.data.virt_lines)) {
decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true);
}
- if (url != NULL) {
- DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT;
- sh.url = url;
- decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0);
- }
if (has_hl) {
DecorSignHighlight sh = decor_sh_from_inline(hl);
+ sh.url = url;
decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id);
}
} else {
@@ -797,12 +785,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
uint32_t decor_indexed = DECOR_ID_INVALID;
- if (url != NULL) {
- DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT;
- sh.url = url;
- sh.next = decor_indexed;
- decor_indexed = decor_put_sh(sh);
- }
+
if (sign.flags & kSHIsSign) {
sign.next = decor_indexed;
decor_indexed = decor_put_sh(sign);
@@ -815,9 +798,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
DecorInline decor = DECOR_INLINE_INIT;
- if (decor_alloc || decor_indexed != DECOR_ID_INVALID || schar_high(hl.conceal_char)) {
+ if (decor_alloc || decor_indexed != DECOR_ID_INVALID || url != NULL
+ || schar_high(hl.conceal_char)) {
if (has_hl) {
DecorSignHighlight sh = decor_sh_from_inline(hl);
+ sh.url = url;
sh.next = decor_indexed;
decor_indexed = decor_put_sh(sh);
}
@@ -834,7 +819,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
extmark_set(buf, (uint32_t)ns_id, &id, (int)line, (colnr_T)col, line2, col2,
decor, decor_flags, right_gravity, opts->end_right_gravity,
!GET_BOOL_OR_TRUE(opts, set_extmark, undo_restore),
- opts->invalidate, opts->scoped, err);
+ opts->invalidate, err);
if (ERROR_SET(err)) {
decor_free(decor);
return 0;
@@ -960,7 +945,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In
decor.data.hl.hl_id = hl_id;
extmark_set(buf, ns, NULL, (int)line, (colnr_T)col_start, end_line, (colnr_T)col_end,
- decor, MT_FLAG_DECOR_HL, true, false, false, false, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, false, false, NULL);
return ns_id;
}
@@ -1011,7 +996,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// Note: this function should not be called often. Rather, the callbacks
/// themselves can be used to throttle unneeded callbacks. the `on_start`
/// callback can return `false` to disable the provider until the next redraw.
-/// Similarly, return `false` in `on_win` will skip the `on_lines` calls
+/// Similarly, return `false` in `on_win` will skip the `on_line` calls
/// for that window (but any extmarks set in `on_win` will still be used).
/// A plugin managing multiple sources of decoration should ideally only set
/// one provider, and merge the sources internally. You can use multiple `ns_id`
@@ -1020,10 +1005,10 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// Note: doing anything other than setting extmarks is considered experimental.
/// Doing things like changing options are not explicitly forbidden, but is
/// likely to have unexpected consequences (such as 100% CPU consumption).
-/// doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious
+/// Doing `vim.rpcnotify` should be OK, but `vim.rpcrequest` is quite dubious
/// for the moment.
///
-/// Note: It is not allowed to remove or update extmarks in 'on_line' callbacks.
+/// Note: It is not allowed to remove or update extmarks in `on_line` callbacks.
///
/// @param ns_id Namespace id from |nvim_create_namespace()|
/// @param opts Table of callbacks:
@@ -1038,7 +1023,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// ```
/// - on_win: called when starting to redraw a specific window.
/// ```
-/// ["win", winid, bufnr, topline, botline]
+/// ["win", winid, bufnr, toprow, botrow]
/// ```
/// - on_line: called for each buffer line being redrawn.
/// (The interaction with fold lines is subject to change)
@@ -1217,77 +1202,119 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error
/// EXPERIMENTAL: this API will change in the future.
///
-/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the
-/// given window.
+/// Set some properties for namespace
///
-/// @param window Window handle, or 0 for current window
/// @param ns_id Namespace
-/// @return true if the namespace was added, else false
-Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err)
+/// @param opts Optional parameters to set:
+/// - wins: a list of windows to be scoped in
+///
+void nvim__ns_set(Integer ns_id, Dict(ns_opts) *opts, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
- }
-
VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
- return false;
+ return;
});
- set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ bool set_scoped = true;
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
- }
+ if (HAS_KEY(opts, ns_opts, wins)) {
+ if (opts->wins.size == 0) {
+ set_scoped = false;
+ }
- return true;
-}
+ Set(ptr_t) windows = SET_INIT;
+ for (size_t i = 0; i < opts->wins.size; i++) {
+ Integer win = opts->wins.items[i].data.integer;
-/// EXPERIMENTAL: this API will change in the future.
-///
-/// Gets the namespace scopes for a given window.
-///
-/// @param window Window handle, or 0 for current window
-/// @return a list of namespaces ids
-ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err)
-{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return (Array)ARRAY_DICT_INIT;
+ win_T *wp = find_window_by_handle((Window)win, err);
+ if (!wp) {
+ return;
+ }
+
+ set_put(ptr_t, &windows, wp);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(ptr_t, &windows, wp) && !set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ set_put(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id) && !set_has(ptr_t, &windows, wp)) {
+ set_del(uint32_t, &wp->w_ns_set, (uint32_t)ns_id);
+
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
+
+ set_destroy(ptr_t, &windows);
}
- Array rv = arena_array(arena, set_size(&win->w_ns_set));
- uint32_t i;
- set_foreach(&win->w_ns_set, i, {
- ADD_C(rv, INTEGER_OBJ((Integer)(i)));
- });
+ if (set_scoped && !set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_put(uint32_t, &namespace_localscope, (uint32_t)ns_id);
- return rv;
+ // When a namespace becomes scoped, any window which contains
+ // elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ } else if (!set_scoped && set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ set_del(uint32_t, &namespace_localscope, (uint32_t)ns_id);
+
+ // When a namespace becomes unscoped, any window which does not
+ // contain elements associated with namespace needs to be redrawn
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (map_has(uint32_t, wp->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
+ changed_window_setting(wp);
+ }
+ }
+ }
}
/// EXPERIMENTAL: this API will change in the future.
///
-/// Unscopes a namespace (un-binds it from the given scope).
+/// Get the properties for namespace
///
-/// @param window Window handle, or 0 for current window
-/// @param ns_id the namespace to remove
-/// @return true if the namespace was removed, else false
-Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err)
+/// @param ns_id Namespace
+/// @return Map defining the namespace properties, see |nvim__ns_set()|
+Dict(ns_opts) nvim__ns_get(Integer ns_id, Arena *arena, Error *err)
{
- win_T *win = find_window_by_handle(window, err);
- if (!win) {
- return false;
+ Dict(ns_opts) opts = KEYDICT_INIT;
+
+ Array windows = ARRAY_DICT_INIT;
+
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ VALIDATE_INT(ns_initialized((uint32_t)ns_id), "ns_id", ns_id, {
+ return opts;
+ });
+
+ if (!set_has(uint32_t, &namespace_localscope, (uint32_t)ns_id)) {
+ return opts;
}
- if (!set_has(uint32_t, &win->w_ns_set, (uint32_t)ns_id)) {
- return false;
+ size_t count = 0;
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ count++;
+ }
}
- set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
+ windows = arena_array(arena, count);
- if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
- changed_window_setting(win);
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (set_has(uint32_t, &wp->w_ns_set, (uint32_t)ns_id)) {
+ ADD(windows, INTEGER_OBJ(wp->handle));
+ }
}
- return true;
+ PUT_KEY(opts, ns_opts, wins, windows);
+
+ return opts;
}
diff --git a/src/nvim/api/extmark.h b/src/nvim/api/extmark.h
index 124feaabfb..af2d51c95c 100644
--- a/src/nvim/api/extmark.h
+++ b/src/nvim/api/extmark.h
@@ -4,14 +4,29 @@
#include "nvim/api/keysets_defs.h" // IWYU pragma: keep
#include "nvim/api/private/defs.h" // IWYU pragma: keep
+#include "nvim/buffer_defs.h"
#include "nvim/decoration_defs.h" // IWYU pragma: keep
#include "nvim/macros_defs.h"
#include "nvim/map_defs.h"
#include "nvim/types_defs.h"
EXTERN Map(String, int) namespace_ids INIT( = MAP_INIT);
+/// Non-global namespaces. A locally-scoped namespace may be "orphaned" if all
+/// window(s) it was scoped to, are destroyed. Such orphans are tracked here to
+/// avoid being mistaken as "global scope".
+EXTERN Set(uint32_t) namespace_localscope INIT( = SET_INIT);
EXTERN handle_T next_namespace_id INIT( = 1);
+/// Returns true if the namespace is global or scoped in the given window.
+static inline bool ns_in_win(uint32_t ns_id, win_T *wp)
+{
+ if (!set_has(uint32_t, &namespace_localscope, ns_id)) {
+ return true;
+ }
+
+ return set_has(uint32_t, &wp->w_ns_set, ns_id);
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.h.generated.h"
#endif
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index 00d8aa8428..552612dd13 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -103,7 +103,7 @@ typedef struct {
Object nargs;
Object preview;
Object range;
- Boolean register_;
+ Boolean register_ DictKey(register);
} Dict(user_command);
typedef struct {
@@ -170,7 +170,7 @@ typedef struct {
Boolean reverse;
Boolean altfont;
Boolean nocombine;
- Boolean default_;
+ Boolean default_ DictKey(default);
Object cterm;
Object foreground;
Object fg;
@@ -275,8 +275,8 @@ typedef struct {
String reg;
Boolean bang;
Array args;
- Dictionary magic;
- Dictionary mods;
+ Dict magic;
+ Dict mods;
Object nargs;
Object addr;
Object nextcmd;
@@ -293,7 +293,7 @@ typedef struct {
Boolean silent;
Boolean emsg_silent;
Boolean unsilent;
- Dictionary filter;
+ Dict filter;
Boolean sandbox;
Boolean noautocmd;
Boolean browse;
@@ -387,3 +387,46 @@ typedef struct {
Window win;
Buffer buf;
} Dict(redraw);
+
+typedef struct {
+ OptionalKeys is_set__ns_opts_;
+ Array wins;
+} Dict(ns_opts);
+
+typedef struct {
+ OptionalKeys is_set___shada_search_pat_;
+ Boolean magic DictKey(sm);
+ Boolean smartcase DictKey(sc);
+ Boolean has_line_offset DictKey(sl);
+ Boolean place_cursor_at_end DictKey(se);
+ Boolean is_last_used DictKey(su);
+ Boolean is_substitute_pattern DictKey(ss);
+ Boolean highlighted DictKey(sh);
+ Boolean search_backward DictKey(sb);
+ Integer offset DictKey(so);
+ String pat DictKey(sp);
+} Dict(_shada_search_pat);
+
+typedef struct {
+ OptionalKeys is_set___shada_mark_;
+ Integer n;
+ Integer l;
+ Integer c;
+ String f;
+} Dict(_shada_mark);
+
+typedef struct {
+ OptionalKeys is_set___shada_register_;
+ StringArray rc;
+ Boolean ru;
+ Integer rt;
+ Integer n;
+ Integer rw;
+} Dict(_shada_register);
+
+typedef struct {
+ OptionalKeys is_set___shada_buflist_item_;
+ Integer l;
+ Integer c;
+ String f;
+} Dict(_shada_buflist_item);
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index d9bc0ccc92..1a0edd551e 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -54,6 +54,10 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
}
if (HAS_KEY_X(opts, buf)) {
+ VALIDATE(!(HAS_KEY_X(opts, scope) && *scope == OPT_GLOBAL), "%s",
+ "cannot use both global 'scope' and 'buf'", {
+ return FAIL;
+ });
*scope = OPT_LOCAL;
*req_scope = kOptReqBuf;
*from = find_buffer_by_handle(opts->buf, err);
@@ -68,11 +72,6 @@ static int validate_option_value_args(Dict(option) *opts, char *name, OptIndex *
return FAIL;
});
- VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s",
- "cannot use both 'scope' and 'buf'", {
- return FAIL;
- });
-
VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)),
"%s", "cannot use both 'buf' and 'win'", {
return FAIL;
@@ -257,13 +256,13 @@ void nvim_set_option_value(uint64_t channel_id, String name, Object value, Dict(
/// Gets the option information for all options.
///
-/// The dictionary has the full option names as keys and option metadata
-/// dictionaries as detailed at |nvim_get_option_info2()|.
+/// The dict has the full option names as keys and option metadata dicts as detailed at
+/// |nvim_get_option_info2()|.
///
/// @see |nvim_get_commands()|
///
-/// @return dictionary of all options
-Dictionary nvim_get_all_options_info(Arena *arena, Error *err)
+/// @return dict of all options
+Dict nvim_get_all_options_info(Arena *arena, Error *err)
FUNC_API_SINCE(7)
{
return get_all_vimoptions(arena);
@@ -271,7 +270,7 @@ Dictionary nvim_get_all_options_info(Arena *arena, Error *err)
/// Gets the option information for one option from arbitrary buffer or window
///
-/// Resulting dictionary has keys:
+/// Resulting dict has keys:
/// - name: Name of the option (like 'filetype')
/// - shortname: Shortened name of the option (like 'ft')
/// - type: type of option ("string", "number" or "boolean")
@@ -302,7 +301,7 @@ Dictionary nvim_get_all_options_info(Arena *arena, Error *err)
/// Implies {scope} is "local".
/// @param[out] err Error details, if any
/// @return Option Information
-Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error *err)
+Dict nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(11)
{
OptIndex opt_idx = 0;
@@ -311,7 +310,7 @@ Dictionary nvim_get_option_info2(String name, Dict(option) *opts, Arena *arena,
void *from = NULL;
if (!validate_option_value_args(opts, name.data, &opt_idx, &scope, &req_scope, &from, NULL,
err)) {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
buf_T *buf = (req_scope == kOptReqBuf) ? (buf_T *)from : curbuf;
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c
index a78d78c057..59e7373f68 100644
--- a/src/nvim/api/private/converter.c
+++ b/src/nvim/api/private/converter.c
@@ -7,7 +7,9 @@
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h"
+#include "nvim/eval/decode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
@@ -28,6 +30,7 @@ typedef struct {
#endif
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
+#define TYPVAL_ENCODE_CHECK_BEFORE
#define TYPVAL_ENCODE_CONV_NIL(tv) \
kvi_push(edata->stack, NIL)
@@ -91,8 +94,7 @@ static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t le
kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- kvi_push(edata->stack, \
- DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
+ kvi_push(edata->stack, DICT_OBJ(((Dict) { .capacity = 0, .size = 0 })))
static inline void typval_encode_list_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
@@ -134,7 +136,7 @@ static inline void typval_encode_list_end(EncodedData *const edata)
static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
- kvi_push(edata->stack, DICTIONARY_OBJ(arena_dict(edata->arena, len)));
+ kvi_push(edata->stack, DICT_OBJ(arena_dict(edata->arena, len)));
}
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
@@ -149,13 +151,13 @@ static inline void typval_encode_after_key(EncodedData *const edata)
{
Object key = kv_pop(edata->stack);
Object *const dict = &kv_last(edata->stack);
- assert(dict->type == kObjectTypeDictionary);
- assert(dict->data.dictionary.size < dict->data.dictionary.capacity);
+ assert(dict->type == kObjectTypeDict);
+ assert(dict->data.dict.size < dict->data.dict.capacity);
if (key.type == kObjectTypeString) {
- dict->data.dictionary.items[dict->data.dictionary.size].key
+ dict->data.dict.items[dict->data.dict.size].key
= key.data.string;
} else {
- dict->data.dictionary.items[dict->data.dictionary.size].key
+ dict->data.dict.items[dict->data.dict.size].key
= STATIC_CSTR_AS_STRING("__INVALID_KEY__");
}
}
@@ -168,9 +170,9 @@ static inline void typval_encode_between_dict_items(EncodedData *const edata)
{
Object val = kv_pop(edata->stack);
Object *const dict = &kv_last(edata->stack);
- assert(dict->type == kObjectTypeDictionary);
- assert(dict->data.dictionary.size < dict->data.dictionary.capacity);
- dict->data.dictionary.items[dict->data.dictionary.size++].value = val;
+ assert(dict->type == kObjectTypeDict);
+ assert(dict->data.dict.size < dict->data.dict.capacity);
+ dict->data.dict.items[dict->data.dict.size++].value = val;
}
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \
@@ -182,7 +184,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
typval_encode_between_dict_items(edata);
#ifndef NDEBUG
const Object *const dict = &kv_last(edata->stack);
- assert(dict->data.dictionary.size == dict->data.dictionary.capacity);
+ assert(dict->data.dict.size == dict->data.dict.capacity);
#endif
}
@@ -217,6 +219,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
#undef TYPVAL_ENCODE_CONV_LIST_START
#undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START
#undef TYPVAL_ENCODE_CONV_EMPTY_DICT
+#undef TYPVAL_ENCODE_CHECK_BEFORE
#undef TYPVAL_ENCODE_CONV_NIL
#undef TYPVAL_ENCODE_CONV_BOOL
#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
@@ -300,15 +303,11 @@ void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Erro
tv->vval.v_float = obj->data.floating;
break;
- case kObjectTypeString:
- tv->v_type = VAR_STRING;
- if (obj->data.string.data == NULL) {
- tv->vval.v_string = NULL;
- } else {
- tv->vval.v_string = xmemdupz(obj->data.string.data,
- obj->data.string.size);
- }
+ case kObjectTypeString: {
+ String s = obj->data.string;
+ *tv = decode_string(s.data, s.size, false, false);
break;
+ }
case kObjectTypeArray: {
list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size);
@@ -325,11 +324,11 @@ void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Erro
break;
}
- case kObjectTypeDictionary: {
+ case kObjectTypeDict: {
dict_T *const dict = tv_dict_alloc();
- for (uint32_t i = 0; i < obj->data.dictionary.size; i++) {
- KeyValuePair *item = &obj->data.dictionary.items[i];
+ for (uint32_t i = 0; i < obj->data.dict.size; i++) {
+ KeyValuePair *item = &obj->data.dict.items[i];
String key = item->key;
dictitem_T *const di = tv_dict_item_alloc(key.data);
object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err);
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index ca088d7a55..26d5ac09a8 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -5,7 +5,6 @@
#include <string.h>
#include "klib/kvec.h"
-#include "nvim/func_attr.h"
#include "nvim/types_defs.h"
#define ARRAY_DICT_INIT KV_INITIAL_VALUE
@@ -18,8 +17,11 @@
#ifdef INCLUDE_GENERATED_DECLARATIONS
# define ArrayOf(...) Array
-# define DictionaryOf(...) Dictionary
+# define DictOf(...) Dict
# define Dict(name) KeyDict_##name
+# define DictHash(name) KeyDict_##name##_get_field
+# define DictKey(name)
+# include "api/private/defs.h.inline.generated.h"
#endif
// Basic types
@@ -47,15 +49,13 @@ typedef enum {
/// Internal call from Lua code
#define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1)
-static inline bool is_internal_call(uint64_t channel_id)
- REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
-
/// Check whether call is internal
///
/// @param[in] channel_id Channel id.
///
/// @return true if channel_id refers to internal channel.
static inline bool is_internal_call(const uint64_t channel_id)
+ FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST
{
return !!(channel_id & INTERNAL_CALL_MASK);
}
@@ -88,7 +88,9 @@ typedef struct object Object;
typedef kvec_t(Object) Array;
typedef struct key_value_pair KeyValuePair;
-typedef kvec_t(KeyValuePair) Dictionary;
+typedef kvec_t(KeyValuePair) Dict;
+
+typedef kvec_t(String) StringArray;
typedef enum {
kObjectTypeNil = 0,
@@ -97,7 +99,7 @@ typedef enum {
kObjectTypeFloat,
kObjectTypeString,
kObjectTypeArray,
- kObjectTypeDictionary,
+ kObjectTypeDict,
kObjectTypeLuaRef,
// EXT types, cannot be split or reordered, see #EXT_OBJECT_TYPE_SHIFT
kObjectTypeBuffer,
@@ -105,6 +107,10 @@ typedef enum {
kObjectTypeTabpage,
} ObjectType;
+typedef enum {
+ kUnpackTypeStringArray = -1,
+} UnpackType;
+
/// Value by which objects represented as EXT type are shifted
///
/// Subtracted when packing, added when unpacking. Used to allow moving
@@ -121,7 +127,7 @@ struct object {
Float floating;
String string;
Array array;
- Dictionary dictionary;
+ Dict dict;
LuaRef luaref;
} data;
};
@@ -142,7 +148,7 @@ typedef struct {
typedef struct {
char *str;
size_t ptr_off;
- ObjectType type; // kObjectTypeNil == untyped
+ int type; // ObjectType or UnpackType. kObjectTypeNil == untyped
int opt_index;
bool is_hlgroup;
} KeySetLink;
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index a17e78cc31..e1fb4ed732 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1,6 +1,5 @@
#include <assert.h>
#include <limits.h>
-#include <msgpack/unpack.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
@@ -199,7 +198,7 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
api_set_error(err, kErrorTypeException, "Key is fixed: %s", key.data);
}
} else if (dict->dv_lock) {
- api_set_error(err, kErrorTypeException, "Dictionary is locked");
+ api_set_error(err, kErrorTypeException, "Dict is locked");
} else if (key.size == 0) {
api_set_error(err, kErrorTypeValidation, "Key name is empty");
} else if (key.size > INT_MAX) {
@@ -529,29 +528,19 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col
start_col = start_col < 0 ? line_length + start_col + 1 : start_col;
end_col = end_col < 0 ? line_length + end_col + 1 : end_col;
- if (start_col >= MAXCOL || end_col >= MAXCOL) {
- api_set_error(err, kErrorTypeValidation, "Column index is too high");
- return rv;
- }
+ start_col = MIN(MAX(0, start_col), line_length);
+ end_col = MIN(MAX(0, end_col), line_length);
if (start_col > end_col) {
- api_set_error(err, kErrorTypeValidation, "start_col must be less than end_col");
- return rv;
- }
-
- if (start_col >= line_length) {
+ api_set_error(err, kErrorTypeValidation, "start_col must be less than or equal to end_col");
return rv;
}
- return cstrn_as_string(&bufstr[start_col], (size_t)(end_col - start_col));
+ return cbuf_as_string(bufstr + start_col, (size_t)(end_col - start_col));
}
void api_free_string(String value)
{
- if (!value.data) {
- return;
- }
-
xfree(value.data);
}
@@ -562,9 +551,9 @@ Array arena_array(Arena *arena, size_t max_size)
return arr;
}
-Dictionary arena_dict(Arena *arena, size_t max_size)
+Dict arena_dict(Arena *arena, size_t max_size)
{
- Dictionary dict = ARRAY_DICT_INIT;
+ Dict dict = ARRAY_DICT_INIT;
kv_fixsize_arena(arena, dict, max_size);
return dict;
}
@@ -607,8 +596,8 @@ void api_free_object(Object value)
api_free_array(value.data.array);
break;
- case kObjectTypeDictionary:
- api_free_dictionary(value.data.dictionary);
+ case kObjectTypeDict:
+ api_free_dict(value.data.dict);
break;
case kObjectTypeLuaRef:
@@ -626,7 +615,7 @@ void api_free_array(Array value)
xfree(value.items);
}
-void api_free_dictionary(Dictionary value)
+void api_free_dict(Dict value)
{
for (size_t i = 0; i < value.size; i++) {
api_free_string(value.items[i].key);
@@ -659,7 +648,7 @@ Object api_metadata(void)
Arena arena = ARENA_EMPTY;
Error err = ERROR_INIT;
metadata = unpack((char *)packed_api_metadata, sizeof(packed_api_metadata), &arena, &err);
- if (ERROR_SET(&err) || metadata.type != kObjectTypeDictionary) {
+ if (ERROR_SET(&err) || metadata.type != kObjectTypeDict) {
abort();
}
mem_for_metadata = arena_finish(&arena);
@@ -695,9 +684,9 @@ Array copy_array(Array array, Arena *arena)
return rv;
}
-Dictionary copy_dictionary(Dictionary dict, Arena *arena)
+Dict copy_dict(Dict dict, Arena *arena)
{
- Dictionary rv = arena_dict(arena, dict.size);
+ Dict rv = arena_dict(arena, dict.size);
for (size_t i = 0; i < dict.size; i++) {
KeyValuePair item = dict.items[i];
PUT_C(rv, copy_string(item.key, arena).data, copy_object(item.value, arena));
@@ -724,8 +713,8 @@ Object copy_object(Object obj, Arena *arena)
case kObjectTypeArray:
return ARRAY_OBJ(copy_array(obj.data.array, arena));
- case kObjectTypeDictionary:
- return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary, arena));
+ case kObjectTypeDict:
+ return DICT_OBJ(copy_dict(obj.data.dict, arena));
case kObjectTypeLuaRef:
return LUAREF_OBJ(api_new_luaref(obj.data.luaref));
@@ -779,7 +768,8 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
String str = obj.data.string;
return str.size ? syn_check_group(str.data, str.size) : 0;
} else if (obj.type == kObjectTypeInteger) {
- return MAX((int)obj.data.integer, 0);
+ int id = (int)obj.data.integer;
+ return (1 <= id && id <= highlight_num_groups()) ? id : 0;
} else {
api_set_error(err, kErrorTypeValidation, "Invalid highlight: %s", what);
return 0;
@@ -801,7 +791,7 @@ char *api_typename(ObjectType t)
return "String";
case kObjectTypeArray:
return "Array";
- case kObjectTypeDictionary:
+ case kObjectTypeDict:
return "Dict";
case kObjectTypeLuaRef:
return "Function";
@@ -854,7 +844,7 @@ free_exit:
}
// see also nlua_pop_keydict for the lua specific implementation
-bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error *err)
+bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dict dict, Error *err)
{
for (size_t i = 0; i < dict.size; i++) {
String k = dict.items[i].key;
@@ -918,23 +908,25 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error
return false;
});
*(Array *)mem = value->data.array;
- } else if (field->type == kObjectTypeDictionary) {
- Dictionary *val = (Dictionary *)mem;
+ } else if (field->type == kObjectTypeDict) {
+ Dict *val = (Dict *)mem;
// allow empty array as empty dict for lua (directly or via lua-client RPC)
if (value->type == kObjectTypeArray && value->data.array.size == 0) {
- *val = (Dictionary)ARRAY_DICT_INIT;
- } else if (value->type == kObjectTypeDictionary) {
- *val = value->data.dictionary;
+ *val = (Dict)ARRAY_DICT_INIT;
+ } else if (value->type == kObjectTypeDict) {
+ *val = value->data.dict;
} else {
- api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ api_err_exp(err, field->str, api_typename((ObjectType)field->type),
+ api_typename(value->type));
return false;
}
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
- if (value->type == kObjectTypeInteger || value->type == field->type) {
+ if (value->type == kObjectTypeInteger || value->type == (ObjectType)field->type) {
*(handle_T *)mem = (handle_T)value->data.integer;
} else {
- api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ api_err_exp(err, field->str, api_typename((ObjectType)field->type),
+ api_typename(value->type));
return false;
}
} else if (field->type == kObjectTypeLuaRef) {
@@ -949,9 +941,9 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error
return true;
}
-Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, Arena *arena)
+Dict api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size, Arena *arena)
{
- Dictionary rv = arena_dict(arena, max_size);
+ Dict rv = arena_dict(arena, max_size);
for (size_t i = 0; table[i].str; i++) {
KeySetLink *field = &table[i];
bool is_set = true;
@@ -979,12 +971,12 @@ Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size,
val = STRING_OBJ(*(String *)mem);
} else if (field->type == kObjectTypeArray) {
val = ARRAY_OBJ(*(Array *)mem);
- } else if (field->type == kObjectTypeDictionary) {
- val = DICTIONARY_OBJ(*(Dictionary *)mem);
+ } else if (field->type == kObjectTypeDict) {
+ val = DICT_OBJ(*(Dict *)mem);
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
val.data.integer = *(handle_T *)mem;
- val.type = field->type;
+ val.type = (ObjectType)field->type;
} else if (field->type == kObjectTypeLuaRef) {
// do nothing
} else {
@@ -1010,8 +1002,8 @@ void api_luarefs_free_object(Object value)
api_luarefs_free_array(value.data.array);
break;
- case kObjectTypeDictionary:
- api_luarefs_free_dict(value.data.dictionary);
+ case kObjectTypeDict:
+ api_luarefs_free_dict(value.data.dict);
break;
default:
@@ -1027,8 +1019,8 @@ void api_luarefs_free_keydict(void *dict, KeySetLink *table)
api_luarefs_free_object(*(Object *)mem);
} else if (table[i].type == kObjectTypeLuaRef) {
api_free_luaref(*(LuaRef *)mem);
- } else if (table[i].type == kObjectTypeDictionary) {
- api_luarefs_free_dict(*(Dictionary *)mem);
+ } else if (table[i].type == kObjectTypeDict) {
+ api_luarefs_free_dict(*(Dict *)mem);
}
}
}
@@ -1040,7 +1032,7 @@ void api_luarefs_free_array(Array value)
}
}
-void api_luarefs_free_dict(Dictionary value)
+void api_luarefs_free_dict(Dict value)
{
for (size_t i = 0; i < value.size; i++) {
api_luarefs_free_object(value.items[i].value);
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 7eda8ffaf6..57932e067e 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -53,9 +53,9 @@
.type = kObjectTypeArray, \
.data.array = a })
-#define DICTIONARY_OBJ(d) ((Object) { \
- .type = kObjectTypeDictionary, \
- .data.dictionary = d })
+#define DICT_OBJ(d) ((Object) { \
+ .type = kObjectTypeDict, \
+ .data.dict = d })
#define LUAREF_OBJ(r) ((Object) { \
.type = kObjectTypeLuaRef, \
@@ -90,7 +90,7 @@
name.items = name##__items; \
#define MAXSIZE_TEMP_DICT(name, maxsize) \
- Dictionary name = ARRAY_DICT_INIT; \
+ Dict name = ARRAY_DICT_INIT; \
KeyValuePair name##__items[maxsize]; \
name.capacity = maxsize; \
name.items = name##__items; \
@@ -121,7 +121,7 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder;
#define api_init_tabpage
#define api_init_object = NIL
#define api_init_array = ARRAY_DICT_INIT
-#define api_init_dictionary = ARRAY_DICT_INIT
+#define api_init_dict = ARRAY_DICT_INIT
#define KEYDICT_INIT { 0 }
diff --git a/src/nvim/api/private/validate.c b/src/nvim/api/private/validate.c
index e198c671eb..9fd7d3bfa6 100644
--- a/src/nvim/api/private/validate.c
+++ b/src/nvim/api/private/validate.c
@@ -17,7 +17,7 @@ void api_err_invalid(Error *err, const char *name, const char *val_s, int64_t va
char *has_space = strchr(name, ' ');
// No value.
- if (val_s && val_s[0] == '\0') {
+ if (val_s && val_s[0] == NUL) {
api_set_error(err, errtype, has_space ? "Invalid %s" : "Invalid '%s'", name);
return;
}
diff --git a/src/nvim/api/private/validate.h b/src/nvim/api/private/validate.h
index 2c1d1a241d..67af8adea8 100644
--- a/src/nvim/api/private/validate.h
+++ b/src/nvim/api/private/validate.h
@@ -42,7 +42,7 @@
#define VALIDATE_T(name, expected_t, actual_t, code) \
do { \
- STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \
+ STATIC_ASSERT(expected_t != kObjectTypeDict, "use VALIDATE_T_DICT"); \
if (expected_t != actual_t) { \
api_err_exp(err, name, api_typename(expected_t), api_typename(actual_t)); \
code; \
@@ -52,7 +52,7 @@
/// Checks that `obj_` has type `expected_t`.
#define VALIDATE_T2(obj_, expected_t, code) \
do { \
- STATIC_ASSERT(expected_t != kObjectTypeDictionary, "use VALIDATE_T_DICT"); \
+ STATIC_ASSERT(expected_t != kObjectTypeDict, "use VALIDATE_T_DICT"); \
if ((obj_).type != expected_t) { \
api_err_exp(err, STR(obj_), api_typename(expected_t), api_typename((obj_).type)); \
code; \
@@ -62,11 +62,11 @@
/// Checks that `obj_` has Dict type. Also allows empty Array in a Lua context.
#define VALIDATE_T_DICT(name, obj_, code) \
do { \
- if ((obj_).type != kObjectTypeDictionary \
+ if ((obj_).type != kObjectTypeDict \
&& !(channel_id == LUA_INTERNAL_CALL \
&& (obj_).type == kObjectTypeArray \
&& (obj_).data.array.size == 0)) { \
- api_err_exp(err, name, api_typename(kObjectTypeDictionary), api_typename((obj_).type)); \
+ api_err_exp(err, name, api_typename(kObjectTypeDict), api_typename((obj_).type)); \
code; \
} \
} while (0)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index fdf25c75d7..b09a9ed253 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -1,6 +1,5 @@
#include <assert.h>
#include <inttypes.h>
-#include <msgpack/pack.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -94,15 +93,15 @@ void remote_ui_free_all_mem(void)
}
#endif
-/// Wait until ui has connected on stdio channel if only_stdio
-/// is true, otherwise any channel.
+/// Wait until UI has connected.
+///
+/// @param only_stdio UI is expected to connect on stdio.
void remote_ui_wait_for_attach(bool only_stdio)
{
if (only_stdio) {
Channel *channel = find_channel(CHAN_STDIO);
if (!channel) {
- // this function should only be called in --embed mode, stdio channel
- // can be assumed.
+ // `only_stdio` implies --embed mode, thus stdio channel can be assumed.
abort();
}
@@ -129,8 +128,7 @@ void remote_ui_wait_for_attach(bool only_stdio)
/// @param height Requested screen rows
/// @param options |ui-option| map
/// @param[out] err Error details, if any
-void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options,
- Error *err)
+void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dict options, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
if (map_has(uint64_t, &connected_uis, channel_id)) {
@@ -688,8 +686,8 @@ void remote_ui_hl_attr_define(RemoteUI *ui, Integer id, HlAttrs rgb_attrs, HlAtt
PUT_C(rgb, "url", CSTR_AS_OBJ(url));
}
- ADD_C(args, DICTIONARY_OBJ(rgb));
- ADD_C(args, DICTIONARY_OBJ(cterm));
+ ADD_C(args, DICT_OBJ(rgb));
+ ADD_C(args, DICT_OBJ(cterm));
if (ui->ui_ext[kUIHlState]) {
ADD_C(args, ARRAY_OBJ(info));
@@ -710,7 +708,7 @@ void remote_ui_highlight_set(RemoteUI *ui, int id)
MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE);
hlattrs2dict(&dict, NULL, syn_attr2entry(id), ui->rgb, false);
MAXSIZE_TEMP_ARRAY(args, 1);
- ADD_C(args, DICTIONARY_OBJ(dict));
+ ADD_C(args, DICT_OBJ(dict));
push_call(ui, "highlight_set", args);
}
@@ -778,16 +776,26 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
for (size_t i = 0; i < ncells; i++) {
repeat++;
if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) {
- if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1
+ if (
+ // Close to overflowing the redraw buffer. Finish this event, flush,
+ // and start a new "grid_line" event at the current position.
+ // For simplicity leave place for the final "clear" element as well,
+ // hence the factor of 2 in the check.
+ UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1
+ // Also if there is a lot of packed cells, pass them off to the UI to
+ // let it start processing them.
|| ui->ncells_pending >= 500) {
- // close to overflowing the redraw buffer. finish this event,
- // flush, and start a new "grid_line" event at the current position.
- // For simplicity leave place for the final "clear" element
- // as well, hence the factor of 2 in the check.
- // Also if there is a lot of packed cells, pass them of to the UI to
- // let it start processing them
+ // If the last chunk was all spaces, add an empty clearing chunk,
+ // so it's clear that the last chunk wasn't a clearing chunk.
+ if (was_space) {
+ nelem++;
+ ui->ncells_pending += 1;
+ mpack_array(buf, 3);
+ mpack_str_small(buf, S_LEN(" "));
+ mpack_uint(buf, (uint32_t)clearattr);
+ mpack_uint(buf, 0);
+ }
mpack_w2(&lenpos, nelem);
-
// We only ever set the wrap field on the final "grid_line" event for the line.
mpack_bool(buf, false);
ui_flush_buf(ui);
@@ -838,7 +846,7 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco
char sc_buf[MAX_SCHAR_SIZE];
schar_get(sc_buf, chunk[i]);
remote_ui_put(ui, sc_buf);
- if (utf_ambiguous_width(utf_ptr2char(sc_buf))) {
+ if (utf_ambiguous_width(sc_buf)) {
ui->client_col = -1; // force cursor update
}
}
@@ -911,11 +919,11 @@ static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena)
Array new_item = arena_array(arena, 2);
int attr = (int)item.items[0].data.integer;
if (attr) {
- Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
+ Dict rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false);
- ADD_C(new_item, DICTIONARY_OBJ(rgb_attrs));
+ ADD_C(new_item, DICT_OBJ(rgb_attrs));
} else {
- ADD_C(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD_C(new_item, DICT_OBJ((Dict)ARRAY_DICT_INIT));
}
ADD_C(new_item, item.items[1]);
ADD_C(new_contents, ARRAY_OBJ(new_item));
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index fc780e1248..8c88a19147 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -28,6 +28,8 @@
#include "nvim/cursor.h"
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
+#include "nvim/edit.h"
+#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
@@ -68,7 +70,7 @@
#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/os_defs.h"
-#include "nvim/os/process.h"
+#include "nvim/os/proc.h"
#include "nvim/popupmenu.h"
#include "nvim/pos_defs.h"
#include "nvim/runtime.h"
@@ -115,7 +117,7 @@ Integer nvim_get_hl_id_by_name(String name)
/// @param[out] err Error details, if any.
/// @return Highlight groups as a map from group name to a highlight definition map as in |nvim_set_hl()|,
/// or only a single highlight definition map if requested by name or id.
-Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err)
+Dict nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(11)
{
return ns_get_hl_defs((NS)ns_id, opts, arena, err);
@@ -313,7 +315,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
keys_esc = keys.data;
}
if (lowlevel) {
- input_enqueue_raw(cstr_as_string(keys_esc));
+ input_enqueue_raw(keys_esc, strlen(keys_esc));
} else {
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
@@ -342,9 +344,10 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
}
}
-/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level
-/// input buffer and the call is non-blocking (input is processed
-/// asynchronously by the eventloop).
+/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level input buffer and the call
+/// is non-blocking (input is processed asynchronously by the eventloop).
+///
+/// To input blocks of text, |nvim_paste()| is much faster and should be preferred.
///
/// On execution error: does not fail, but updates v:errmsg.
///
@@ -524,13 +527,13 @@ Object nvim_exec_lua(String code, Array args, Arena *arena, Error *err)
/// @param log_level The log level
/// @param opts Reserved for future use.
/// @param[out] err Error details, if any
-Object nvim_notify(String msg, Integer log_level, Dictionary opts, Arena *arena, Error *err)
+Object nvim_notify(String msg, Integer log_level, Dict opts, Arena *arena, Error *err)
FUNC_API_SINCE(7)
{
MAXSIZE_TEMP_ARRAY(args, 3);
ADD_C(args, STRING_OBJ(msg));
ADD_C(args, INTEGER_OBJ(log_level));
- ADD_C(args, DICTIONARY_OBJ(opts));
+ ADD_C(args, DICT_OBJ(opts));
return NLUA_EXEC_STATIC("return vim.notify(...)", args, kRetObject, arena, err);
}
@@ -571,10 +574,10 @@ typedef struct {
Arena *arena;
} RuntimeCookie;
-/// Find files in runtime directories
+/// Finds files in runtime directories, in 'runtimepath' order.
///
/// "name" can contain wildcards. For example
-/// nvim_get_runtime_file("colors/*.vim", true) will return all color
+/// `nvim_get_runtime_file("colors/*.{vim,lua}", true)` will return all color
/// scheme files. Always use forward slashes (/) in the search pattern for
/// subdirectories regardless of platform.
///
@@ -1210,17 +1213,30 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
}
}
-/// Pastes at cursor, in any mode.
+/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call
+/// this to implement "paste", but it's also intended for use by scripts to input large,
+/// dot-repeatable blocks of text (as opposed to |nvim_input()| which is subject to mappings/events
+/// and is thus much slower).
+///
+/// Invokes the |vim.paste()| handler, which handles each mode appropriately.
///
-/// Invokes the `vim.paste` handler, which handles each mode appropriately.
-/// Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n").
+/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the
+/// return value (which is strictly decided by `vim.paste()`). On error or cancel, subsequent calls
+/// are ignored ("drained") until the next paste is initiated (phase 1 or -1).
///
-/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err`
-/// but do not affect the return value (which is strictly decided by
-/// `vim.paste()`). On error, subsequent calls are ignored ("drained") until
-/// the next paste is initiated (phase 1 or -1).
+/// Useful in mappings and scripts to insert multiline text. Example:
+///
+/// ```lua
+/// vim.keymap.set('n', 'x', function()
+/// vim.api.nvim_paste([[
+/// line1
+/// line2
+/// line3
+/// ]], false, -1)
+/// end, { buffer = true })
+/// ```
///
-/// @param data Multiline input. May be binary (containing NUL bytes).
+/// @param data Multiline input. Lines break at LF ("\n"). May be binary (containing NUL bytes).
/// @param crlf Also break lines at CR and CRLF.
/// @param phase -1: paste in a single call (i.e. without streaming).
/// To "stream" a paste, call `nvim_paste` sequentially with
@@ -1231,20 +1247,20 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
/// @param[out] err Error details, if any
/// @return
/// - true: Client may continue pasting.
-/// - false: Client must cancel the paste.
-Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error *err)
+/// - false: Client should cancel the paste.
+Boolean nvim_paste(uint64_t channel_id, String data, Boolean crlf, Integer phase, Arena *arena,
+ Error *err)
FUNC_API_SINCE(6)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
{
- static bool draining = false;
- bool cancel = false;
+ static bool cancelled = false;
VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, {
return false;
});
if (phase == -1 || phase == 1) { // Start of paste-stream.
- draining = false;
- } else if (draining) {
+ cancelled = false;
+ } else if (cancelled) {
// Skip remaining chunks. Report error only once per "stream".
goto theend;
}
@@ -1253,40 +1269,29 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error
ADD_C(args, ARRAY_OBJ(lines));
ADD_C(args, INTEGER_OBJ(phase));
Object rv = NLUA_EXEC_STATIC("return vim.paste(...)", args, kRetNilBool, arena, err);
- if (ERROR_SET(err)) {
- draining = true;
- goto theend;
+ // vim.paste() decides if client should cancel.
+ if (ERROR_SET(err) || (rv.type == kObjectTypeBoolean && !rv.data.boolean)) {
+ cancelled = true;
}
- if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 1)) {
- ResetRedobuff();
- AppendCharToRedobuff('a'); // Dot-repeat.
- }
- // vim.paste() decides if client should cancel. Errors do NOT cancel: we
- // want to drain remaining chunks (rather than divert them to main input).
- cancel = (rv.type == kObjectTypeBoolean && !rv.data.boolean);
- if (!cancel && !(State & MODE_CMDLINE)) { // Dot-repeat.
- for (size_t i = 0; i < lines.size; i++) {
- String s = lines.items[i].data.string;
- assert(s.size <= INT_MAX);
- AppendToRedobuffLit(s.data, (int)s.size);
- // readfile()-style: "\n" is indicated by presence of N+1 item.
- if (i + 1 < lines.size) {
- AppendCharToRedobuff(NL);
- }
- }
+ if (!cancelled && (phase == -1 || phase == 1)) {
+ paste_store(channel_id, kFalse, NULL_STRING, crlf);
+ }
+ if (!cancelled) {
+ paste_store(channel_id, kNone, data, crlf);
}
- if (!(State & (MODE_CMDLINE | MODE_INSERT)) && (phase == -1 || phase == 3)) {
- AppendCharToRedobuff(ESC); // Dot-repeat.
+ if (phase == 3 || phase == (cancelled ? 2 : -1)) {
+ paste_store(channel_id, kTrue, NULL_STRING, crlf);
}
theend:
- if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
- draining = false;
+ ;
+ bool retval = !cancelled;
+ if (phase == -1 || phase == 3) { // End of paste-stream.
+ cancelled = false;
}
-
- return !cancel;
+ return retval;
}
-/// Puts text at cursor, in any mode.
+/// Puts text at cursor, in any mode. For dot-repeatable input, use |nvim_paste()|.
///
/// Compare |:put| and |p| which are always linewise.
///
@@ -1359,10 +1364,10 @@ Integer nvim_get_color_by_name(String name)
/// (e.g. 65535).
///
/// @return Map of color names and RGB values.
-Dictionary nvim_get_color_map(Arena *arena)
+Dict nvim_get_color_map(Arena *arena)
FUNC_API_SINCE(1)
{
- Dictionary colors = arena_dict(arena, ARRAY_SIZE(color_name_table));
+ Dict colors = arena_dict(arena, ARRAY_SIZE(color_name_table));
for (int i = 0; color_name_table[i].name != NULL; i++) {
PUT_C(colors, color_name_table[i].name, INTEGER_OBJ(color_name_table[i].color));
@@ -1378,7 +1383,7 @@ Dictionary nvim_get_color_map(Arena *arena)
/// @param[out] err Error details, if any
///
/// @return map of global |context|.
-Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
+Dict nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(6)
{
Array types = ARRAY_DICT_INIT;
@@ -1405,7 +1410,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
int_types |= kCtxFuncs;
} else {
VALIDATE_S(false, "type", s, {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
});
}
}
@@ -1414,7 +1419,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
Context ctx = CONTEXT_INIT;
ctx_save(&ctx, int_types);
- Dictionary dict = ctx_to_dict(&ctx, arena);
+ Dict dict = ctx_to_dict(&ctx, arena);
ctx_free(&ctx);
return dict;
}
@@ -1422,7 +1427,7 @@ Dictionary nvim_get_context(Dict(context) *opts, Arena *arena, Error *err)
/// Sets the current editor state from the given |context| map.
///
/// @param dict |Context| map.
-Object nvim_load_context(Dictionary dict, Error *err)
+Object nvim_load_context(Dict dict, Error *err)
FUNC_API_SINCE(6)
{
Context ctx = CONTEXT_INIT;
@@ -1444,11 +1449,11 @@ Object nvim_load_context(Dictionary dict, Error *err)
/// Gets the current mode. |mode()|
/// "blocking" is true if Nvim is waiting for input.
///
-/// @returns Dictionary { "mode": String, "blocking": Boolean }
-Dictionary nvim_get_mode(Arena *arena)
+/// @returns Dict { "mode": String, "blocking": Boolean }
+Dict nvim_get_mode(Arena *arena)
FUNC_API_SINCE(2) FUNC_API_FAST
{
- Dictionary rv = arena_dict(arena, 2);
+ Dict rv = arena_dict(arena, 2);
char *modestr = arena_alloc(arena, MODE_MAX_LENGTH, false);
get_mode(modestr);
bool blocked = input_blocking();
@@ -1464,7 +1469,7 @@ Dictionary nvim_get_mode(Arena *arena)
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @returns Array of |maparg()|-like dictionaries describing mappings.
/// The "buffer" key is always zero.
-ArrayOf(Dictionary) nvim_get_keymap(String mode, Arena *arena)
+ArrayOf(Dict) nvim_get_keymap(String mode, Arena *arena)
FUNC_API_SINCE(3)
{
return keymap_array(mode, NULL, arena);
@@ -1523,7 +1528,7 @@ void nvim_del_keymap(uint64_t channel_id, String mode, String lhs, Error *err)
}
/// Returns a 2-tuple (Array), where item 0 is the current channel id and item
-/// 1 is the |api-metadata| map (Dictionary).
+/// 1 is the |api-metadata| map (Dict).
///
/// @returns 2-tuple `[{channel-id}, {api-metadata}]`
Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
@@ -1552,7 +1557,7 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
///
/// @param channel_id
/// @param name Short name for the connected client
-/// @param version Dictionary describing the version, with these
+/// @param version Dict describing the version, with these
/// (optional) keys:
/// - "major" major version (defaults to 0 if not set, for no release yet)
/// - "minor" minor version
@@ -1584,14 +1589,15 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
///
/// @param attributes Arbitrary string:string map of informal client properties.
/// Suggested keys:
+/// - "pid": Process id.
/// - "website": Client homepage URL (e.g. GitHub repository)
/// - "license": License description ("Apache 2", "GPLv3", "MIT", …)
/// - "logo": URI or path to image, preferably small logo or icon.
/// .png or .svg format is preferred.
///
/// @param[out] err Error details, if any
-void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, String type,
- Dictionary methods, Dictionary attributes, Arena *arena, Error *err)
+void nvim_set_client_info(uint64_t channel_id, String name, Dict version, String type, Dict methods,
+ Dict attributes, Arena *arena, Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
MAXSIZE_TEMP_DICT(info, 5);
@@ -1605,7 +1611,7 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
}
}
if (!has_major) {
- Dictionary v = arena_dict(arena, version.size + 1);
+ Dict v = arena_dict(arena, version.size + 1);
if (version.size) {
memcpy(v.items, version.items, version.size * sizeof(v.items[0]));
v.size = version.size;
@@ -1613,19 +1619,19 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
PUT_C(v, "major", INTEGER_OBJ(0));
version = v;
}
- PUT_C(info, "version", DICTIONARY_OBJ(version));
+ PUT_C(info, "version", DICT_OBJ(version));
PUT_C(info, "type", STRING_OBJ(type));
- PUT_C(info, "methods", DICTIONARY_OBJ(methods));
- PUT_C(info, "attributes", DICTIONARY_OBJ(attributes));
+ PUT_C(info, "methods", DICT_OBJ(methods));
+ PUT_C(info, "attributes", DICT_OBJ(attributes));
- rpc_set_client_info(channel_id, copy_dictionary(info, NULL));
+ rpc_set_client_info(channel_id, copy_dict(info, NULL));
}
/// Gets information about a channel.
///
/// @param chan channel_id, or 0 for current channel
-/// @returns Dictionary describing a channel, with these keys:
+/// @returns Channel info dict with these keys:
/// - "id" Channel id.
/// - "argv" (optional) Job arguments list.
/// - "stream" Stream underlying the channel.
@@ -1637,20 +1643,18 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
/// - "bytes" Send and receive raw bytes.
/// - "terminal" |terminal| instance interprets ASCII sequences.
/// - "rpc" |RPC| communication on the channel is active.
-/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this
-/// is a device path like "/dev/pts/1". If the name is unknown,
-/// the key will still be present if a pty is used (e.g. for
-/// conpty on Windows).
-/// - "buffer" (optional) Buffer with connected |terminal| instance.
-/// - "client" (optional) Info about the peer (client on the other end of
-/// the RPC channel), if provided by it via
-/// |nvim_set_client_info()|.
-///
-Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err)
+/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this is a device path like
+/// "/dev/pts/1". If unknown, the key will still be present if a pty is used (e.g.
+/// for conpty on Windows).
+/// - "buffer" (optional) Buffer connected to |terminal| instance.
+/// - "client" (optional) Info about the peer (client on the other end of the RPC channel),
+/// which it provided via |nvim_set_client_info()|.
+///
+Dict nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
if (chan < 0) {
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
if (chan == 0 && !is_internal_call(channel_id)) {
@@ -1747,17 +1751,17 @@ Array nvim__id_array(Array arr, Arena *arena)
return copy_array(arr, arena);
}
-/// Returns dictionary given as argument.
+/// Returns dict given as argument.
///
/// This API function is used for testing. One should not rely on its presence
/// in plugins.
///
-/// @param[in] dct Dictionary to return.
+/// @param[in] dct Dict to return.
///
/// @return its argument.
-Dictionary nvim__id_dictionary(Dictionary dct, Arena *arena)
+Dict nvim__id_dict(Dict dct, Arena *arena)
{
- return copy_dictionary(dct, arena);
+ return copy_dict(dct, arena);
}
/// Returns floating-point value given as argument.
@@ -1776,9 +1780,9 @@ Float nvim__id_float(Float flt)
/// Gets internal stats.
///
/// @return Map of various internal stats.
-Dictionary nvim__stats(Arena *arena)
+Dict nvim__stats(Arena *arena)
{
- Dictionary rv = arena_dict(arena, 6);
+ Dict rv = arena_dict(arena, 6);
PUT_C(rv, "fsync", INTEGER_OBJ(g_stats.fsync));
PUT_C(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip));
PUT_C(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count()));
@@ -1855,8 +1859,8 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err)
});
#ifdef MSWIN
- rvobj = DICTIONARY_OBJ(os_proc_info((int)pid, arena));
- if (rvobj.data.dictionary.size == 0) { // Process not found.
+ rvobj = DICT_OBJ(os_proc_info((int)pid, arena));
+ if (rvobj.data.dict.size == 0) { // Process not found.
return NIL;
}
#else
@@ -1866,7 +1870,7 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err)
Object o = NLUA_EXEC_STATIC("return vim._os_proc_info(...)", a, kRetObject, arena, err);
if (o.type == kObjectTypeArray && o.data.array.size == 0) {
return NIL; // Process not found.
- } else if (o.type == kObjectTypeDictionary) {
+ } else if (o.type == kObjectTypeDict) {
rvobj = o;
} else if (!ERROR_SET(err)) {
api_set_error(err, kErrorTypeException,
@@ -1930,7 +1934,7 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, E
schar_get(sc_buf, g->chars[off]);
ADD_C(ret, CSTR_AS_OBJ(sc_buf));
int attr = g->attrs[off];
- ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
+ ADD_C(ret, DICT_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
// will not work first time
if (!highlight_use_hlstate()) {
ADD_C(ret, ARRAY_OBJ(hl_inspect(attr, arena)));
@@ -2073,18 +2077,18 @@ Array nvim_get_mark(String name, Dict(empty) *opts, Arena *arena, Error *err)
/// - use_statuscol_lnum: (number) Evaluate statuscolumn for this line number instead of statusline.
///
/// @param[out] err Error details, if any.
-/// @return Dictionary containing statusline information, with these keys:
+/// @return Dict containing statusline information, with these keys:
/// - str: (string) Characters that will be displayed on the statusline.
/// - width: (number) Display width of the statusline.
/// - highlights: Array containing highlight information of the statusline. Only included when
/// the "highlights" key in {opts} is true. Each element of the array is a
-/// |Dictionary| with these keys:
+/// |Dict| with these keys:
/// - start: (number) Byte index (0-based) of first character that uses the highlight.
/// - group: (string) Name of highlight group.
-Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err)
+Dict nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(8) FUNC_API_FAST
{
- Dictionary result = ARRAY_DICT_INIT;
+ Dict result = ARRAY_DICT_INIT;
int maxwidth;
schar_T fillchar = 0;
@@ -2210,18 +2214,18 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *
// If first character doesn't have a defined highlight,
// add the default highlight at the beginning of the highlight list
if (hltab->start == NULL || (hltab->start - buf) != 0) {
- Dictionary hl_info = arena_dict(arena, 2);
+ Dict hl_info = arena_dict(arena, 2);
const char *grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp,
opts->use_winbar, stc_hl_id);
PUT_C(hl_info, "start", INTEGER_OBJ(0));
PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname));
- ADD_C(hl_values, DICTIONARY_OBJ(hl_info));
+ ADD_C(hl_values, DICT_OBJ(hl_info));
}
for (stl_hlrec_t *sp = hltab; sp->start != NULL; sp++) {
- Dictionary hl_info = arena_dict(arena, 2);
+ Dict hl_info = arena_dict(arena, 2);
PUT_C(hl_info, "start", INTEGER_OBJ(sp->start - buf));
@@ -2235,7 +2239,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Arena *
grpname = arena_memdupz(arena, user_group, strlen(user_group));
}
PUT_C(hl_info, "group", CSTR_AS_OBJ(grpname));
- ADD_C(hl_values, DICTIONARY_OBJ(hl_info));
+ ADD_C(hl_values, DICT_OBJ(hl_info));
}
PUT_C(result, "highlights", ARRAY_OBJ(hl_values));
}
@@ -2261,12 +2265,12 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data)
/// @param index Completion candidate index
/// @param opts Optional parameters.
/// - info: (string) info text.
-/// @return Dictionary containing these keys:
+/// @return Dict containing these keys:
/// - winid: (number) floating window id
/// - bufnr: (number) buffer id in floating window
-Dictionary nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena)
+Dict nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena)
{
- Dictionary rv = arena_dict(arena, 2);
+ Dict rv = arena_dict(arena, 2);
if (HAS_KEY(opts, complete_set, info)) {
win_T *wp = pum_set_info((int)index, opts->info.data);
if (wp) {
@@ -2354,8 +2358,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
}
}
- int count = (win != NULL) + (buf != NULL);
- VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", {
+ unsigned count = (win != NULL) + (buf != NULL);
+ VALIDATE(xpopcount(opts->is_set__redraw_) > count, "%s", "at least one action required", {
return;
});
@@ -2392,10 +2396,6 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
redraw_buf_range_later(rbuf, first, last);
}
- if (opts->cursor) {
- setcursor_mayforce(win ? win : curwin, true);
- }
-
bool flush = opts->flush;
if (opts->tabline) {
// Flush later in case tabline was just hidden or shown for the first time.
@@ -2422,11 +2422,22 @@ void nvim__redraw(Dict(redraw) *opts, Error *err)
}
}
- // Flush pending screen updates if "flush" or "clear" is true, or when
- // redrawing a status component may have changed the grid dimensions.
+ win_T *cwin = win ? win : curwin;
+ // Allow moving cursor to recently opened window and make sure it is drawn #28868.
+ if (opts->cursor && (!cwin->w_grid.target || !cwin->w_grid.target->valid)) {
+ flush = true;
+ }
+
+ // Redraw pending screen updates when explicitly requested or when determined
+ // that it is necessary to properly draw other requested components.
if (flush && !cmdpreview) {
update_screen();
}
+
+ if (opts->cursor) {
+ setcursor_mayforce(cwin, true);
+ }
+
ui_flush();
RedrawingDisabled = save_rd;
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 477cbe2428..165cc93fbe 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -48,12 +48,12 @@
/// - output: (boolean, default false) Whether to capture and return
/// all (non-error, non-shell |:!|) output.
/// @param[out] err Error details (Vim error), if any
-/// @return Dictionary containing information about execution, with these keys:
+/// @return Dict containing information about execution, with these keys:
/// - output: (string|nil) Output if `opts.output` is true.
-Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
+Dict nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
FUNC_API_SINCE(11) FUNC_API_RET_ALLOC
{
- Dictionary result = ARRAY_DICT_INIT;
+ Dict result = ARRAY_DICT_INIT;
String output = exec_impl(channel_id, src, opts, err);
if (ERROR_SET(err)) {
@@ -109,7 +109,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
memmove(s.data, s.data + 1, s.size - 1);
- s.data[s.size - 1] = '\0';
+ s.data[s.size - 1] = NUL;
s.size = s.size - 1;
}
return s; // Caller will free the memory.
@@ -140,8 +140,7 @@ void nvim_command(String command, Error *err)
try_end(err);
}
-/// Evaluates a Vimscript |expression|.
-/// Dictionaries and Lists are recursively expanded.
+/// Evaluates a Vimscript |expression|. Dicts and Lists are recursively expanded.
///
/// On execution error: fails with Vimscript error, updates v:errmsg.
///
@@ -270,7 +269,7 @@ Object nvim_call_function(String fn, Array args, Arena *arena, Error *err)
///
/// On execution error: fails with Vimscript error, updates v:errmsg.
///
-/// @param dict Dictionary, or String evaluating to a Vimscript |self| dict
+/// @param dict Dict, or String evaluating to a Vimscript |self| dict
/// @param fn Name of the function defined on the Vimscript dict
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
@@ -297,12 +296,11 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
// refcount of a dict. Not necessary for a RPC dict.
mustfree = true;
break;
- case kObjectTypeDictionary:
+ case kObjectTypeDict:
object_to_vim(dict, &rettv, err);
break;
default:
- api_set_error(err, kErrorTypeValidation,
- "dict argument type must be String or Dictionary");
+ api_set_error(err, kErrorTypeValidation, "dict argument type must be String or Dict");
return rv;
}
dict_T *self_dict = rettv.vval.v_dict;
@@ -311,7 +309,7 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
goto end;
}
- if (fn.data && fn.size > 0 && dict.type != kObjectTypeDictionary) {
+ 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);
@@ -377,8 +375,8 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// one should highlight region [start_col, end_col)).
///
/// @return
-/// - AST: top-level dictionary with these keys:
-/// - "error": Dictionary with error, present only if parser saw some
+/// - AST: top-level dict with these keys:
+/// - "error": Dict with error, present only if parser saw some
/// error. Contains the following keys:
/// - "message": String, error message in printf format, translated.
/// Must contain exactly one "%.*s".
@@ -387,7 +385,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// that should be equal to the length of expr string.
/// ("Successfully parsed" here means "participated in AST
/// creation", not "till the first error".)
-/// - "ast": AST, either nil or a dictionary with these keys:
+/// - "ast": AST, either nil or a dict with these keys:
/// - "type": node type, one of the value names from ExprASTNodeType
/// stringified without "kExprNode" prefix.
/// - "start": a pair `[line, column]` describing where node is "started"
@@ -427,8 +425,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "svalue": String, value for "SingleQuotedString" and
/// "DoubleQuotedString" nodes.
/// @param[out] err Error details, if any
-Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Arena *arena,
- Error *err)
+Dict nvim_parse_expression(String expr, String flags, Boolean highlight, Arena *arena, Error *err)
FUNC_API_SINCE(4) FUNC_API_FAST
{
int pflags = 0;
@@ -443,11 +440,11 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A
case NUL:
api_set_error(err, kErrorTypeValidation, "Invalid flag: '\\0' (%u)",
(unsigned)flags.data[i]);
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
default:
api_set_error(err, kErrorTypeValidation, "Invalid flag: '%c' (%u)",
flags.data[i], (unsigned)flags.data[i]);
- return (Dictionary)ARRAY_DICT_INIT;
+ return (Dict)ARRAY_DICT_INIT;
}
}
ParserLine parser_lines[] = {
@@ -471,15 +468,15 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A
+ (size_t)highlight // "highlight"
+ 0);
- Dictionary ret = arena_dict(arena, ret_size);
+ Dict ret = arena_dict(arena, ret_size);
PUT_C(ret, "len", INTEGER_OBJ((Integer)(pstate.pos.line == 1
? parser_lines[0].size
: pstate.pos.col)));
if (east.err.msg != NULL) {
- Dictionary err_dict = arena_dict(arena, 2);
+ Dict err_dict = arena_dict(arena, 2);
PUT_C(err_dict, "message", CSTR_TO_ARENA_OBJ(arena, east.err.msg));
PUT_C(err_dict, "arg", CBUF_TO_ARENA_OBJ(arena, east.err.arg, (size_t)east.err.arg_len));
- PUT_C(ret, "error", DICTIONARY_OBJ(err_dict));
+ PUT_C(ret, "error", DICT_OBJ(err_dict));
}
if (highlight) {
Array hl = arena_array(arena, kv_size(colors));
@@ -530,10 +527,10 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A
|| node->type == kExprNodeSingleQuotedString) // "svalue"
+ (node->type == kExprNodeAssignment) // "augmentation"
+ 0);
- Dictionary ret_node = arena_dict(arena, items_size);
- *cur_item.ret_node_p = DICTIONARY_OBJ(ret_node);
+ Dict ret_node = arena_dict(arena, items_size);
+ *cur_item.ret_node_p = DICT_OBJ(ret_node);
}
- Dictionary *ret_node = &cur_item.ret_node_p->data.dictionary;
+ Dict *ret_node = &cur_item.ret_node_p->data.dict;
if (node->children != NULL) {
const size_t num_children = 1 + (node->children->next != NULL);
Array children_array = arena_array(arena, num_children);
@@ -638,8 +635,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, A
case kExprNodeMod:
break;
}
- assert(cur_item.ret_node_p->data.dictionary.size
- == cur_item.ret_node_p->data.dictionary.capacity);
+ assert(cur_item.ret_node_p->data.dict.size == cur_item.ret_node_p->data.dict.capacity);
xfree(*cur_item.node_p);
*cur_item.node_p = NULL;
}
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 3a9986a7d1..f63fdc5381 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -17,6 +17,7 @@
#include "nvim/decoration.h"
#include "nvim/decoration_defs.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/extmark_defs.h"
#include "nvim/globals.h"
@@ -189,13 +190,13 @@
/// ```
/// - title: Title (optional) in window border, string or list.
/// List should consist of `[text, highlight]` tuples.
-/// If string, the default highlight group is `FloatTitle`.
+/// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`.
/// - title_pos: Title position. Must be set with `title` option.
/// Value can be one of "left", "center", or "right".
/// Default is `"left"`.
/// - footer: Footer (optional) in window border, string or list.
/// List should consist of `[text, highlight]` tuples.
-/// If string, the default highlight group is `FloatFooter`.
+/// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`.
/// - footer_pos: Footer position. Must be set with `footer` option.
/// Value can be one of "left", "center", or "right".
/// Default is `"left"`.
@@ -447,7 +448,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
}
}
}
- win->w_config = fconfig;
+ merge_win_config(&win->w_config, fconfig);
// If there's no "vertical" or "split" set, or if "split" is unchanged,
// then we can just change the size of the window.
@@ -851,27 +852,16 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type,
bool *is_present;
VirtText *chunks;
int *width;
- int default_hl_id;
switch (bordertext_type) {
case kBorderTextTitle:
- if (fconfig->title) {
- clear_virttext(&fconfig->title_chunks);
- }
-
is_present = &fconfig->title;
chunks = &fconfig->title_chunks;
width = &fconfig->title_width;
- default_hl_id = syn_check_group(S_LEN("FloatTitle"));
break;
case kBorderTextFooter:
- if (fconfig->footer) {
- clear_virttext(&fconfig->footer_chunks);
- }
-
is_present = &fconfig->footer;
chunks = &fconfig->footer_chunks;
width = &fconfig->footer_width;
- default_hl_id = syn_check_group(S_LEN("FloatFooter"));
break;
}
@@ -880,8 +870,9 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type,
*is_present = false;
return;
}
+ kv_init(*chunks);
kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data),
- .hl_id = default_hl_id }));
+ .hl_id = -1 }));
*width = (int)mb_string2cells(bordertext.data.string.data);
*is_present = true;
return;
@@ -1040,7 +1031,7 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err)
static void generate_api_error(win_T *wp, const char *attribute, Error *err)
{
- if (wp->w_floating) {
+ if (wp != NULL && wp->w_floating) {
api_set_error(err, kErrorTypeValidation,
"Missing 'relative' field when reconfiguring floating window %d",
wp->handle);
@@ -1057,13 +1048,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (config->relative.size > 0) {
if (!parse_float_relative(config->relative, &fconfig->relative)) {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
- return false;
+ 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'");
- return false;
+ goto fail;
}
has_relative = true;
@@ -1078,39 +1069,39 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
} else if (wp == NULL) { // new win
api_set_error(err, kErrorTypeValidation,
"Must specify 'relative' or 'external' when creating a float");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, vertical)) {
if (!is_split) {
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'vertical'");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, split)) {
if (!is_split) {
api_set_error(err, kErrorTypeValidation, "floating windows cannot have 'split'");
- return false;
+ goto fail;
}
if (!parse_config_split(config->split, &fconfig->split)) {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'split' key");
- return false;
+ 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");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, row)) {
if (!has_relative || is_split) {
generate_api_error(wp, "row", err);
- return false;
+ goto fail;
}
fconfig->row = config->row;
}
@@ -1118,7 +1109,7 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (HAS_KEY_X(config, col)) {
if (!has_relative || is_split) {
generate_api_error(wp, "col", err);
- return false;
+ goto fail;
}
fconfig->col = config->col;
}
@@ -1126,11 +1117,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (HAS_KEY_X(config, bufpos)) {
if (!has_relative || is_split) {
generate_api_error(wp, "bufpos", err);
- return false;
+ goto fail;
} else {
if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
- return false;
+ goto fail;
}
if (!HAS_KEY_X(config, row)) {
@@ -1147,11 +1138,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
fconfig->width = (int)config->width;
} else {
api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
- return false;
+ goto fail;
}
} else if (!reconf && !is_split) {
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
- return false;
+ goto fail;
}
if (HAS_KEY_X(config, height)) {
@@ -1159,23 +1150,23 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
fconfig->height = (int)config->height;
} else {
api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
- return false;
+ goto fail;
}
} else if (!reconf && !is_split) {
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
- return false;
+ goto fail;
}
if (relative_is_win || is_split) {
if (reconf && relative_is_win) {
win_T *target_win = find_window_by_handle(config->win, err);
if (!target_win) {
- return false;
+ goto fail;
}
if (target_win == wp) {
api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself");
- return false;
+ goto fail;
}
}
fconfig->window = curwin->handle;
@@ -1188,11 +1179,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (has_relative) {
api_set_error(err, kErrorTypeValidation,
"'win' key is only valid with relative='win' and relative=''");
- return false;
+ goto fail;
} else if (!is_split) {
api_set_error(err, kErrorTypeValidation,
"non-float with 'win' requires at least 'split' or 'vertical'");
- return false;
+ goto fail;
}
}
@@ -1201,11 +1192,11 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
if (has_relative && fconfig->external) {
api_set_error(err, kErrorTypeValidation,
"Only one of 'relative' and 'external' must be used");
- return false;
+ goto fail;
}
if (fconfig->external && !ui_has(kUIMultigrid)) {
api_set_error(err, kErrorTypeValidation, "UI doesn't support external windows");
- return false;
+ goto fail;
}
}
@@ -1216,78 +1207,78 @@ 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'");
- return false;
+ goto fail;
}
if (config->zindex > 0) {
fconfig->zindex = (int)config->zindex;
} else {
api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, title)) {
if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'title'");
- return false;
+ goto fail;
}
// title only work with border
if (!HAS_KEY_X(config, border) && !fconfig->border) {
api_set_error(err, kErrorTypeException, "title requires border to be set");
- return false;
+ goto fail;
}
parse_bordertext(config->title, kBorderTextTitle, fconfig, err);
if (ERROR_SET(err)) {
- return false;
+ goto fail;
}
// handles unset 'title_pos' same as empty string
if (!parse_bordertext_pos(config->title_pos, kBorderTextTitle, fconfig, err)) {
- return false;
+ goto fail;
}
} else {
if (HAS_KEY_X(config, title_pos)) {
api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, footer)) {
if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'footer'");
- return false;
+ goto fail;
}
// footer only work with border
if (!HAS_KEY_X(config, border) && !fconfig->border) {
api_set_error(err, kErrorTypeException, "footer requires border to be set");
- return false;
+ goto fail;
}
parse_bordertext(config->footer, kBorderTextFooter, fconfig, err);
if (ERROR_SET(err)) {
- return false;
+ goto fail;
}
// handles unset 'footer_pos' same as empty string
if (!parse_bordertext_pos(config->footer_pos, kBorderTextFooter, fconfig, err)) {
- return false;
+ goto fail;
}
} else {
if (HAS_KEY_X(config, footer_pos)) {
api_set_error(err, kErrorTypeException, "footer_pos requires footer to be set");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, border)) {
if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
- return false;
+ goto fail;
}
parse_border_style(config->border, fconfig, err);
if (ERROR_SET(err)) {
- return false;
+ goto fail;
}
}
@@ -1298,14 +1289,14 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
fconfig->style = kWinStyleMinimal;
} else {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
- return false;
+ goto fail;
}
}
if (HAS_KEY_X(config, noautocmd)) {
if (wp) {
api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be used with existing windows");
- return false;
+ goto fail;
}
fconfig->noautocmd = config->noautocmd;
}
@@ -1319,5 +1310,9 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
}
return true;
+
+fail:
+ merge_win_config(fconfig, wp != NULL ? wp->w_config : WIN_CONFIG_INIT);
+ return false;
#undef HAS_KEY_X
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 54a19513db..5a4972ef23 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/buffer_defs.h"
#include "nvim/cursor.h"
#include "nvim/drawscreen.h"
+#include "nvim/errors.h"
#include "nvim/eval/window.h"
#include "nvim/ex_docmd.h"
#include "nvim/gettext_defs.h"
@@ -502,16 +503,15 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err)
/// - end_vcol: Ending virtual column index on "end_row",
/// 0-based exclusive, rounded up to full screen lines.
/// When omitted include the whole line.
-/// @return Dictionary containing text height information, with these keys:
+/// @return Dict containing text height information, with these keys:
/// - all: The total number of screen lines occupied by the range.
/// - fill: The number of diff filler or virtual lines among them.
///
/// @see |virtcol()| for text width.
-Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena,
- Error *err)
+Dict nvim_win_text_height(Window window, Dict(win_text_height) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(12)
{
- Dictionary rv = arena_dict(arena, 2);
+ Dict rv = arena_dict(arena, 2);
win_T *const win = find_window_by_handle(window, err);
if (!win) {