diff options
Diffstat (limited to 'src/nvim/api')
-rw-r--r-- | src/nvim/api/autocmd.c | 92 | ||||
-rw-r--r-- | src/nvim/api/command.c | 240 | ||||
-rw-r--r-- | src/nvim/api/deprecated.c | 6 | ||||
-rw-r--r-- | src/nvim/api/extmark.c | 166 | ||||
-rw-r--r-- | src/nvim/api/keysets.h | 321 | ||||
-rw-r--r-- | src/nvim/api/options.c | 46 | ||||
-rw-r--r-- | src/nvim/api/private/defs.h | 12 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 87 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.h | 5 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 99 | ||||
-rw-r--r-- | src/nvim/api/vimscript.c | 14 | ||||
-rw-r--r-- | src/nvim/api/win_config.c | 206 | ||||
-rw-r--r-- | src/nvim/api/window.c | 37 |
13 files changed, 603 insertions, 728 deletions
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; |