aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-01 14:01:19 +0200
committerbfredl <bjorn.linse@gmail.com>2023-08-07 13:11:15 +0200
commit7bc93e0e2f246dd78026a3472d929a0fe450f70d (patch)
tree9e5b99830c3f08e0ffd75c7a0533b39033490a5b
parentc01e624b0762b24a4988bf9474a57d5b6278d180 (diff)
downloadrneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.tar.gz
rneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.tar.bz2
rneovim-7bc93e0e2f246dd78026a3472d929a0fe450f70d.zip
refactor(api): use typed keysets
Initially this is just for geting rid of boilerplate, but eventually the types could get exposed as metadata
-rwxr-xr-xscripts/gen_eval_files.lua17
-rw-r--r--src/nvim/api/autocmd.c92
-rw-r--r--src/nvim/api/command.c240
-rw-r--r--src/nvim/api/deprecated.c6
-rw-r--r--src/nvim/api/extmark.c166
-rw-r--r--src/nvim/api/keysets.h321
-rw-r--r--src/nvim/api/options.c46
-rw-r--r--src/nvim/api/private/defs.h12
-rw-r--r--src/nvim/api/private/helpers.c87
-rw-r--r--src/nvim/api/private/helpers.h5
-rw-r--r--src/nvim/api/vim.c99
-rw-r--r--src/nvim/api/vimscript.c14
-rw-r--r--src/nvim/api/win_config.c206
-rw-r--r--src/nvim/api/window.c37
-rw-r--r--src/nvim/context.c3
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua87
-rw-r--r--src/nvim/highlight.c40
-rw-r--r--src/nvim/highlight_group.c25
-rw-r--r--src/nvim/lua/converter.c73
-rw-r--r--src/nvim/lua/converter.h4
-rw-r--r--src/nvim/mapping.c37
-rw-r--r--test/functional/api/extmark_spec.lua2
-rw-r--r--test/functional/api/highlight_spec.lua8
23 files changed, 766 insertions, 861 deletions
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index c3123fd47c..eea76958ae 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -260,19 +260,18 @@ local function get_api_keysets()
local ret = {} --- @type table<string, vim.EvalFn>
- --- @type {[1]: string, [2]: {[1]: string, [2]: string}[] }[]
+ --- @type {name: string, keys: string[], types: table<string,string>}[]
local keysets = metadata.keysets
- for _, keyset in ipairs(keysets) do
- local kname = keyset[1]
- local kdef = keyset[2]
- for _, field in ipairs(kdef) do
- field[2] = api_type(field[2])
+ for _, k in ipairs(keysets) do
+ local params = {}
+ for _, key in ipairs(k.keys) do
+ table.insert(params, {key, api_type(k.types[key] or 'any')})
end
- ret[kname] = {
+ ret[k.name] = {
signature = 'NA',
- name = kname,
- params = kdef,
+ name = k.name,
+ params = params,
}
end
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index 6ab1283f89..aa0c2695ad 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -11,6 +11,7 @@
#include "lauxlib.h"
#include "nvim/api/autocmd.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/ascii.h"
@@ -125,7 +126,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
});
}
- if (HAS_KEY(opts->event)) {
+ if (HAS_KEY(opts, get_autocmds, event)) {
check_event = true;
Object v = opts->event;
@@ -148,13 +149,13 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
}
}
- VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)),
+ VALIDATE((!HAS_KEY(opts, get_autocmds, pattern) || !HAS_KEY(opts, get_autocmds, buffer)),
"%s", "Cannot use both 'pattern' and 'buffer'", {
goto cleanup;
});
int pattern_filter_count = 0;
- if (HAS_KEY(opts->pattern)) {
+ if (HAS_KEY(opts, get_autocmds, pattern)) {
Object v = opts->pattern;
if (v.type == kObjectTypeString) {
pattern_filters[pattern_filter_count] = v.data.string.data;
@@ -209,7 +210,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
ADD(buffers, CSTR_TO_OBJ(pattern_buflocal));
});
- } else if (HAS_KEY(opts->buffer)) {
+ } else if (HAS_KEY(opts, get_autocmds, buffer)) {
VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), {
goto cleanup;
});
@@ -408,12 +409,12 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
goto cleanup;
}
- VALIDATE((!HAS_KEY(opts->callback) || !HAS_KEY(opts->command)),
+ VALIDATE((!HAS_KEY(opts, create_autocmd, callback) || !HAS_KEY(opts, create_autocmd, command)),
"%s", "Cannot use both 'callback' and 'command'", {
goto cleanup;
});
- if (HAS_KEY(opts->callback)) {
+ if (HAS_KEY(opts, create_autocmd, callback)) {
// NOTE: We could accept callable tables, but that isn't common in the API.
Object *callback = &opts->callback;
@@ -442,36 +443,33 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
aucmd.type = CALLABLE_CB;
aucmd.callable.cb = cb;
- } else if (HAS_KEY(opts->command)) {
- Object *command = &opts->command;
- VALIDATE_T("command", kObjectTypeString, command->type, {
- goto cleanup;
- });
+ } else if (HAS_KEY(opts, create_autocmd, command)) {
aucmd.type = CALLABLE_EX;
- aucmd.callable.cmd = string_to_cstr(command->data.string);
+ aucmd.callable.cmd = string_to_cstr(opts->command);
} else {
VALIDATE(false, "%s", "Required: 'command' or 'callback'", {
goto cleanup;
});
}
- bool is_once = api_object_to_bool(opts->once, "once", false, err);
- bool is_nested = api_object_to_bool(opts->nested, "nested", false, err);
-
int au_group = get_augroup_from_object(opts->group, err);
if (au_group == AUGROUP_ERROR) {
goto cleanup;
}
- if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
+ bool has_buffer = HAS_KEY(opts, create_autocmd, buffer);
+
+ VALIDATE((!HAS_KEY(opts, create_autocmd, pattern) || !has_buffer),
+ "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", {
+ goto cleanup;
+ });
+
+ if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
goto cleanup;
}
- if (HAS_KEY(opts->desc)) {
- VALIDATE_T("desc", kObjectTypeString, opts->desc.type, {
- goto cleanup;
- });
- desc = opts->desc.data.string.data;
+ if (HAS_KEY(opts, create_autocmd, desc)) {
+ desc = opts->desc.data;
}
if (patterns.size == 0) {
@@ -496,8 +494,8 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
pat.data.string.data,
(int)pat.data.string.size,
au_group,
- is_once,
- is_nested,
+ opts->once,
+ opts->nested,
desc,
aucmd);
});
@@ -568,7 +566,9 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
goto cleanup;
}
- VALIDATE((!HAS_KEY(opts->pattern) || !HAS_KEY(opts->buffer)),
+ bool has_buffer = HAS_KEY(opts, clear_autocmds, buffer);
+
+ VALIDATE((!HAS_KEY(opts, clear_autocmds, pattern) || !has_buffer),
"%s", "Cannot use both 'pattern' and 'buffer'", {
goto cleanup;
});
@@ -578,7 +578,7 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
goto cleanup;
}
- if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
+ if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
goto cleanup;
}
@@ -742,21 +742,22 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
});
}
- if (HAS_KEY(opts->buffer)) {
- Object buf_obj = opts->buffer;
- VALIDATE_EXP((buf_obj.type == kObjectTypeInteger || buf_obj.type == kObjectTypeBuffer),
- "buffer", "Integer", api_typename(buf_obj.type), {
+ bool has_buffer = false;
+ if (HAS_KEY(opts, exec_autocmds, buffer)) {
+ VALIDATE((!HAS_KEY(opts, exec_autocmds, pattern)),
+ "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", {
goto cleanup;
});
- buf = find_buffer_by_handle((Buffer)buf_obj.data.integer, err);
+ has_buffer = true;
+ buf = find_buffer_by_handle(opts->buffer, err);
if (ERROR_SET(err)) {
goto cleanup;
}
}
- if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, opts->buffer, err)) {
+ if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
goto cleanup;
}
@@ -764,20 +765,19 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
ADD(patterns, STATIC_CSTR_TO_OBJ(""));
}
- if (HAS_KEY(opts->data)) {
+ if (HAS_KEY(opts, exec_autocmds, data)) {
data = &opts->data;
}
- modeline = api_object_to_bool(opts->modeline, "modeline", true, err);
+ modeline = GET_BOOL_OR_TRUE(opts, exec_autocmds, modeline);
bool did_aucmd = false;
FOREACH_ITEM(event_array, event_str, {
GET_ONE_EVENT(event_nr, event_str, cleanup)
FOREACH_ITEM(patterns, pat, {
- char *fname = !HAS_KEY(opts->buffer) ? pat.data.string.data : NULL;
- did_aucmd |=
- apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data);
+ char *fname = !has_buffer ? pat.data.string.data : NULL;
+ did_aucmd |= apply_autocmds_group(event_nr, fname, NULL, true, au_group, buf, NULL, data);
})
})
@@ -837,17 +837,12 @@ static int get_augroup_from_object(Object group, Error *err)
}
}
-static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Object buffer,
- Error *err)
+static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, bool has_buffer,
+ Buffer buffer, Error *err)
{
const char pattern_buflocal[BUFLOCAL_PAT_LEN];
- VALIDATE((!HAS_KEY(pattern) || !HAS_KEY(buffer)),
- "%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", {
- return false;
- });
-
- if (HAS_KEY(pattern)) {
+ if (pattern.type != kObjectTypeNil) {
Object *v = &pattern;
if (v->type == kObjectTypeString) {
@@ -880,13 +875,8 @@ static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, Ob
return false;
});
}
- } else if (HAS_KEY(buffer)) {
- VALIDATE_EXP((buffer.type == kObjectTypeInteger || buffer.type == kObjectTypeBuffer),
- "buffer", "Integer", api_typename(buffer.type), {
- return false;
- });
-
- buf_T *buf = find_buffer_by_handle((Buffer)buffer.data.integer, err);
+ } else if (has_buffer) {
+ buf_T *buf = find_buffer_by_handle(buffer, err);
if (ERROR_SET(err)) {
return false;
}
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 75140beb88..2b09cfc4b2 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -341,16 +341,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
} \
} while (0)
-#define OBJ_TO_CMOD_FLAG(flag, value, default, varname) \
- do { \
- if (api_object_to_bool(value, varname, default, err)) { \
- cmdinfo.cmdmod.cmod_flags |= (flag); \
- } \
- if (ERROR_SET(err)) { \
- goto end; \
- } \
- } while (0)
-
#define VALIDATE_MOD(cond, mod_, name_) \
do { \
if (!(cond)) { \
@@ -359,18 +349,14 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
} \
} while (0)
- bool output;
- OBJ_TO_BOOL(output, opts->output, false, "'output'");
-
- VALIDATE_R(HAS_KEY(cmd->cmd), "cmd", {
+ VALIDATE_R(HAS_KEY(cmd, cmd, cmd), "cmd", {
goto end;
});
- VALIDATE_EXP((cmd->cmd.type == kObjectTypeString && cmd->cmd.data.string.data[0] != NUL),
- "cmd", "non-empty String", NULL, {
+ VALIDATE_EXP((cmd->cmd.data[0] != NUL), "cmd", "non-empty String", NULL, {
goto end;
});
- cmdname = string_to_cstr(cmd->cmd.data.string);
+ cmdname = string_to_cstr(cmd->cmd);
ea.cmd = cmdname;
char *p = find_ex_command(&ea, NULL);
@@ -407,15 +393,11 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
// Parse command arguments since it's needed to get the command address type.
- if (HAS_KEY(cmd->args)) {
- VALIDATE_T("args", kObjectTypeArray, cmd->args.type, {
- goto end;
- });
-
+ if (HAS_KEY(cmd, cmd, args)) {
// Process all arguments. Convert non-String arguments to String and check if String arguments
// have non-whitespace characters.
- for (size_t i = 0; i < cmd->args.data.array.size; i++) {
- Object elem = cmd->args.data.array.items[i];
+ for (size_t i = 0; i < cmd->args.size; i++) {
+ Object elem = cmd->args.items[i];
char *data_str;
switch (elem.type) {
@@ -477,16 +459,13 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
// since it only ever checks the first argument.
set_cmd_addr_type(&ea, args.size > 0 ? args.items[0].data.string.data : NULL);
- if (HAS_KEY(cmd->range)) {
- VALIDATE_MOD((ea.argt & EX_RANGE), "range", cmd->cmd.data.string.data);
- VALIDATE_T("range", kObjectTypeArray, cmd->range.type, {
- goto end;
- });
- VALIDATE_EXP((cmd->range.data.array.size <= 2), "range", "<=2 elements", NULL, {
+ if (HAS_KEY(cmd, cmd, range)) {
+ VALIDATE_MOD((ea.argt & EX_RANGE), "range", cmd->cmd.data);
+ VALIDATE_EXP((cmd->range.size <= 2), "range", "<=2 elements", NULL, {
goto end;
});
- Array range = cmd->range.data.array;
+ Array range = cmd->range;
ea.addr_count = (int)range.size;
for (size_t i = 0; i < range.size; i++) {
@@ -519,22 +498,21 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
}
- if (HAS_KEY(cmd->count)) {
- VALIDATE_MOD((ea.argt & EX_COUNT), "count", cmd->cmd.data.string.data);
- VALIDATE_EXP((cmd->count.type == kObjectTypeInteger && cmd->count.data.integer >= 0),
- "count", "non-negative Integer", NULL, {
+ if (HAS_KEY(cmd, cmd, count)) {
+ VALIDATE_MOD((ea.argt & EX_COUNT), "count", cmd->cmd.data);
+ VALIDATE_EXP((cmd->count >= 0), "count", "non-negative Integer", NULL, {
goto end;
});
- set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true);
+ set_cmd_count(&ea, (linenr_T)cmd->count, true);
}
- if (HAS_KEY(cmd->reg)) {
- VALIDATE_MOD((ea.argt & EX_REGSTR), "register", cmd->cmd.data.string.data);
- VALIDATE_EXP((cmd->reg.type == kObjectTypeString && cmd->reg.data.string.size == 1),
- "reg", "single character", cmd->reg.data.string.data, {
+ if (HAS_KEY(cmd, cmd, reg)) {
+ VALIDATE_MOD((ea.argt & EX_REGSTR), "register", cmd->cmd.data);
+ VALIDATE_EXP((cmd->reg.size == 1),
+ "reg", "single character", cmd->reg.data, {
goto end;
});
- char regname = cmd->reg.data.string.data[0];
+ char regname = cmd->reg.data[0];
VALIDATE((regname != '='), "%s", "Cannot use register \"=", {
goto end;
});
@@ -545,22 +523,17 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
ea.regname = (uint8_t)regname;
}
- OBJ_TO_BOOL(ea.forceit, cmd->bang, false, "'bang'");
- VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data.string.data);
+ ea.forceit = cmd->bang;
+ VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data);
- if (HAS_KEY(cmd->magic)) {
- VALIDATE_T_DICT("magic", cmd->magic, {
- goto end;
- });
-
- Dict(cmd_magic) magic = { 0 };
- if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field,
- cmd->magic.data.dictionary, err)) {
+ if (HAS_KEY(cmd, cmd, magic)) {
+ Dict(cmd_magic) magic[1] = { 0 };
+ if (!api_dict_to_keydict(magic, KeyDict_cmd_magic_get_field, cmd->magic, err)) {
goto end;
}
- OBJ_TO_BOOL(cmdinfo.magic.file, magic.file, ea.argt & EX_XFILE, "'magic.file'");
- OBJ_TO_BOOL(cmdinfo.magic.bar, magic.bar, ea.argt & EX_TRLBAR, "'magic.bar'");
+ cmdinfo.magic.file = HAS_KEY(magic, cmd_magic, file) ? magic->file : (ea.argt & EX_XFILE);
+ cmdinfo.magic.bar = HAS_KEY(magic, cmd_magic, bar) ? magic->bar : (ea.argt & EX_TRLBAR);
if (cmdinfo.magic.file) {
ea.argt |= EX_XFILE;
} else {
@@ -571,89 +544,63 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
cmdinfo.magic.bar = ea.argt & EX_TRLBAR;
}
- if (HAS_KEY(cmd->mods)) {
- VALIDATE_T_DICT("mods", cmd->mods, {
- goto end;
- });
-
- Dict(cmd_mods) mods = { 0 };
- if (!api_dict_to_keydict(&mods, KeyDict_cmd_mods_get_field, cmd->mods.data.dictionary, err)) {
+ if (HAS_KEY(cmd, cmd, mods)) {
+ Dict(cmd_mods) mods[1] = { 0 };
+ if (!api_dict_to_keydict(mods, KeyDict_cmd_mods_get_field, cmd->mods, err)) {
goto end;
}
- if (HAS_KEY(mods.filter)) {
- VALIDATE_T_DICT("mods.filter", mods.filter, {
- goto end;
- });
-
- Dict(cmd_mods_filter) filter = { 0 };
+ if (HAS_KEY(mods, cmd_mods, filter)) {
+ Dict(cmd_mods_filter) filter[1] = { 0 };
if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field,
- mods.filter.data.dictionary, err)) {
+ mods->filter, err)) {
goto end;
}
- if (HAS_KEY(filter.pattern)) {
- VALIDATE_T2(filter.pattern, kObjectTypeString, {
- goto end;
- });
-
- OBJ_TO_BOOL(cmdinfo.cmdmod.cmod_filter_force, filter.force, false, "'mods.filter.force'");
+ if (HAS_KEY(filter, cmd_mods_filter, pattern)) {
+ cmdinfo.cmdmod.cmod_filter_force = filter->force;
// "filter! // is not no-op, so add a filter if either the pattern is non-empty or if filter
// is inverted.
- if (*filter.pattern.data.string.data != NUL || cmdinfo.cmdmod.cmod_filter_force) {
- cmdinfo.cmdmod.cmod_filter_pat = string_to_cstr(filter.pattern.data.string);
+ if (*filter->pattern.data != NUL || cmdinfo.cmdmod.cmod_filter_force) {
+ cmdinfo.cmdmod.cmod_filter_pat = string_to_cstr(filter->pattern);
cmdinfo.cmdmod.cmod_filter_regmatch.regprog = vim_regcomp(cmdinfo.cmdmod.cmod_filter_pat,
RE_MAGIC);
}
}
}
- if (HAS_KEY(mods.tab)) {
- VALIDATE_T2(mods.tab, kObjectTypeInteger, {
- goto end;
- });
- if ((int)mods.tab.data.integer >= 0) {
+ if (HAS_KEY(mods, cmd_mods, tab)) {
+ if ((int)mods->tab >= 0) {
// Silently ignore negative integers to allow mods.tab to be set to -1.
- cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1;
+ cmdinfo.cmdmod.cmod_tab = (int)mods->tab + 1;
}
}
- if (HAS_KEY(mods.verbose)) {
- VALIDATE_T2(mods.verbose, kObjectTypeInteger, {
- goto end;
- });
- if ((int)mods.verbose.data.integer >= 0) {
+ if (HAS_KEY(mods, cmd_mods, verbose)) {
+ if ((int)mods->verbose >= 0) {
// Silently ignore negative integers to allow mods.verbose to be set to -1.
- cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1;
+ cmdinfo.cmdmod.cmod_verbose = (int)mods->verbose + 1;
}
}
- bool vertical;
- OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'");
- cmdinfo.cmdmod.cmod_split |= (vertical ? WSP_VERT : 0);
+ cmdinfo.cmdmod.cmod_split |= (mods->vertical ? WSP_VERT : 0);
- bool horizontal;
- OBJ_TO_BOOL(horizontal, mods.horizontal, false, "'mods.horizontal'");
- cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0);
+ cmdinfo.cmdmod.cmod_split |= (mods->horizontal ? WSP_HOR : 0);
- if (HAS_KEY(mods.split)) {
- VALIDATE_T2(mods.split, kObjectTypeString, {
- goto end;
- });
-
- if (*mods.split.data.string.data == NUL) {
+ if (HAS_KEY(mods, cmd_mods, split)) {
+ if (*mods->split.data == NUL) {
// Empty string, do nothing.
- } else if (strcmp(mods.split.data.string.data, "aboveleft") == 0
- || strcmp(mods.split.data.string.data, "leftabove") == 0) {
+ } else if (strcmp(mods->split.data, "aboveleft") == 0
+ || strcmp(mods->split.data, "leftabove") == 0) {
cmdinfo.cmdmod.cmod_split |= WSP_ABOVE;
- } else if (strcmp(mods.split.data.string.data, "belowright") == 0
- || strcmp(mods.split.data.string.data, "rightbelow") == 0) {
+ } else if (strcmp(mods->split.data, "belowright") == 0
+ || strcmp(mods->split.data, "rightbelow") == 0) {
cmdinfo.cmdmod.cmod_split |= WSP_BELOW;
- } else if (strcmp(mods.split.data.string.data, "topleft") == 0) {
+ } else if (strcmp(mods->split.data, "topleft") == 0) {
cmdinfo.cmdmod.cmod_split |= WSP_TOP;
- } else if (strcmp(mods.split.data.string.data, "botright") == 0) {
+ } else if (strcmp(mods->split.data, "botright") == 0) {
cmdinfo.cmdmod.cmod_split |= WSP_BOT;
} else {
VALIDATE_S(false, "mods.split", "", {
@@ -662,20 +609,25 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
}
}
- OBJ_TO_CMOD_FLAG(CMOD_SILENT, mods.silent, false, "'mods.silent'");
- OBJ_TO_CMOD_FLAG(CMOD_ERRSILENT, mods.emsg_silent, false, "'mods.emsg_silent'");
- OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods.unsilent, false, "'mods.unsilent'");
- OBJ_TO_CMOD_FLAG(CMOD_SANDBOX, mods.sandbox, false, "'mods.sandbox'");
- OBJ_TO_CMOD_FLAG(CMOD_NOAUTOCMD, mods.noautocmd, false, "'mods.noautocmd'");
- OBJ_TO_CMOD_FLAG(CMOD_BROWSE, mods.browse, false, "'mods.browse'");
- OBJ_TO_CMOD_FLAG(CMOD_CONFIRM, mods.confirm, false, "'mods.confirm'");
- OBJ_TO_CMOD_FLAG(CMOD_HIDE, mods.hide, false, "'mods.hide'");
- OBJ_TO_CMOD_FLAG(CMOD_KEEPALT, mods.keepalt, false, "'mods.keepalt'");
- OBJ_TO_CMOD_FLAG(CMOD_KEEPJUMPS, mods.keepjumps, false, "'mods.keepjumps'");
- OBJ_TO_CMOD_FLAG(CMOD_KEEPMARKS, mods.keepmarks, false, "'mods.keepmarks'");
- OBJ_TO_CMOD_FLAG(CMOD_KEEPPATTERNS, mods.keeppatterns, false, "'mods.keeppatterns'");
- OBJ_TO_CMOD_FLAG(CMOD_LOCKMARKS, mods.lockmarks, false, "'mods.lockmarks'");
- OBJ_TO_CMOD_FLAG(CMOD_NOSWAPFILE, mods.noswapfile, false, "'mods.noswapfile'");
+#define OBJ_TO_CMOD_FLAG(flag, value) \
+ if (value) { \
+ cmdinfo.cmdmod.cmod_flags |= (flag); \
+ }
+
+ OBJ_TO_CMOD_FLAG(CMOD_SILENT, mods->silent);
+ OBJ_TO_CMOD_FLAG(CMOD_ERRSILENT, mods->emsg_silent);
+ OBJ_TO_CMOD_FLAG(CMOD_UNSILENT, mods->unsilent);
+ OBJ_TO_CMOD_FLAG(CMOD_SANDBOX, mods->sandbox);
+ OBJ_TO_CMOD_FLAG(CMOD_NOAUTOCMD, mods->noautocmd);
+ OBJ_TO_CMOD_FLAG(CMOD_BROWSE, mods->browse);
+ OBJ_TO_CMOD_FLAG(CMOD_CONFIRM, mods->confirm);
+ OBJ_TO_CMOD_FLAG(CMOD_HIDE, mods->hide);
+ OBJ_TO_CMOD_FLAG(CMOD_KEEPALT, mods->keepalt);
+ OBJ_TO_CMOD_FLAG(CMOD_KEEPJUMPS, mods->keepjumps);
+ OBJ_TO_CMOD_FLAG(CMOD_KEEPMARKS, mods->keepmarks);
+ OBJ_TO_CMOD_FLAG(CMOD_KEEPPATTERNS, mods->keeppatterns);
+ OBJ_TO_CMOD_FLAG(CMOD_LOCKMARKS, mods->lockmarks);
+ OBJ_TO_CMOD_FLAG(CMOD_NOSWAPFILE, mods->noswapfile);
if (cmdinfo.cmdmod.cmod_flags & CMOD_ERRSILENT) {
// CMOD_ERRSILENT must imply CMOD_SILENT, otherwise apply_cmdmod() and undo_cmdmod() won't
@@ -699,13 +651,13 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
garray_T * const save_capture_ga = capture_ga;
const int save_msg_col = msg_col;
- if (output) {
+ if (opts->output) {
ga_init(&capture_local, 1, 80);
capture_ga = &capture_local;
}
TRY_WRAP(err, {
- if (output) {
+ if (opts->output) {
msg_silent++;
msg_col = 0; // prevent leading spaces
}
@@ -714,7 +666,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
execute_cmd(&ea, &cmdinfo, false);
});
- if (output) {
+ if (opts->output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
// Put msg_col back where it was, since nothing should have been written.
@@ -726,7 +678,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
goto clear_ga;
}
- if (output && capture_local.ga_len > 1) {
+ if (opts->output && capture_local.ga_len > 1) {
retv = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
@@ -740,7 +692,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
goto end;
}
clear_ga:
- if (output) {
+ if (opts->output) {
ga_clear(&capture_local);
}
end:
@@ -1037,7 +989,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
name.data, {
goto err;
});
- VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), "%s",
+ VALIDATE((!HAS_KEY(opts, user_command, range) || !HAS_KEY(opts, user_command, count)), "%s",
"Cannot use both 'range' and 'count'", {
goto err;
});
@@ -1075,13 +1027,14 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
goto err;
});
}
- } else if (HAS_KEY(opts->nargs)) {
+ } else if (HAS_KEY(opts, user_command, nargs)) {
VALIDATE_S(false, "nargs", "", {
goto err;
});
}
- VALIDATE((!HAS_KEY(opts->complete) || argt), "%s", "'complete' used without 'nargs'", {
+ VALIDATE((!HAS_KEY(opts, user_command, complete) || argt),
+ "%s", "'complete' used without 'nargs'", {
goto err;
});
@@ -1101,7 +1054,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
argt |= EX_RANGE | EX_ZEROR;
def = opts->range.data.integer;
addr_type_arg = ADDR_LINES;
- } else if (HAS_KEY(opts->range)) {
+ } else if (HAS_KEY(opts, user_command, range)) {
VALIDATE_S(false, "range", "", {
goto err;
});
@@ -1117,13 +1070,13 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
argt |= EX_COUNT | EX_ZEROR | EX_RANGE;
addr_type_arg = ADDR_OTHER;
def = opts->count.data.integer;
- } else if (HAS_KEY(opts->count)) {
+ } else if (HAS_KEY(opts, user_command, count)) {
VALIDATE_S(false, "count", "", {
goto err;
});
}
- if (HAS_KEY(opts->addr)) {
+ if (HAS_KEY(opts, user_command, addr)) {
VALIDATE_T("addr", kObjectTypeString, opts->addr.type, {
goto err;
});
@@ -1139,31 +1092,23 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
}
}
- if (api_object_to_bool(opts->bang, "bang", false, err)) {
+ if (opts->bang) {
argt |= EX_BANG;
- } else if (ERROR_SET(err)) {
- goto err;
}
- if (api_object_to_bool(opts->bar, "bar", false, err)) {
+ if (opts->bar) {
argt |= EX_TRLBAR;
- } else if (ERROR_SET(err)) {
- goto err;
}
- if (api_object_to_bool(opts->register_, "register", false, err)) {
+ if (opts->register_) {
argt |= EX_REGSTR;
- } else if (ERROR_SET(err)) {
- goto err;
}
- if (api_object_to_bool(opts->keepscript, "keepscript", false, err)) {
+ if (opts->keepscript) {
argt |= EX_KEEPSCRIPT;
- } else if (ERROR_SET(err)) {
- goto err;
}
- bool force = api_object_to_bool(opts->force, "force", true, err);
+ bool force = GET_BOOL_OR_TRUE(opts, user_command, force);
if (ERROR_SET(err)) {
goto err;
}
@@ -1178,13 +1123,13 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict(
"complete", opts->complete.data.string.data, {
goto err;
});
- } else if (HAS_KEY(opts->complete)) {
+ } else if (HAS_KEY(opts, user_command, complete)) {
VALIDATE_EXP(false, "complete", "Function or String", NULL, {
goto err;
});
}
- if (HAS_KEY(opts->preview)) {
+ if (HAS_KEY(opts, user_command, preview)) {
VALIDATE_T("preview", kObjectTypeLuaRef, opts->preview.type, {
goto err;
});
@@ -1254,13 +1199,12 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error
FUNC_API_SINCE(4)
{
bool global = (buffer == -1);
- bool builtin = api_object_to_bool(opts->builtin, "builtin", false, err);
if (ERROR_SET(err)) {
return (Dictionary)ARRAY_DICT_INIT;
}
if (global) {
- if (builtin) {
+ if (opts->builtin) {
api_set_error(err, kErrorTypeValidation, "builtin=true not implemented");
return (Dictionary)ARRAY_DICT_INIT;
}
@@ -1268,7 +1212,7 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error
}
buf_T *buf = find_buffer_by_handle(buffer, err);
- if (builtin || !buf) {
+ if (opts->builtin || !buf) {
return (Dictionary)ARRAY_DICT_INIT;
}
return commands_array(buf);
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 2e3ebd7c39..f5a77ece7e 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -35,8 +35,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
FUNC_API_SINCE(7)
FUNC_API_DEPRECATED_SINCE(11)
{
- Dict(exec_opts) opts = { 0 };
- opts.output = BOOLEAN_OBJ(output);
+ Dict(exec_opts) opts = { .output = output };
return exec_impl(channel_id, src, &opts, err);
}
@@ -46,8 +45,7 @@ String nvim_command_output(uint64_t channel_id, String command, Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(7)
{
- Dict(exec_opts) opts = { 0 };
- opts.output = BOOLEAN_OBJ(true);
+ Dict(exec_opts) opts = { .output = true };
return exec_impl(channel_id, command, &opts, err);
}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index d254373eb0..8a60d81649 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -10,6 +10,7 @@
#include "lauxlib.h"
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/buffer_defs.h"
@@ -581,40 +582,32 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
});
uint32_t id = 0;
- if (HAS_KEY(opts->id)) {
- VALIDATE_EXP((opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0),
- "id", "positive Integer", NULL, {
+ if (HAS_KEY(opts, set_extmark, id)) {
+ VALIDATE_EXP((opts->id > 0), "id", "positive Integer", NULL, {
goto error;
});
- id = (uint32_t)opts->id.data.integer;
+ id = (uint32_t)opts->id;
}
int line2 = -1;
+ bool did_end_line = false;
// For backward compatibility we support "end_line" as an alias for "end_row"
- if (HAS_KEY(opts->end_line)) {
- VALIDATE(!HAS_KEY(opts->end_row), "%s", "cannot use both 'end_row' and 'end_line'", {
+ if (HAS_KEY(opts, set_extmark, end_line)) {
+ VALIDATE(!HAS_KEY(opts, set_extmark, end_row),
+ "%s", "cannot use both 'end_row' and 'end_line'", {
goto error;
});
- opts->end_row = opts->end_line;
- }
-#define OPTION_TO_BOOL(target, name, val) \
- target = api_object_to_bool(opts->name, #name, val, err); \
- if (ERROR_SET(err)) { \
- goto error; \
+ opts->end_row = opts->end_line;
+ did_end_line = true;
}
- bool strict = true;
- OPTION_TO_BOOL(strict, strict, true);
-
- if (HAS_KEY(opts->end_row)) {
- VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, {
- goto error;
- });
+ bool strict = GET_BOOL_OR_TRUE(opts, set_extmark, strict);
- Integer val = opts->end_row.data.integer;
+ if (HAS_KEY(opts, set_extmark, end_row) || did_end_line) {
+ Integer val = opts->end_row;
VALIDATE_RANGE((val >= 0 && !(val > buf->b_ml.ml_line_count && strict)), "end_row", {
goto error;
});
@@ -622,12 +615,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
colnr_T col2 = -1;
- if (HAS_KEY(opts->end_col)) {
- VALIDATE_T("end_col", kObjectTypeInteger, opts->end_col.type, {
- goto error;
- });
-
- Integer val = opts->end_col.data.integer;
+ if (HAS_KEY(opts, set_extmark, end_col)) {
+ Integer val = opts->end_col;
VALIDATE_RANGE((val >= 0 && val <= MAXCOL), "end_col", {
goto error;
});
@@ -636,6 +625,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
// uncrustify:off
+ // TODO(bfredl): keyset type alias for hl_group? (nil|int|string)
struct {
const char *name;
Object *opt;
@@ -652,7 +642,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
// uncrustify:on
for (int j = 0; hls[j].name && hls[j].dest; j++) {
- if (HAS_KEY(*hls[j].opt)) {
+ if (hls[j].opt->type != kObjectTypeNil) {
*hls[j].dest = object_to_hl_id(*hls[j].opt, hls[j].name, err);
if (ERROR_SET(err)) {
goto error;
@@ -661,12 +651,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
- if (HAS_KEY(opts->conceal)) {
- VALIDATE_T("conceal", kObjectTypeString, opts->conceal.type, {
- goto error;
- });
-
- String c = opts->conceal.data.string;
+ if (HAS_KEY(opts, set_extmark, conceal)) {
+ String c = opts->conceal;
decor.conceal = true;
if (c.size) {
decor.conceal_char = utf_ptr2char(c.data);
@@ -674,25 +660,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
has_decor = true;
}
- if (HAS_KEY(opts->virt_text)) {
- VALIDATE_T("virt_text", kObjectTypeArray, opts->virt_text.type, {
- goto error;
- });
-
- decor.virt_text = parse_virt_text(opts->virt_text.data.array, err,
- &decor.virt_text_width);
+ if (HAS_KEY(opts, set_extmark, virt_text)) {
+ decor.virt_text = parse_virt_text(opts->virt_text, err, &decor.virt_text_width);
has_decor = true;
if (ERROR_SET(err)) {
goto error;
}
}
- if (HAS_KEY(opts->virt_text_pos)) {
- VALIDATE_T("virt_text_pos", kObjectTypeString, opts->virt_text_pos.type, {
- goto error;
- });
-
- String str = opts->virt_text_pos.data.string;
+ if (HAS_KEY(opts, set_extmark, virt_text_pos)) {
+ String str = opts->virt_text_pos;
if (strequal("eol", str.data)) {
decor.virt_text_pos = kVTEndOfLine;
} else if (strequal("overlay", str.data)) {
@@ -708,24 +685,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
- if (HAS_KEY(opts->virt_text_win_col)) {
- VALIDATE_T("virt_text_win_col", kObjectTypeInteger, opts->virt_text_win_col.type, {
- goto error;
- });
-
- decor.col = (int)opts->virt_text_win_col.data.integer;
+ if (HAS_KEY(opts, set_extmark, virt_text_win_col)) {
+ decor.col = (int)opts->virt_text_win_col;
decor.virt_text_pos = kVTWinCol;
}
- OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false);
- OPTION_TO_BOOL(decor.hl_eol, hl_eol, false);
+ decor.hl_eol = opts->hl_eol;
+ decor.virt_text_hide = opts->virt_text_hide;
- if (HAS_KEY(opts->hl_mode)) {
- VALIDATE_T("hl_mode", kObjectTypeString, opts->hl_mode.type, {
- goto error;
- });
-
- String str = opts->hl_mode.data.string;
+ if (HAS_KEY(opts, set_extmark, hl_mode)) {
+ String str = opts->hl_mode;
if (strequal("replace", str.data)) {
decor.hl_mode = kHlModeReplace;
} else if (strequal("combine", str.data)) {
@@ -744,15 +713,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
- bool virt_lines_leftcol = false;
- OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false);
-
- if (HAS_KEY(opts->virt_lines)) {
- VALIDATE_T("virt_lines", kObjectTypeArray, opts->virt_lines.type, {
- goto error;
- });
+ bool virt_lines_leftcol = opts->virt_lines_leftcol;
- Array a = opts->virt_lines.data.array;
+ if (HAS_KEY(opts, set_extmark, virt_lines)) {
+ Array a = opts->virt_lines;
for (size_t j = 0; j < a.size; j++) {
VALIDATE_T("virt_text_line", kObjectTypeArray, a.items[j].type, {
goto error;
@@ -767,61 +731,44 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
}
- OPTION_TO_BOOL(decor.virt_lines_above, virt_lines_above, false);
-
- if (HAS_KEY(opts->priority)) {
- VALIDATE_T("priority", kObjectTypeInteger, opts->priority.type, {
- goto error;
- });
-
- Integer val = opts->priority.data.integer;
+ decor.virt_lines_above = opts->virt_lines_above;
- VALIDATE_RANGE((val >= 0 && val <= UINT16_MAX), "priority", {
+ if (HAS_KEY(opts, set_extmark, priority)) {
+ VALIDATE_RANGE((opts->priority >= 0 && opts->priority <= UINT16_MAX), "priority", {
goto error;
});
- decor.priority = (DecorPriority)val;
+ decor.priority = (DecorPriority)opts->priority;
}
- if (HAS_KEY(opts->sign_text)) {
- VALIDATE_T("sign_text", kObjectTypeString, opts->sign_text.type, {
- goto error;
- });
-
- VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data.string.data),
+ if (HAS_KEY(opts, set_extmark, sign_text)) {
+ VALIDATE_S(init_sign_text(&decor.sign_text, opts->sign_text.data),
"sign_text", "", {
goto error;
});
has_decor = true;
}
- bool right_gravity = true;
- OPTION_TO_BOOL(right_gravity, right_gravity, true);
+ bool right_gravity = GET_BOOL_OR_TRUE(opts, set_extmark, right_gravity);
// Only error out if they try to set end_right_gravity without
// setting end_col or end_row
- VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)),
+ VALIDATE(!(line2 == -1 && col2 == -1 && HAS_KEY(opts, set_extmark, end_right_gravity)),
"%s", "cannot set end_right_gravity without end_row or end_col", {
goto error;
});
- bool end_right_gravity = false;
- OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false);
+ bool end_right_gravity = opts->end_right_gravity;
size_t len = 0;
- bool ephemeral = false;
- OPTION_TO_BOOL(ephemeral, ephemeral, false);
-
- if (!HAS_KEY(opts->spell)) {
+ if (!HAS_KEY(opts, set_extmark, spell)) {
decor.spell = kNone;
} else {
- bool spell = false;
- OPTION_TO_BOOL(spell, spell, false);
- decor.spell = spell ? kTrue : kFalse;
+ decor.spell = opts->spell ? kTrue : kFalse;
has_decor = true;
}
- OPTION_TO_BOOL(decor.ui_watched, ui_watched, false);
+ decor.ui_watched = opts->ui_watched;
if (decor.ui_watched) {
has_decor = true;
}
@@ -836,7 +783,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
});
line = buf->b_ml.ml_line_count;
} else if (line < buf->b_ml.ml_line_count) {
- len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false));
+ len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1, false));
}
if (col == -1) {
@@ -854,7 +801,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
if (col2 >= 0) {
if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
- len = ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line2 + 1, false));
+ len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line2 + 1, false));
} else if (line2 == buf->b_ml.ml_line_count) {
// We are trying to add an extmark past final newline
len = 0;
@@ -873,10 +820,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
// TODO(bfredl): synergize these two branches even more
- if (ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
+ if (opts->ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id);
} else {
- if (ephemeral) {
+ if (opts->ephemeral) {
api_set_error(err, kErrorTypeException, "not yet implemented");
goto error;
}
@@ -1107,7 +1054,7 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *
struct {
const char *name;
- Object *source;
+ LuaRef *source;
LuaRef *dest;
} cbs[] = {
{ "on_start", &opts->on_start, &p->redraw_start },
@@ -1121,25 +1068,18 @@ void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *
};
for (size_t i = 0; cbs[i].source && cbs[i].dest && cbs[i].name; i++) {
- Object *v = cbs[i].source;
- if (v->type == kObjectTypeNil) {
+ LuaRef *v = cbs[i].source;
+ if (*v <= 0) {
continue;
}
- VALIDATE_T(cbs[i].name, kObjectTypeLuaRef, v->type, {
- goto error;
- });
-
- *(cbs[i].dest) = v->data.luaref;
- v->data.luaref = LUA_NOREF;
+ *(cbs[i].dest) = *v;
+ *v = LUA_NOREF;
}
p->active = true;
p->hl_valid++;
p->hl_cached = false;
- return;
-error:
- decor_provider_clear(p);
}
/// Gets the line and column of an |extmark|.
diff --git a/src/nvim/api/keysets.h b/src/nvim/api/keysets.h
index e08186161a..a47e278cad 100644
--- a/src/nvim/api/keysets.h
+++ b/src/nvim/api/keysets.h
@@ -4,135 +4,144 @@
#include "nvim/api/private/defs.h"
typedef struct {
- Object types;
+ OptionalKeys is_set__context_;
+ Array types;
} Dict(context);
typedef struct {
- Object on_start;
- Object on_buf;
- Object on_win;
- Object on_line;
- Object on_end;
- Object _on_hl_def;
- Object _on_spell_nav;
+ OptionalKeys is_set__set_decoration_provider_;
+ LuaRef on_start;
+ LuaRef on_buf;
+ LuaRef on_win;
+ LuaRef on_line;
+ LuaRef on_end;
+ LuaRef _on_hl_def;
+ LuaRef _on_spell_nav;
} Dict(set_decoration_provider);
typedef struct {
- Object id;
- Object end_line;
- Object end_row;
- Object end_col;
+ OptionalKeys is_set__set_extmark_;
+ Integer id;
+ Integer end_line;
+ Integer end_row;
+ Integer end_col;
Object hl_group;
- Object virt_text;
- Object virt_text_pos;
- Object virt_text_win_col;
- Object virt_text_hide;
- Object hl_eol;
- Object hl_mode;
- Object ephemeral;
- Object priority;
- Object right_gravity;
- Object end_right_gravity;
- Object virt_lines;
- Object virt_lines_above;
- Object virt_lines_leftcol;
- Object strict;
- Object sign_text;
+ Array virt_text;
+ String virt_text_pos;
+ Integer virt_text_win_col;
+ Boolean virt_text_hide;
+ Boolean hl_eol;
+ String hl_mode;
+ Boolean ephemeral;
+ Integer priority;
+ Boolean right_gravity;
+ Boolean end_right_gravity;
+ Array virt_lines;
+ Boolean virt_lines_above;
+ Boolean virt_lines_leftcol;
+ Boolean strict;
+ String sign_text;
Object sign_hl_group;
Object number_hl_group;
Object line_hl_group;
Object cursorline_hl_group;
- Object conceal;
- Object spell;
- Object ui_watched;
+ String conceal;
+ Boolean spell;
+ Boolean ui_watched;
} Dict(set_extmark);
typedef struct {
- Object noremap;
- Object nowait;
- Object silent;
- Object script;
- Object expr;
- Object unique;
- Object callback;
- Object desc;
- Object replace_keycodes;
+ OptionalKeys is_set__keymap_;
+ Boolean noremap;
+ Boolean nowait;
+ Boolean silent;
+ Boolean script;
+ Boolean expr;
+ Boolean unique;
+ LuaRef callback;
+ String desc;
+ Boolean replace_keycodes;
} Dict(keymap);
typedef struct {
- Object builtin;
+ Boolean builtin;
} Dict(get_commands);
typedef struct {
+ OptionalKeys is_set__user_command_;
Object addr;
- Object bang;
- Object bar;
+ Boolean bang;
+ Boolean bar;
Object complete;
Object count;
Object desc;
- Object force;
- Object keepscript;
+ Boolean force;
+ Boolean keepscript;
Object nargs;
Object preview;
Object range;
- Object register_;
+ Boolean register_;
} Dict(user_command);
typedef struct {
- Object row;
- Object col;
- Object width;
- Object height;
- Object anchor;
- Object relative;
- Object win;
- Object bufpos;
- Object external;
- Object focusable;
- Object zindex;
+ OptionalKeys is_set__float_config_;
+ Float row;
+ Float col;
+ Integer width;
+ Integer height;
+ String anchor;
+ String relative;
+ Window win;
+ Array bufpos;
+ Boolean external;
+ Boolean focusable;
+ Integer zindex;
Object border;
Object title;
- Object title_pos;
- Object style;
- Object noautocmd;
+ String title_pos;
+ String style;
+ Boolean noautocmd;
} Dict(float_config);
typedef struct {
- Object is_lua;
- Object do_source;
+ Boolean is_lua;
+ Boolean do_source;
} Dict(runtime);
typedef struct {
- Object winid;
- Object maxwidth;
- Object fillchar;
- Object highlights;
- Object use_winbar;
- Object use_tabline;
- Object use_statuscol_lnum;
+ OptionalKeys is_set__eval_statusline_;
+ Window winid;
+ Integer maxwidth;
+ String fillchar;
+ Boolean highlights;
+ Boolean use_winbar;
+ Boolean use_tabline;
+ Integer use_statuscol_lnum;
} Dict(eval_statusline);
typedef struct {
- Object scope;
- Object win;
- Object buf;
- Object filetype;
+ OptionalKeys is_set__option_;
+ String scope;
+ Window win;
+ Buffer buf;
+ String filetype;
} Dict(option);
typedef struct {
- Object bold;
- Object standout;
- Object strikethrough;
- Object underline;
- Object undercurl;
- Object underdouble;
- Object underdotted;
- Object underdashed;
- Object italic;
- Object reverse;
- Object altfont;
- Object nocombine;
- Object default_;
+ OptionalKeys is_set__highlight_;
+ Boolean bold;
+ Boolean standout;
+ Boolean strikethrough;
+ Boolean underline;
+ Boolean undercurl;
+ Boolean underdouble;
+ Boolean underdotted;
+ Boolean underdashed;
+ Boolean italic;
+ Boolean reverse;
+ Boolean altfont;
+ Boolean nocombine;
+ Boolean default_;
Object cterm;
Object foreground;
Object fg;
@@ -144,67 +153,73 @@ typedef struct {
Object sp;
Object link;
Object global_link;
- Object fallback;
- Object blend;
- Object fg_indexed;
- Object bg_indexed;
+ Boolean fallback;
+ Integer blend;
+ Boolean fg_indexed;
+ Boolean bg_indexed;
} Dict(highlight);
typedef struct {
- Object bold;
- Object standout;
- Object strikethrough;
- Object underline;
- Object undercurl;
- Object underdouble;
- Object underdotted;
- Object underdashed;
- Object italic;
- Object reverse;
- Object altfont;
- Object nocombine;
+ Boolean bold;
+ Boolean standout;
+ Boolean strikethrough;
+ Boolean underline;
+ Boolean undercurl;
+ Boolean underdouble;
+ Boolean underdotted;
+ Boolean underdashed;
+ Boolean italic;
+ Boolean reverse;
+ Boolean altfont;
+ Boolean nocombine;
} Dict(highlight_cterm);
typedef struct {
- Object id;
- Object name;
- Object link;
+ OptionalKeys is_set__get_highlight_;
+ Integer id;
+ String name;
+ Boolean link;
} Dict(get_highlight);
typedef struct {
- Object start_row;
- Object end_row;
- Object start_vcol;
- Object end_vcol;
+ OptionalKeys is_set__win_text_height_;
+ Integer start_row;
+ Integer end_row;
+ Integer start_vcol;
+ Integer end_vcol;
} Dict(win_text_height);
typedef struct {
- Object buffer;
+ OptionalKeys is_set__clear_autocmds_;
+ Buffer buffer;
Object event;
Object group;
Object pattern;
} Dict(clear_autocmds);
typedef struct {
- Object buffer;
+ OptionalKeys is_set__create_autocmd_;
+ Buffer buffer;
Object callback;
- Object command;
- Object desc;
+ String command;
+ String desc;
Object group;
- Object nested;
- Object once;
+ Boolean nested;
+ Boolean once;
Object pattern;
} Dict(create_autocmd);
typedef struct {
- Object buffer;
+ OptionalKeys is_set__exec_autocmds_;
+ Buffer buffer;
Object group;
- Object modeline;
+ Boolean modeline;
Object pattern;
Object data;
} Dict(exec_autocmds);
typedef struct {
+ OptionalKeys is_set__get_autocmds_;
Object event;
Object group;
Object pattern;
@@ -216,62 +231,66 @@ typedef struct {
} Dict(create_augroup);
typedef struct {
- Object cmd;
- Object range;
- Object count;
- Object reg;
- Object bang;
- Object args;
- Object magic;
- Object mods;
+ OptionalKeys is_set__cmd_;
+ String cmd;
+ Array range;
+ Integer count;
+ String reg;
+ Boolean bang;
+ Array args;
+ Dictionary magic;
+ Dictionary mods;
Object nargs;
Object addr;
Object nextcmd;
} Dict(cmd);
typedef struct {
- Object file;
- Object bar;
+ OptionalKeys is_set__cmd_magic_;
+ Boolean file;
+ Boolean bar;
} Dict(cmd_magic);
typedef struct {
- Object silent;
- Object emsg_silent;
- Object unsilent;
- Object filter;
- Object sandbox;
- Object noautocmd;
- Object browse;
- Object confirm;
- Object hide;
- Object horizontal;
- Object keepalt;
- Object keepjumps;
- Object keepmarks;
- Object keeppatterns;
- Object lockmarks;
- Object noswapfile;
- Object tab;
- Object verbose;
- Object vertical;
- Object split;
+ OptionalKeys is_set__cmd_mods_;
+ Boolean silent;
+ Boolean emsg_silent;
+ Boolean unsilent;
+ Dictionary filter;
+ Boolean sandbox;
+ Boolean noautocmd;
+ Boolean browse;
+ Boolean confirm;
+ Boolean hide;
+ Boolean horizontal;
+ Boolean keepalt;
+ Boolean keepjumps;
+ Boolean keepmarks;
+ Boolean keeppatterns;
+ Boolean lockmarks;
+ Boolean noswapfile;
+ Integer tab;
+ Integer verbose;
+ Boolean vertical;
+ String split;
} Dict(cmd_mods);
typedef struct {
- Object pattern;
- Object force;
+ OptionalKeys is_set__cmd_mods_filter_;
+ String pattern;
+ Boolean force;
} Dict(cmd_mods_filter);
typedef struct {
- Object output;
+ Boolean output;
} Dict(cmd_opts);
typedef struct {
- Object verbose;
+ Boolean verbose;
} Dict(echo_opts);
typedef struct {
- Object output;
+ Boolean output;
} Dict(exec_opts);
#endif // NVIM_API_KEYSETS_H
diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c
index 3d42f60940..e33cb72e8d 100644
--- a/src/nvim/api/options.c
+++ b/src/nvim/api/options.c
@@ -8,6 +8,7 @@
#include "nvim/api/options.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/autocmd.h"
@@ -26,14 +27,11 @@
static int validate_option_value_args(Dict(option) *opts, char *name, int *scope, int *opt_type,
void **from, char **filetype, Error *err)
{
- if (HAS_KEY(opts->scope)) {
- VALIDATE_T("scope", kObjectTypeString, opts->scope.type, {
- return FAIL;
- });
-
- if (!strcmp(opts->scope.data.string.data, "local")) {
+#define HAS_KEY_X(d, v) HAS_KEY(d, option, v)
+ if (HAS_KEY_X(opts, scope)) {
+ if (!strcmp(opts->scope.data, "local")) {
*scope = OPT_LOCAL;
- } else if (!strcmp(opts->scope.data.string.data, "global")) {
+ } else if (!strcmp(opts->scope.data, "global")) {
*scope = OPT_GLOBAL;
} else {
VALIDATE_EXP(false, "scope", "'local' or 'global'", NULL, {
@@ -44,51 +42,40 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope
*opt_type = SREQ_GLOBAL;
- if (filetype != NULL && HAS_KEY(opts->filetype)) {
- VALIDATE_T("scope", kObjectTypeString, opts->filetype.type, {
- return FAIL;
- });
-
- *filetype = opts->filetype.data.string.data;
+ if (filetype != NULL && HAS_KEY_X(opts, filetype)) {
+ *filetype = opts->filetype.data;
}
- if (HAS_KEY(opts->win)) {
- VALIDATE_T_HANDLE("win", kObjectTypeWindow, opts->win.type, {
- return FAIL;
- });
-
+ if (HAS_KEY_X(opts, win)) {
*opt_type = SREQ_WIN;
- *from = find_window_by_handle((int)opts->win.data.integer, err);
+ *from = find_window_by_handle(opts->win, err);
if (ERROR_SET(err)) {
return FAIL;
}
}
- if (HAS_KEY(opts->buf)) {
- VALIDATE_T_HANDLE("buf", kObjectTypeBuffer, opts->buf.type, {
- return FAIL;
- });
-
+ if (HAS_KEY_X(opts, buf)) {
*scope = OPT_LOCAL;
*opt_type = SREQ_BUF;
- *from = find_buffer_by_handle((int)opts->buf.data.integer, err);
+ *from = find_buffer_by_handle(opts->buf, err);
if (ERROR_SET(err)) {
return FAIL;
}
}
- VALIDATE((!HAS_KEY(opts->filetype)
- || !(HAS_KEY(opts->buf) || HAS_KEY(opts->scope) || HAS_KEY(opts->win))),
+ VALIDATE((!HAS_KEY_X(opts, filetype)
+ || !(HAS_KEY_X(opts, buf) || HAS_KEY_X(opts, scope) || HAS_KEY_X(opts, win))),
"%s", "cannot use 'filetype' with 'scope', 'buf' or 'win'", {
return FAIL;
});
- VALIDATE((!HAS_KEY(opts->scope) || !HAS_KEY(opts->buf)), "%s",
+ VALIDATE((!HAS_KEY_X(opts, scope) || !HAS_KEY_X(opts, buf)), "%s",
"cannot use both 'scope' and 'buf'", {
return FAIL;
});
- VALIDATE((!HAS_KEY(opts->win) || !HAS_KEY(opts->buf)), "%s", "cannot use both 'buf' and 'win'", {
+ VALIDATE((!HAS_KEY_X(opts, win) || !HAS_KEY_X(opts, buf)),
+ "%s", "cannot use both 'buf' and 'win'", {
return FAIL;
});
@@ -111,6 +98,7 @@ static int validate_option_value_args(Dict(option) *opts, char *name, int *scope
}
return OK;
+#undef HAS_KEY_X
}
/// Create a dummy buffer and run the FileType autocmd on it.
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index b1b9e383b0..b467ce75a9 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -124,10 +124,20 @@ struct key_value_pair {
Object value;
};
-typedef Object *(*field_hash)(void *retval, const char *str, size_t len);
+typedef uint64_t OptionalKeys;
+
+// this is the prefix of all keysets with optional keys
+typedef struct {
+ OptionalKeys is_set_;
+} OptKeySet;
+
typedef struct {
char *str;
size_t ptr_off;
+ ObjectType type; // kObjectTypeNil == untyped
+ int opt_index;
} KeySetLink;
+typedef KeySetLink *(*FieldHashfn)(const char *str, size_t len);
+
#endif // NVIM_API_PRIVATE_DEFS_H
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d0c8ab4dd4..bbc87422d0 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -16,6 +16,7 @@
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/private/validate.h"
#include "nvim/ascii.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
@@ -915,17 +916,84 @@ free_exit:
return (HlMessage)KV_INITIAL_VALUE;
}
-bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err)
+// see also nlua_pop_keydict for the lua specific implementation
+bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error *err)
{
for (size_t i = 0; i < dict.size; i++) {
String k = dict.items[i].key;
- Object *field = hashy(rv, k.data, k.size);
+ KeySetLink *field = hashy(k.data, k.size);
if (!field) {
api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s'", (int)k.size, k.data);
return false;
}
- *field = dict.items[i].value;
+ if (field->opt_index >= 0) {
+ OptKeySet *ks = (OptKeySet *)retval;
+ ks->is_set_ |= (1ULL << field->opt_index);
+ }
+
+ char *mem = ((char *)retval + field->ptr_off);
+ Object *value = &dict.items[i].value;
+ if (field->type == kObjectTypeNil) {
+ *(Object *)mem = *value;
+ } else if (field->type == kObjectTypeInteger) {
+ VALIDATE_T(field->str, kObjectTypeInteger, value->type, {
+ return false;
+ });
+ *(Integer *)mem = value->data.integer;
+ } else if (field->type == kObjectTypeFloat) {
+ Float *val = (Float *)mem;
+ if (value->type == kObjectTypeInteger) {
+ *val = (Float)value->data.integer;
+ } else {
+ VALIDATE_T(field->str, kObjectTypeFloat, value->type, {
+ return false;
+ });
+ *val = value->data.floating;
+ }
+ } else if (field->type == kObjectTypeBoolean) {
+ // caller should check HAS_KEY to override the nil behavior, or GET_BOOL_OR_TRUE
+ // to directly use true when nil
+ *(Boolean *)mem = api_object_to_bool(*value, field->str, false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+ } else if (field->type == kObjectTypeString) {
+ VALIDATE_T(field->str, kObjectTypeString, value->type, {
+ return false;
+ });
+ *(String *)mem = value->data.string;
+ } else if (field->type == kObjectTypeArray) {
+ VALIDATE_T(field->str, kObjectTypeArray, value->type, {
+ return false;
+ });
+ *(Array *)mem = value->data.array;
+ } else if (field->type == kObjectTypeDictionary) {
+ Dictionary *val = (Dictionary *)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;
+ } else {
+ api_err_exp(err, field->str, api_typename(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) {
+ *(handle_T *)mem = (handle_T)value->data.integer;
+ } else {
+ api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ return false;
+ }
+ } else if (field->type == kObjectTypeLuaRef) {
+ api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s' is only allowed from Lua",
+ (int)k.size, k.data);
+ return false;
+ } else {
+ abort();
+ }
}
return true;
@@ -934,7 +1002,18 @@ bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err
void api_free_keydict(void *dict, KeySetLink *table)
{
for (size_t i = 0; table[i].str; i++) {
- api_free_object(*(Object *)((char *)dict + table[i].ptr_off));
+ char *mem = ((char *)dict + table[i].ptr_off);
+ if (table[i].type == kObjectTypeNil) {
+ api_free_object(*(Object *)mem);
+ } else if (table[i].type == kObjectTypeString) {
+ api_free_string(*(String *)mem);
+ } else if (table[i].type == kObjectTypeArray) {
+ api_free_array(*(Array *)mem);
+ } else if (table[i].type == kObjectTypeDictionary) {
+ api_free_dictionary(*(Dictionary *)mem);
+ } else if (table[i].type == kObjectTypeLuaRef) {
+ api_free_luaref(*(LuaRef *)mem);
+ }
}
}
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index cb74c655cd..95e5cf67c8 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -63,8 +63,9 @@
#define NIL ((Object)OBJECT_INIT)
#define NULL_STRING ((String)STRING_INIT)
-// currently treat key=vim.NIL as if the key was missing
-#define HAS_KEY(o) ((o).type != kObjectTypeNil)
+#define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1 << KEYSET_OPTIDX_##typ##__##key)) != 0)
+
+#define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true)
#define PUT(dict, k, v) \
kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v }))
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b4a6fa718b..22fe69e447 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -558,16 +558,15 @@ ArrayOf(String) nvim__get_runtime(Array pat, Boolean all, Dict(runtime) *opts, E
FUNC_API_SINCE(8)
FUNC_API_FAST
{
- bool is_lua = api_object_to_bool(opts->is_lua, "is_lua", false, err);
- bool source = api_object_to_bool(opts->do_source, "do_source", false, err);
- VALIDATE((!source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback", {});
+ VALIDATE((!opts->do_source || nlua_is_deferred_safe()), "%s", "'do_source' used in fast callback",
+ {});
if (ERROR_SET(err)) {
return (Array)ARRAY_DICT_INIT;
}
- ArrayOf(String) res = runtime_get_named(is_lua, pat, all);
+ ArrayOf(String) res = runtime_get_named(opts->is_lua, pat, all);
- if (source) {
+ if (opts->do_source) {
for (size_t i = 0; i < res.size; i++) {
String name = res.items[i].data.string;
(void)do_source(name.data, false, DOSO_NONE, NULL);
@@ -718,15 +717,13 @@ void nvim_echo(Array chunks, Boolean history, Dict(echo_opts) *opts, Error *err)
goto error;
}
- bool verbose = api_object_to_bool(opts->verbose, "verbose", false, err);
-
- if (verbose) {
+ if (opts->verbose) {
verbose_enter();
}
msg_multiattr(hl_msg, history ? "echomsg" : "echo", history);
- if (verbose) {
+ if (opts->verbose) {
verbose_leave();
verbose_stop(); // flush now
}
@@ -1323,11 +1320,8 @@ Dictionary nvim_get_context(Dict(context) *opts, Error *err)
FUNC_API_SINCE(6)
{
Array types = ARRAY_DICT_INIT;
- if (HAS_KEY(opts->types)) {
- VALIDATE_T("types", kObjectTypeArray, opts->types.type, {
- return (Dictionary)ARRAY_DICT_INIT;
- });
- types = opts->types.data.array;
+ if (HAS_KEY(opts, context, types)) {
+ types = opts->types;
}
int int_types = types.size > 0 ? 0 : kCtxAll;
@@ -2091,12 +2085,8 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
int maxwidth;
int fillchar = 0;
- int use_bools = 0;
int statuscol_lnum = 0;
Window window = 0;
- bool use_winbar = false;
- bool use_tabline = false;
- bool highlights = false;
if (str.size < 2 || memcmp(str.data, "%!", 2) != 0) {
const char *const errmsg = check_stl_option(str.data);
@@ -2105,58 +2095,28 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
});
}
- if (HAS_KEY(opts->winid)) {
- VALIDATE_T("winid", kObjectTypeInteger, opts->winid.type, {
- return result;
- });
-
- window = (Window)opts->winid.data.integer;
+ if (HAS_KEY(opts, eval_statusline, winid)) {
+ window = opts->winid;
}
- if (HAS_KEY(opts->fillchar)) {
- VALIDATE_T("fillchar", kObjectTypeString, opts->fillchar.type, {
- return result;
- });
- VALIDATE_EXP((opts->fillchar.data.string.size != 0
- && ((size_t)utf_ptr2len(opts->fillchar.data.string.data)
- == opts->fillchar.data.string.size)),
+ if (HAS_KEY(opts, eval_statusline, fillchar)) {
+ VALIDATE_EXP((*opts->fillchar.data != 0
+ && ((size_t)utf_ptr2len(opts->fillchar.data) == opts->fillchar.size)),
"fillchar", "single character", NULL, {
return result;
});
- fillchar = utf_ptr2char(opts->fillchar.data.string.data);
+ fillchar = utf_ptr2char(opts->fillchar.data);
}
- if (HAS_KEY(opts->highlights)) {
- highlights = api_object_to_bool(opts->highlights, "highlights", false, err);
- if (ERROR_SET(err)) {
- return result;
- }
- }
- if (HAS_KEY(opts->use_winbar)) {
- use_winbar = api_object_to_bool(opts->use_winbar, "use_winbar", false, err);
- if (ERROR_SET(err)) {
- return result;
- }
- use_bools++;
- }
- if (HAS_KEY(opts->use_tabline)) {
- use_tabline = api_object_to_bool(opts->use_tabline, "use_tabline", false, err);
- if (ERROR_SET(err)) {
- return result;
- }
- use_bools++;
- }
+ int use_bools = (int)opts->use_winbar + (int)opts->use_tabline;
- win_T *wp = use_tabline ? curwin : find_window_by_handle(window, err);
+ win_T *wp = opts->use_tabline ? curwin : find_window_by_handle(window, err);
if (wp == NULL) {
api_set_error(err, kErrorTypeException, "unknown winid %d", window);
return result;
}
- if (HAS_KEY(opts->use_statuscol_lnum)) {
- VALIDATE_T("use_statuscol_lnum", kObjectTypeInteger, opts->use_statuscol_lnum.type, {
- return result;
- });
- statuscol_lnum = (int)opts->use_statuscol_lnum.data.integer;
+ if (HAS_KEY(opts, eval_statusline, use_statuscol_lnum)) {
+ statuscol_lnum = (int)opts->use_statuscol_lnum;
VALIDATE_RANGE(statuscol_lnum > 0 && statuscol_lnum <= wp->w_buffer->b_ml.ml_line_count,
"use_statuscol_lnum", {
return result;
@@ -2172,11 +2132,11 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
statuscol_T statuscol = { 0 };
SignTextAttrs sattrs[SIGN_SHOW_MAX] = { 0 };
- if (use_tabline) {
+ if (opts->use_tabline) {
fillchar = ' ';
} else {
if (fillchar == 0) {
- if (use_winbar) {
+ if (opts->use_winbar) {
fillchar = wp->w_p_fcs_chars.wbr;
} else {
int attr;
@@ -2220,15 +2180,12 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
}
}
- if (HAS_KEY(opts->maxwidth)) {
- VALIDATE_T("maxwidth", kObjectTypeInteger, opts->maxwidth.type, {
- return result;
- });
-
- maxwidth = (int)opts->maxwidth.data.integer;
+ if (HAS_KEY(opts, eval_statusline, maxwidth)) {
+ maxwidth = (int)opts->maxwidth;
} else {
maxwidth = statuscol_lnum ? win_col_off(wp)
- : (use_tabline || (!use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width;
+ : (opts->use_tabline
+ || (!opts->use_winbar && global_stl_height() > 0)) ? Columns : wp->w_width;
}
char buf[MAXPATHL];
@@ -2246,7 +2203,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
0,
fillchar,
maxwidth,
- highlights ? &hltab : NULL,
+ opts->highlights ? &hltab : NULL,
NULL,
statuscol_lnum ? &statuscol : NULL);
@@ -2255,7 +2212,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
// Restore original value of 'cursorbind'
wp->w_p_crb = p_crb_save;
- if (highlights) {
+ if (opts->highlights) {
Array hl_values = ARRAY_DICT_INIT;
const char *grpname;
char user_group[15]; // strlen("User") + strlen("2147483647") + NUL
@@ -2264,7 +2221,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
// add the default highlight at the beginning of the highlight list
if (hltab->start == NULL || (hltab->start - buf) != 0) {
Dictionary hl_info = ARRAY_DICT_INIT;
- grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id);
+ grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id);
PUT(hl_info, "start", INTEGER_OBJ(0));
PUT(hl_info, "group", CSTR_TO_OBJ(grpname));
@@ -2278,7 +2235,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
PUT(hl_info, "start", INTEGER_OBJ(sp->start - buf));
if (sp->userhl == 0) {
- grpname = get_default_stl_hl(use_tabline ? NULL : wp, use_winbar, stc_hl_id);
+ grpname = get_default_stl_hl(opts->use_tabline ? NULL : wp, opts->use_winbar, stc_hl_id);
} else if (sp->userhl < 0) {
grpname = syn_id2name(-sp->userhl);
} else {
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 8a598d86f0..4801562ad2 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -61,7 +61,7 @@ Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Er
return result;
}
- if (HAS_KEY(opts->output) && api_object_to_bool(opts->output, "opts.output", false, err)) {
+ if (opts->output) {
PUT(result, "output", STRING_OBJ(output));
}
@@ -70,19 +70,17 @@ Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Er
String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
{
- Boolean output = api_object_to_bool(opts->output, "opts.output", false, err);
-
const int save_msg_silent = msg_silent;
garray_T *const save_capture_ga = capture_ga;
const int save_msg_col = msg_col;
garray_T capture_local;
- if (output) {
+ if (opts->output) {
ga_init(&capture_local, 1, 80);
capture_ga = &capture_local;
}
try_start();
- if (output) {
+ if (opts->output) {
msg_silent++;
msg_col = 0; // prevent leading spaces
}
@@ -90,7 +88,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
const sctx_T save_current_sctx = api_set_sctx(channel_id);
do_source_str(src.data, "nvim_exec2()");
- if (output) {
+ if (opts->output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
// Put msg_col back where it was, since nothing should have been written.
@@ -104,7 +102,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
goto theend;
}
- if (output && capture_local.ga_len > 1) {
+ if (opts->output && capture_local.ga_len > 1) {
String s = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
@@ -118,7 +116,7 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
return s; // Caller will free the memory.
}
theend:
- if (output) {
+ if (opts->output) {
ga_clear(&capture_local);
}
return (String)STRING_INIT;
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 81a239d913..b666d1efa2 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -7,6 +7,7 @@
#include "klib/kvec.h"
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/win_config.h"
#include "nvim/ascii.h"
@@ -231,7 +232,7 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
- if (HAS_KEY(config->style)) {
+ if (HAS_KEY(config, float_config, style)) {
if (fconfig.style == kWinStyleMinimal) {
win_set_minimal_style(win);
didset_window_options(win, true);
@@ -380,12 +381,8 @@ static bool parse_float_bufpos(Array bufpos, lpos_T *out)
return true;
}
-static void parse_border_title(Object title, Object title_pos, FloatConfig *fconfig, Error *err)
+static void parse_border_title(Object title, FloatConfig *fconfig, Error *err)
{
- if (!parse_title_pos(title_pos, fconfig, err)) {
- return;
- }
-
if (title.type == kObjectTypeString) {
if (title.data.string.size == 0) {
fconfig->title = false;
@@ -415,24 +412,14 @@ static void parse_border_title(Object title, Object title_pos, FloatConfig *fcon
fconfig->title = true;
}
-static bool parse_title_pos(Object title_pos, FloatConfig *fconfig, Error *err)
+static bool parse_title_pos(String title_pos, FloatConfig *fconfig, Error *err)
{
- if (!HAS_KEY(title_pos)) {
+ if (title_pos.size == 0) {
fconfig->title_pos = kAlignLeft;
return true;
}
- if (title_pos.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation, "title_pos must be string");
- return false;
- }
-
- if (title_pos.data.string.size == 0) {
- fconfig->title_pos = kAlignLeft;
- return true;
- }
-
- char *pos = title_pos.data.string.data;
+ char *pos = title_pos.data;
if (strequal(pos, "left")) {
fconfig->title_pos = kAlignLeft;
@@ -559,110 +546,90 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf,
bool new_win, Error *err)
{
+#define HAS_KEY_X(d, key) HAS_KEY(d, float_config, key)
bool has_relative = false, relative_is_win = false;
- if (config->relative.type == kObjectTypeString) {
- // ignore empty string, to match nvim_win_get_config
- if (config->relative.data.string.size > 0) {
- if (!parse_float_relative(config->relative.data.string, &fconfig->relative)) {
- api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
- return false;
- }
+ // ignore empty string, to match nvim_win_get_config
+ if (HAS_KEY_X(config, relative) && config->relative.size > 0) {
+ if (!parse_float_relative(config->relative, &fconfig->relative)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
+ return false;
+ }
- if (!(HAS_KEY(config->row) && HAS_KEY(config->col)) && !HAS_KEY(config->bufpos)) {
- api_set_error(err, kErrorTypeValidation,
- "'relative' requires 'row'/'col' or 'bufpos'");
- return false;
- }
+ if (!(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;
+ }
- has_relative = true;
- fconfig->external = false;
- if (fconfig->relative == kFloatRelativeWindow) {
- relative_is_win = true;
- fconfig->bufpos.lnum = -1;
- }
+ has_relative = true;
+ fconfig->external = false;
+ if (fconfig->relative == kFloatRelativeWindow) {
+ relative_is_win = true;
+ fconfig->bufpos.lnum = -1;
}
- } else if (HAS_KEY(config->relative)) {
- api_set_error(err, kErrorTypeValidation, "'relative' key must be String");
- return false;
}
- if (config->anchor.type == kObjectTypeString) {
- if (!parse_float_anchor(config->anchor.data.string, &fconfig->anchor)) {
+ 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;
}
- } else if (HAS_KEY(config->anchor)) {
- api_set_error(err, kErrorTypeValidation, "'anchor' key must be String");
- return false;
}
- if (HAS_KEY(config->row)) {
+ if (HAS_KEY_X(config, row)) {
if (!has_relative) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'");
return false;
- } else if (config->row.type == kObjectTypeInteger) {
- fconfig->row = (double)config->row.data.integer;
- } else if (config->row.type == kObjectTypeFloat) {
- fconfig->row = config->row.data.floating;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'row' key must be Integer or Float");
- return false;
}
+ fconfig->row = config->row;
}
- if (HAS_KEY(config->col)) {
+ if (HAS_KEY_X(config, col)) {
if (!has_relative) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'");
return false;
- } else if (config->col.type == kObjectTypeInteger) {
- fconfig->col = (double)config->col.data.integer;
- } else if (config->col.type == kObjectTypeFloat) {
- fconfig->col = config->col.data.floating;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'col' key must be Integer or Float");
- return false;
}
+ fconfig->col = config->col;
}
- if (HAS_KEY(config->bufpos)) {
+ if (HAS_KEY_X(config, bufpos)) {
if (!has_relative) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'");
return false;
- } else if (config->bufpos.type == kObjectTypeArray) {
- if (!parse_float_bufpos(config->bufpos.data.array, &fconfig->bufpos)) {
+ } else {
+ if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
return false;
}
- if (!HAS_KEY(config->row)) {
+ if (!HAS_KEY_X(config, row)) {
fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1;
}
- if (!HAS_KEY(config->col)) {
+ if (!HAS_KEY_X(config, col)) {
fconfig->col = 0;
}
- } else {
- api_set_error(err, kErrorTypeValidation, "'bufpos' key must be Array");
- return false;
}
}
- if (config->width.type == kObjectTypeInteger && config->width.data.integer > 0) {
- fconfig->width = (int)config->width.data.integer;
- } else if (HAS_KEY(config->width)) {
- api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
- return false;
+ if (HAS_KEY_X(config, width)) {
+ if (config->width > 0) {
+ fconfig->width = (int)config->width;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
+ return false;
+ }
} else if (!reconf) {
api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
return false;
}
- if (config->height.type == kObjectTypeInteger && config->height.data.integer > 0) {
- fconfig->height = (int)config->height.data.integer;
- } else if (HAS_KEY(config->height)) {
- api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
- return false;
+ if (HAS_KEY_X(config, height)) {
+ if (config->height > 0) {
+ fconfig->height = (int)config->height;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
+ return false;
+ }
} else if (!reconf) {
api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
return false;
@@ -670,26 +637,20 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
if (relative_is_win) {
fconfig->window = curwin->handle;
- if (config->win.type == kObjectTypeInteger || config->win.type == kObjectTypeWindow) {
- if (config->win.data.integer > 0) {
- fconfig->window = (Window)config->win.data.integer;
+ if (HAS_KEY_X(config, win)) {
+ if (config->win > 0) {
+ fconfig->window = config->win;
}
- } else if (HAS_KEY(config->win)) {
- api_set_error(err, kErrorTypeValidation, "'win' key must be Integer or Window");
- return false;
}
} else {
- if (HAS_KEY(config->win)) {
+ if (HAS_KEY_X(config, win)) {
api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win'");
return false;
}
}
- if (HAS_KEY(config->external)) {
- fconfig->external = api_object_to_bool(config->external, "'external' key", false, err);
- if (ERROR_SET(err)) {
- return false;
- }
+ if (HAS_KEY_X(config, external)) {
+ fconfig->external = config->external;
if (has_relative && fconfig->external) {
api_set_error(err, kErrorTypeValidation,
"Only one of 'relative' and 'external' must be used");
@@ -708,30 +669,22 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
return false;
}
- if (HAS_KEY(config->focusable)) {
- fconfig->focusable = api_object_to_bool(config->focusable, "'focusable' key", false, err);
- if (ERROR_SET(err)) {
- return false;
- }
- }
-
- if (config->zindex.type == kObjectTypeInteger && config->zindex.data.integer > 0) {
- fconfig->zindex = (int)config->zindex.data.integer;
- } else if (HAS_KEY(config->zindex)) {
- api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
- return false;
+ if (HAS_KEY_X(config, focusable)) {
+ fconfig->focusable = config->focusable;
}
- if (HAS_KEY(config->title_pos)) {
- if (!HAS_KEY(config->title)) {
- api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
+ if (HAS_KEY_X(config, zindex)) {
+ if (config->zindex > 0) {
+ fconfig->zindex = (int)config->zindex;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
return false;
}
}
- if (HAS_KEY(config->title)) {
+ if (HAS_KEY_X(config, title)) {
// title only work with border
- if (!HAS_KEY(config->border) && !fconfig->border) {
+ if (!HAS_KEY_X(config, border) && !fconfig->border) {
api_set_error(err, kErrorTypeException, "title requires border to be set");
return false;
}
@@ -739,42 +692,49 @@ static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig,
if (fconfig->title) {
clear_virttext(&fconfig->title_chunks);
}
- parse_border_title(config->title, config->title_pos, fconfig, err);
+
+ parse_border_title(config->title, fconfig, err);
if (ERROR_SET(err)) {
return false;
}
+
+ // handles unset 'title_pos' same as empty string
+ if (!parse_title_pos(config->title_pos, fconfig, err)) {
+ return false;
+ }
+ } else {
+ if (HAS_KEY_X(config, title_pos)) {
+ api_set_error(err, kErrorTypeException, "title_pos requires title to be set");
+ return false;
+ }
}
- if (HAS_KEY(config->border)) {
+ if (HAS_KEY_X(config, border)) {
parse_border_style(config->border, fconfig, err);
if (ERROR_SET(err)) {
return false;
}
}
- if (config->style.type == kObjectTypeString) {
- if (config->style.data.string.data[0] == NUL) {
+ if (HAS_KEY_X(config, style)) {
+ if (config->style.data[0] == NUL) {
fconfig->style = kWinStyleUnused;
- } else if (striequal(config->style.data.string.data, "minimal")) {
+ } else if (striequal(config->style.data, "minimal")) {
fconfig->style = kWinStyleMinimal;
} else {
api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
+ return false;
}
- } else if (HAS_KEY(config->style)) {
- api_set_error(err, kErrorTypeValidation, "'style' key must be String");
- return false;
}
- if (HAS_KEY(config->noautocmd)) {
+ if (HAS_KEY_X(config, noautocmd)) {
if (!new_win) {
api_set_error(err, kErrorTypeValidation, "Invalid key: 'noautocmd'");
return false;
}
- fconfig->noautocmd = api_object_to_bool(config->noautocmd, "'noautocmd' key", false, err);
- if (ERROR_SET(err)) {
- return false;
- }
+ fconfig->noautocmd = config->noautocmd;
}
return true;
+#undef HAS_KEY_X
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index f32a7e671d..f74071a002 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/window.h"
@@ -513,18 +514,12 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren
bool oob = false;
- if (HAS_KEY(opts->start_row)) {
- VALIDATE_T("start_row", kObjectTypeInteger, opts->start_row.type, {
- return rv;
- });
- start_lnum = (linenr_T)normalize_index(buf, opts->start_row.data.integer, false, &oob);
+ if (HAS_KEY(opts, win_text_height, start_row)) {
+ start_lnum = (linenr_T)normalize_index(buf, opts->start_row, false, &oob);
}
- if (HAS_KEY(opts->end_row)) {
- VALIDATE_T("end_row", kObjectTypeInteger, opts->end_row.type, {
- return rv;
- });
- end_lnum = (linenr_T)normalize_index(buf, opts->end_row.data.integer, false, &oob);
+ if (HAS_KEY(opts, win_text_height, end_row)) {
+ end_lnum = (linenr_T)normalize_index(buf, opts->end_row, false, &oob);
}
VALIDATE(!oob, "%s", "Line index out of bounds", {
@@ -534,27 +529,23 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren
return rv;
});
- if (HAS_KEY(opts->start_vcol)) {
- VALIDATE(HAS_KEY(opts->start_row), "%s", "'start_vcol' specified without 'start_row'", {
+ if (HAS_KEY(opts, win_text_height, start_vcol)) {
+ VALIDATE(HAS_KEY(opts, win_text_height, start_row),
+ "%s", "'start_vcol' specified without 'start_row'", {
return rv;
});
- VALIDATE_T("start_vcol", kObjectTypeInteger, opts->start_vcol.type, {
- return rv;
- });
- start_vcol = opts->start_vcol.data.integer;
+ start_vcol = opts->start_vcol;
VALIDATE_RANGE((start_vcol >= 0 && start_vcol <= MAXCOL), "start_vcol", {
return rv;
});
}
- if (HAS_KEY(opts->end_vcol)) {
- VALIDATE(HAS_KEY(opts->end_row), "%s", "'end_vcol' specified without 'end_row'", {
- return rv;
- });
- VALIDATE_T("end_vcol", kObjectTypeInteger, opts->end_vcol.type, {
+ if (HAS_KEY(opts, win_text_height, end_vcol)) {
+ VALIDATE(HAS_KEY(opts, win_text_height, end_row),
+ "%s", "'end_vcol' specified without 'end_row'", {
return rv;
});
- end_vcol = opts->end_vcol.data.integer;
+ end_vcol = opts->end_vcol;
VALIDATE_RANGE((end_vcol >= 0 && end_vcol <= MAXCOL), "end_vcol", {
return rv;
});
@@ -568,7 +559,7 @@ Dictionary nvim_win_text_height(Window window, Dict(win_text_height) *opts, Aren
int64_t fill = 0;
int64_t all = win_text_height(win, start_lnum, start_vcol, end_lnum, end_vcol, &fill);
- if (!HAS_KEY(opts->end_row)) {
+ if (!HAS_KEY(opts, win_text_height, end_row)) {
const int64_t end_fill = win_get_fill(win, line_count + 1);
fill += end_fill;
all += end_fill;
diff --git a/src/nvim/context.c b/src/nvim/context.c
index f7b3491be7..ca28ed9970 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -271,8 +271,7 @@ static inline void ctx_save_funcs(Context *ctx, bool scriptonly)
size_t cmd_len = sizeof("func! ") + strlen(name);
char *cmd = xmalloc(cmd_len);
snprintf(cmd, cmd_len, "func! %s", name);
- Dict(exec_opts) opts = { 0 };
- opts.output = BOOLEAN_OBJ(true);
+ Dict(exec_opts) opts = { .output = true };
String func_body = exec_impl(VIML_INTERNAL_CALL, cstr_as_string(cmd),
&opts, &err);
xfree(cmd);
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index fe63cb883e..9c15597fcc 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -67,13 +67,27 @@ local keysets = {}
local function add_keyset(val)
local keys = {}
- for _,field in ipairs(val.fields) do
+ local types = {}
+ local is_set_name = 'is_set__' .. val.keyset_name .. '_'
+ local has_optional = false
+ for i,field in ipairs(val.fields) do
if field.type ~= 'Object' then
- error 'not yet implemented: types other than Object'
+ types[field.name] = field.type
+ end
+ if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then
+ table.insert(keys, field.name)
+ else
+ if i > 1 then
+ error("'is_set__{type}_' must be first if present")
+ elseif field.name ~= is_set_name then
+ error(val.keyset_name..": name of first key should be "..is_set_name)
+ elseif field.type ~= 'OptionalKeys' then
+ error("'"..is_set_name.."' must have type 'OptionalKeys'")
+ end
+ has_optional = true
end
- table.insert(keys, {field.name, field.type})
end
- table.insert(keysets, {val.keyset_name, keys})
+ table.insert(keysets, {name=val.keyset_name, keys=keys, types=types, has_optional=has_optional})
end
-- read each input file, parse and append to the api metadata
@@ -232,53 +246,60 @@ output:write([[
]])
-for _,keyset in ipairs(keysets) do
- local name, keys = unpack(keyset)
- local special = {}
- local function sanitize(key)
- if special[key] then
- return key .. "_"
- end
- return key
- end
+for _,k in ipairs(keysets) do
+ local c_name = {}
- local key_names = {}
- for i = 1,#keys do
- local kname = keys[i][1]
- if vim.endswith(kname, "_") then
- kname = string.sub(kname,1, #kname - 1)
- special[kname] = true
+ for i = 1,#k.keys do
+ -- some keys, like "register" are c keywords and get
+ -- escaped with a trailing _ in the struct.
+ if vim.endswith(k.keys[i], "_") then
+ local orig = k.keys[i]
+ k.keys[i] = string.sub(k.keys[i],1, #(k.keys[i]) - 1)
+ c_name[k.keys[i]] = orig
+ k.types[k.keys[i]] = k.types[orig]
end
- key_names[i] = kname
end
- local neworder, hashfun = hashy.hashy_hash(name, key_names, function (idx)
- return name.."_table["..idx.."].str"
+
+ local neworder, hashfun = hashy.hashy_hash(k.name, k.keys, function (idx)
+ return k.name.."_table["..idx.."].str"
end)
- keysets_defs:write("extern KeySetLink "..name.."_table[];\n")
+ keysets_defs:write("extern KeySetLink "..k.name.."_table[];\n")
- output:write("KeySetLink "..name.."_table[] = {\n")
- for _, key in ipairs(neworder) do
- output:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..sanitize(key)..")},\n")
+ local function typename(type)
+ if type ~= nil then
+ return "kObjectType"..type
+ else
+ return "kObjectTypeNil"
+ end
+ end
+
+ output:write("KeySetLink "..k.name.."_table[] = {\n")
+ for i, key in ipairs(neworder) do
+ local ind = -1
+ if k.has_optional then
+ ind = i
+ keysets_defs:write("#define KEYSET_OPTIDX_"..k.name.."__"..key.." "..ind.."\n")
+ end
+ output:write(' {"'..key..'", offsetof(KeyDict_'..k.name..", "..(c_name[key] or key).."), "..typename(k.types[key])..", "..ind.."},\n")
end
- output:write(' {NULL, 0},\n')
+ output:write(' {NULL, 0, kObjectTypeNil, -1},\n')
output:write("};\n\n")
output:write(hashfun)
output:write([[
-Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len)
+KeySetLink *KeyDict_]]..k.name..[[_get_field(const char *str, size_t len)
{
- int hash = ]]..name..[[_hash(str, len);
+ int hash = ]]..k.name..[[_hash(str, len);
if (hash == -1) {
return NULL;
}
-
- return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off);
+ return &]]..k.name..[[_table[hash];
}
]])
- keysets_defs:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n")
+ keysets_defs:write("#define api_free_keydict_"..k.name.."(x) api_free_keydict(x, "..k.name.."_table)\n")
end
local function real_type(type)
@@ -666,7 +687,7 @@ local function process_function(fn)
if (ERROR_SET(&err)) {
luaL_where(lstate, 1);
if (err_param) {
- lua_pushstring(lstate, "param '");
+ lua_pushstring(lstate, "Invalid '");
lua_pushstring(lstate, err_param);
lua_pushstring(lstate, "': ");
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index fad113adc5..3755b7ae05 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -226,8 +226,8 @@ int ns_get_hl(NS *ns_hl, int hl_id, bool link, bool nodefault)
if (api_dict_to_keydict(&dict, KeyDict_highlight_get_field,
ret.data.dictionary, &err)) {
attrs = dict2hlattrs(&dict, true, &it.link_id, &err);
- fallback = api_object_to_bool(dict.fallback, "fallback", true, &err);
- tmp = api_object_to_bool(dict.fallback, "tmp", false, &err);
+ fallback = GET_BOOL_OR_TRUE(&dict, highlight, fallback);
+ tmp = dict.fallback; // or false
if (it.link_id >= 0) {
fallback = true;
}
@@ -938,6 +938,7 @@ void hlattrs2dict(Dictionary *hl, Dictionary *hl_attrs, HlAttrs ae, bool use_rgb
HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *err)
{
+#define HAS_KEY_X(d, key) HAS_KEY(d, highlight, key)
HlAttrs hlattrs = HLATTRS_INIT;
int32_t fg = -1, bg = -1, ctermfg = -1, ctermbg = -1, sp = -1;
int blend = -1;
@@ -946,7 +947,7 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
bool cterm_mask_provided = false;
#define CHECK_FLAG(d, m, name, extra, flag) \
- if (api_object_to_bool(d->name##extra, #name, false, err)) { \
+ if (d->name##extra) { \
if (flag & HL_UNDERLINE_MASK) { \
m &= ~HL_UNDERLINE_MASK; \
} \
@@ -971,52 +972,48 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, nocombine, , HL_NOCOMBINE);
CHECK_FLAG(dict, mask, default, _, HL_DEFAULT);
- if (HAS_KEY(dict->fg)) {
+ if (HAS_KEY_X(dict, fg)) {
fg = object_to_color(dict->fg, "fg", use_rgb, err);
- } else if (HAS_KEY(dict->foreground)) {
+ } else if (HAS_KEY_X(dict, foreground)) {
fg = object_to_color(dict->foreground, "foreground", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (HAS_KEY(dict->bg)) {
+ if (HAS_KEY_X(dict, bg)) {
bg = object_to_color(dict->bg, "bg", use_rgb, err);
- } else if (HAS_KEY(dict->background)) {
+ } else if (HAS_KEY_X(dict, background)) {
bg = object_to_color(dict->background, "background", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (HAS_KEY(dict->sp)) {
+ if (HAS_KEY_X(dict, sp)) {
sp = object_to_color(dict->sp, "sp", true, err);
- } else if (HAS_KEY(dict->special)) {
+ } else if (HAS_KEY_X(dict, special)) {
sp = object_to_color(dict->special, "special", true, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
- if (HAS_KEY(dict->blend)) {
- VALIDATE_T("blend", kObjectTypeInteger, dict->blend.type, {
- return hlattrs;
- });
-
- Integer blend0 = dict->blend.data.integer;
+ if (HAS_KEY_X(dict, blend)) {
+ Integer blend0 = dict->blend;
VALIDATE_RANGE((blend0 >= 0 && blend0 <= 100), "blend", {
return hlattrs;
});
blend = (int)blend0;
}
- if (HAS_KEY(dict->link) || HAS_KEY(dict->global_link)) {
+ if (HAS_KEY_X(dict, link) || HAS_KEY_X(dict, global_link)) {
if (!link_id) {
api_set_error(err, kErrorTypeValidation, "Invalid Key: '%s'",
- HAS_KEY(dict->global_link) ? "global_link" : "link");
+ HAS_KEY_X(dict, global_link) ? "global_link" : "link");
return hlattrs;
}
- if (HAS_KEY(dict->global_link)) {
+ if (HAS_KEY_X(dict, global_link)) {
*link_id = object_to_hl_id(dict->global_link, "link", err);
mask |= HL_GLOBAL;
} else {
@@ -1050,21 +1047,21 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
// empty list from Lua API should clear all cterm attributes
// TODO(clason): handle via gen_api_dispatch
cterm_mask_provided = true;
- } else if (HAS_KEY(dict->cterm)) {
+ } else if (HAS_KEY_X(dict, cterm)) {
VALIDATE_EXP(false, "cterm", "Dict", api_typename(dict->cterm.type), {
return hlattrs;
});
}
#undef CHECK_FLAG
- if (HAS_KEY(dict->ctermfg)) {
+ if (HAS_KEY_X(dict, ctermfg)) {
ctermfg = object_to_color(dict->ctermfg, "ctermfg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
}
}
- if (HAS_KEY(dict->ctermbg)) {
+ if (HAS_KEY_X(dict, ctermbg)) {
ctermbg = object_to_color(dict->ctermbg, "ctermbg", false, err);
if (ERROR_SET(err)) {
return hlattrs;
@@ -1091,6 +1088,7 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
}
return hlattrs;
+#undef HAS_KEY_X
}
int object_to_color(Object val, char *key, bool rgb, Error *err)
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 9ae928a0d2..de53545195 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -832,9 +832,11 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
struct {
int *dest; RgbValue val; Object name;
} cattrs[] = {
- { &g->sg_rgb_fg_idx, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground },
- { &g->sg_rgb_bg_idx, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background },
- { &g->sg_rgb_sp_idx, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special },
+ { &g->sg_rgb_fg_idx, g->sg_rgb_fg,
+ HAS_KEY(dict, highlight, fg) ? dict->fg : dict->foreground },
+ { &g->sg_rgb_bg_idx, g->sg_rgb_bg,
+ HAS_KEY(dict, highlight, bg) ? dict->bg : dict->background },
+ { &g->sg_rgb_sp_idx, g->sg_rgb_sp, HAS_KEY(dict, highlight, sp) ? dict->sp : dict->special },
{ NULL, -1, NIL },
};
@@ -1563,19 +1565,12 @@ static bool hlgroup2dict(Dictionary *hl, NS ns_id, int hl_id, Arena *arena)
Dictionary ns_get_hl_defs(NS ns_id, Dict(get_highlight) *opts, Arena *arena, Error *err)
{
- Boolean link = api_object_to_bool(opts->link, "link", true, err);
+ Boolean link = GET_BOOL_OR_TRUE(opts, get_highlight, link);
int id = -1;
- if (opts->name.type != kObjectTypeNil) {
- VALIDATE_T("highlight name", kObjectTypeString, opts->name.type, {
- goto cleanup;
- });
- String name = opts->name.data.string;
- id = syn_check_group(name.data, name.size);
- } else if (opts->id.type != kObjectTypeNil) {
- VALIDATE_T("highlight id", kObjectTypeInteger, opts->id.type, {
- goto cleanup;
- });
- id = (int)opts->id.data.integer;
+ if (HAS_KEY(opts, get_highlight, name)) {
+ id = syn_check_group(opts->name.data, opts->name.size);
+ } else if (HAS_KEY(opts, get_highlight, id)) {
+ id = (int)opts->id;
}
if (id != -1) {
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 5b3b4dbe08..07c452deed 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -871,7 +871,8 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons
{
if (lua_type(lstate, -1) != LUA_TTABLE) {
if (err) {
- api_set_error(err, kErrorTypeValidation, "Expected lua table");
+ api_set_error(err, kErrorTypeValidation, "Expected lua %s",
+ (type == kObjectTypeFloat) ? "number" : "table");
}
return (LuaTableProps) { .type = kObjectTypeNil };
}
@@ -884,7 +885,7 @@ static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *cons
if (table_props.type != type) {
if (err) {
- api_set_error(err, kErrorTypeValidation, "Unexpected type");
+ api_set_error(err, kErrorTypeValidation, "Expected %s-like lua table", api_typename(type));
}
}
@@ -1224,26 +1225,19 @@ LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
return rv;
}
-#define GENERATE_INDEX_FUNCTION(type) \
- type nlua_pop_##type(lua_State *lstate, Error *err) \
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
- { \
- type ret; \
- if (lua_type(lstate, -1) != LUA_TNUMBER) { \
- api_set_error(err, kErrorTypeValidation, "Expected Lua number"); \
- ret = (type) - 1; \
- } else { \
- ret = (type)lua_tonumber(lstate, -1); \
- } \
- lua_pop(lstate, 1); \
- return ret; \
+handle_T nlua_pop_handle(lua_State *lstate, Error *err)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ handle_T ret;
+ if (lua_type(lstate, -1) != LUA_TNUMBER) {
+ api_set_error(err, kErrorTypeValidation, "Expected Lua number");
+ ret = (handle_T) - 1;
+ } else {
+ ret = (handle_T)lua_tonumber(lstate, -1);
}
-
-GENERATE_INDEX_FUNCTION(Buffer)
-GENERATE_INDEX_FUNCTION(Window)
-GENERATE_INDEX_FUNCTION(Tabpage)
-
-#undef GENERATE_INDEX_FUNCTION
+ lua_pop(lstate, 1);
+ return ret;
+}
/// Record some auxiliary values in vim module
///
@@ -1292,7 +1286,8 @@ void nlua_init_types(lua_State *const lstate)
lua_rawset(lstate, -3);
}
-void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err)
+// lua specific variant of api_dict_to_keydict
+void nlua_pop_keydict(lua_State *L, void *retval, FieldHashfn hashy, Error *err)
{
if (!lua_istable(L, -1)) {
api_set_error(err, kErrorTypeValidation, "Expected lua table");
@@ -1305,14 +1300,44 @@ void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err)
// [dict, key, value]
size_t len;
const char *s = lua_tolstring(L, -2, &len);
- Object *field = hashy(retval, s, len);
+ KeySetLink *field = hashy(s, len);
if (!field) {
api_set_error(err, kErrorTypeValidation, "invalid key: %.*s", (int)len, s);
lua_pop(L, 3); // []
return;
}
- *field = nlua_pop_Object(L, true, err);
+ if (field->opt_index >= 0) {
+ OptKeySet *ks = (OptKeySet *)retval;
+ ks->is_set_ |= (1ULL << field->opt_index);
+ }
+ char *mem = ((char *)retval + field->ptr_off);
+
+ if (field->type == kObjectTypeNil) {
+ *(Object *)mem = nlua_pop_Object(L, true, err);
+ } else if (field->type == kObjectTypeInteger) {
+ *(Integer *)mem = nlua_pop_Integer(L, err);
+ } else if (field->type == kObjectTypeBoolean) {
+ *(Boolean *)mem = nlua_pop_Boolean(L, err);
+ } else if (field->type == kObjectTypeString) {
+ *(String *)mem = nlua_pop_String(L, err);
+ } else if (field->type == kObjectTypeFloat) {
+ *(Float *)mem = nlua_pop_Float(L, err);
+ } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
+ || field->type == kObjectTypeTabpage) {
+ *(handle_T *)mem = nlua_pop_handle(L, err);
+ } else if (field->type == kObjectTypeArray) {
+ *(Array *)mem = nlua_pop_Array(L, err);
+ } else if (field->type == kObjectTypeDictionary) {
+ *(Dictionary *)mem = nlua_pop_Dictionary(L, false, err);
+ } else if (field->type == kObjectTypeLuaRef) {
+ *(LuaRef *)mem = nlua_pop_LuaRef(L, err);
+ } else {
+ abort();
+ }
+ if (ERROR_SET(err)) {
+ break;
+ }
}
// [dict]
lua_pop(L, 1);
diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h
index 241dd65cc7..d1d6b9d62a 100644
--- a/src/nvim/lua/converter.h
+++ b/src/nvim/lua/converter.h
@@ -9,6 +9,10 @@
#include "nvim/eval/typval_defs.h"
#include "nvim/func_attr.h"
+#define nlua_pop_Buffer nlua_pop_handle
+#define nlua_pop_Window nlua_pop_handle
+#define nlua_pop_Tabpage nlua_pop_handle
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/converter.h.generated.h"
#endif
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index d7747ee291..0cb94e6f5b 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -2558,26 +2558,22 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
const sctx_T save_current_sctx = api_set_sctx(channel_id);
- if (opts != NULL && opts->callback.type == kObjectTypeLuaRef) {
- lua_funcref = opts->callback.data.luaref;
- opts->callback.data.luaref = LUA_NOREF;
- }
MapArguments parsed_args = MAP_ARGUMENTS_INIT;
if (opts) {
-#define KEY_TO_BOOL(name) \
- parsed_args.name = api_object_to_bool(opts->name, #name, false, err); \
- if (ERROR_SET(err)) { \
- goto fail_and_free; \
- }
-
- KEY_TO_BOOL(nowait);
- KEY_TO_BOOL(noremap);
- KEY_TO_BOOL(silent);
- KEY_TO_BOOL(script);
- KEY_TO_BOOL(expr);
- KEY_TO_BOOL(unique);
- KEY_TO_BOOL(replace_keycodes);
-#undef KEY_TO_BOOL
+ parsed_args.nowait = opts->nowait;
+ parsed_args.noremap = opts->noremap;
+ parsed_args.silent = opts->silent;
+ parsed_args.script = opts->script;
+ parsed_args.expr = opts->expr;
+ parsed_args.unique = opts->unique;
+ parsed_args.replace_keycodes = opts->replace_keycodes;
+ if (HAS_KEY(opts, keymap, callback)) {
+ lua_funcref = opts->callback;
+ opts->callback = LUA_NOREF;
+ }
+ if (HAS_KEY(opts, keymap, desc)) {
+ parsed_args.desc = string_to_cstr(opts->desc);
+ }
}
parsed_args.buffer = !global;
@@ -2593,11 +2589,6 @@ void modify_keymap(uint64_t channel_id, Buffer buffer, bool is_unmap, String mod
goto fail_and_free;
}
- if (opts != NULL && opts->desc.type == kObjectTypeString) {
- parsed_args.desc = string_to_cstr(opts->desc.data.string);
- } else {
- parsed_args.desc = NULL;
- }
if (parsed_args.lhs_len > MAXMAPLEN || parsed_args.alt_lhs_len > MAXMAPLEN) {
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
goto fail_and_free;
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index ec1c9245ba..6d8e3d8e0a 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -109,7 +109,7 @@ describe('API/extmarks', function()
eq("Invalid 'virt_text_pos': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { virt_text_pos = 'foo' }))
eq("Invalid 'hl_mode': expected String, got Integer", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 0 }))
eq("Invalid 'hl_mode': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 'foo' }))
- eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 }))
+ eq("Invalid 'id': expected Integer, got Array", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 }))
eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1}))
eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1}))
-- No memory leak with virt_text, virt_lines, sign_text
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index d3a79327ae..5fa2235018 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -434,10 +434,8 @@ describe('API: get highlight', function()
before_each(clear)
it('validation', function()
- eq(
- 'Invalid highlight name: expected String, got Integer',
- pcall_err(meths.get_hl, 0, { name = 177 })
- )
+ eq("Invalid 'name': expected String, got Integer",
+ pcall_err(meths.get_hl, 0, { name = 177 }))
eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' }))
end)
@@ -534,7 +532,7 @@ describe('API: get highlight', function()
eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { id = 0 }))
eq(
- 'Invalid highlight id: expected Integer, got String',
+ "Invalid 'id': expected Integer, got String",
pcall_err(meths.get_hl, 0, { id = 'Test_set_hl' })
)