From 7224c889e0d5d70b99ae377036baa6377c33a568 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 10:25:24 +0100 Subject: build: enable MSVC level 3 warnings (#21934) MSVC has 4 different warning levels: 1 (severe), 2 (significant), 3 (production quality) and 4 (informational). Enabling level 3 warnings mostly revealed conversion problems, similar to GCC/clang -Wconversion flag. --- src/nvim/api/command.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index abd265f2cf..7e7df3ee0f 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -512,7 +512,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { VALIDATION_ERROR("'count' must be a non-negative Integer"); } - set_cmd_count(&ea, cmd->count.data.integer, true); + set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); } if (HAS_KEY(cmd->reg)) { @@ -1005,7 +1005,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) { uint32_t argt = 0; - long def = -1; + int64_t def = -1; cmd_addr_T addr_type_arg = ADDR_NONE; int compl = EXPAND_NOTHING; char *compl_arg = NULL; -- cgit From 4be6c6cf0ddf5e31d4103cb5df06651ba6f4897b Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Feb 2023 11:05:57 +0100 Subject: refactor: replace char_u with char (#21901) refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/command.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 7e7df3ee0f..f09a00e5c2 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -127,7 +127,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) // otherwise split arguments by whitespace. if (ea.argt & EX_NOSPC) { if (*ea.arg != NUL) { - ADD(args, STRING_OBJ(cstrn_to_string((char *)ea.arg, length))); + ADD(args, STRING_OBJ(cstrn_to_string(ea.arg, length))); } } else { size_t end = 0; @@ -153,9 +153,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) } if (cmd != NULL) { - PUT(result, "cmd", CSTR_TO_OBJ((char *)cmd->uc_name)); + PUT(result, "cmd", CSTR_TO_OBJ(cmd->uc_name)); } else { - PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx))); + PUT(result, "cmd", CSTR_TO_OBJ(get_command_name(NULL, ea.cmdidx))); } if (ea.argt & EX_RANGE) { @@ -237,7 +237,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) break; } PUT(result, "addr", CSTR_TO_OBJ(addr)); - PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd)); + PUT(result, "nextcmd", CSTR_TO_OBJ(ea.nextcmd)); Dictionary mods = ARRAY_DICT_INIT; -- cgit From 46a87a5d2bac598fed0870f0d3c926087f95d30f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 05:19:04 -0500 Subject: refactor(api): VALIDATE macros #22187 Problem: - API validation involves too much boilerplate. - API validation errors are not consistently worded. Solution: Introduce some macros. Currently these are clumsy, but they at least help with consistency and avoid some nesting. --- src/nvim/api/command.c | 63 ++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f09a00e5c2..0a95833256 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -11,6 +11,7 @@ #include "nvim/api/command.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/autocmd.h" #include "nvim/buffer_defs.h" @@ -99,10 +100,9 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) { Dictionary result = ARRAY_DICT_INIT; - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); + VALIDATE((opts.size == 0), "opts dict isn't empty", { return result; - } + }); // Parse command line exarg_T ea; @@ -998,7 +998,7 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) } } - api_set_error(err, kErrorTypeException, "No such user-defined command: %s", name.data); + api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, @@ -1014,20 +1014,17 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, LuaRef compl_luaref = LUA_NOREF; LuaRef preview_luaref = LUA_NOREF; - if (!uc_validate_name(name.data)) { - api_set_error(err, kErrorTypeValidation, "Invalid command name"); + VALIDATE_S(uc_validate_name(name.data), "command name", name.data, { goto err; - } - - if (mb_islower(name.data[0])) { - api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter"); + }); + VALIDATE_S(!mb_islower(name.data[0]), "command name (must begin with an uppercase letter)", + name.data, { goto err; - } - - if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive"); + }); + VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), + "Cannot use both 'range' and 'count'", { goto err; - } + }); if (opts->nargs.type == kObjectTypeInteger) { switch (opts->nargs.data.integer) { @@ -1038,14 +1035,14 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NOSPC | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_INT(false, "nargs", (int64_t)opts->nargs.data.integer, { + goto err; + }); } } else if (opts->nargs.type == kObjectTypeString) { - if (opts->nargs.data.string.size > 1) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); + VALIDATE_S((opts->nargs.data.string.size <= 1), "nargs", opts->nargs.data.string.data, { goto err; - } + }); switch (opts->nargs.data.string.data[0]) { case '*': @@ -1058,18 +1055,19 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, argt |= EX_EXTRA | EX_NEEDARG; break; default: - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", opts->nargs.data.string.data, { + goto err; + }); } } else if (HAS_KEY(opts->nargs)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'"); - goto err; + VALIDATE_S(false, "nargs", "", { + goto err; + }); } - if (HAS_KEY(opts->complete) && !argt) { - api_set_error(err, kErrorTypeValidation, "'complete' used without 'nargs'"); + VALIDATE((!HAS_KEY(opts->complete) || argt), "'complete' used without 'nargs'", { goto err; - } + }); if (opts->range.type == kObjectTypeBoolean) { if (opts->range.data.boolean) { @@ -1077,13 +1075,12 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_LINES; } } else if (opts->range.type == kObjectTypeString) { - if (opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1) { - argt |= EX_RANGE | EX_DFLALL; - addr_type_arg = ADDR_LINES; - } else { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); + VALIDATE_S((opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1), + "range", "", { goto err; - } + }); + argt |= EX_RANGE | EX_DFLALL; + addr_type_arg = ADDR_LINES; } else if (opts->range.type == kObjectTypeInteger) { argt |= EX_RANGE | EX_ZEROR; def = opts->range.data.integer; -- cgit From ff3d04b75b4a9314815c37d53ebc4d035a043335 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 08:07:38 -0500 Subject: refactor(api): VALIDATE macros #22256 - VALIDATE() takes a format string - deduplicate check_string_array - VALIDATE_RANGE - validate UI args --- src/nvim/api/command.c | 62 +++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 28 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 0a95833256..cae3927dfd 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -100,7 +100,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) { Dictionary result = ARRAY_DICT_INIT; - VALIDATE((opts.size == 0), "opts dict isn't empty", { + VALIDATE((opts.size == 0), "%s", "opts dict isn't empty", { return result; }); @@ -1021,7 +1021,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, name.data, { goto err; }); - VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), + VALIDATE((!HAS_KEY(opts->range) || !HAS_KEY(opts->count)), "%s", "Cannot use both 'range' and 'count'", { goto err; }); @@ -1065,7 +1065,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, }); } - VALIDATE((!HAS_KEY(opts->complete) || argt), "'complete' used without 'nargs'", { + VALIDATE((!HAS_KEY(opts->complete) || argt), "%s", "'complete' used without 'nargs'", { goto err; }); @@ -1086,8 +1086,9 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, def = opts->range.data.integer; addr_type_arg = ADDR_LINES; } else if (HAS_KEY(opts->range)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'"); - goto err; + VALIDATE_S(false, "range", "", { + goto err; + }); } if (opts->count.type == kObjectTypeBoolean) { @@ -1101,23 +1102,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, addr_type_arg = ADDR_OTHER; def = opts->count.data.integer; } else if (HAS_KEY(opts->count)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'count'"); - goto err; + VALIDATE_S(false, "count", "", { + goto err; + }); } - if (opts->addr.type == kObjectTypeString) { - if (parse_addr_type_arg(opts->addr.data.string.data, (int)opts->addr.data.string.size, - &addr_type_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); + if (HAS_KEY(opts->addr)) { + VALIDATE_T("addr", kObjectTypeString, opts->addr.type, { goto err; - } + }); + + VALIDATE_S(OK == parse_addr_type_arg(opts->addr.data.string.data, + (int)opts->addr.data.string.size, &addr_type_arg), "addr", + opts->addr.data.string.data, { + goto err; + }); if (addr_type_arg != ADDR_LINES) { argt |= EX_ZEROR; } - } else if (HAS_KEY(opts->addr)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'"); - goto err; } if (api_object_to_bool(opts->bang, "bang", false, err)) { @@ -1153,23 +1156,25 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, compl = EXPAND_USER_LUA; compl_luaref = api_new_luaref(opts->complete.data.luaref); } else if (opts->complete.type == kObjectTypeString) { - if (parse_compl_arg(opts->complete.data.string.data, - (int)opts->complete.data.string.size, &compl, &argt, - &compl_arg) != OK) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); + VALIDATE_S(OK == parse_compl_arg(opts->complete.data.string.data, + (int)opts->complete.data.string.size, &compl, &argt, + &compl_arg), + "complete", opts->complete.data.string.data, { goto err; - } + }); } else if (HAS_KEY(opts->complete)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'"); - goto err; + VALIDATE(false, "%s", "Invalid complete: expected Function or String", { + goto err; + }); } - if (opts->preview.type == kObjectTypeLuaRef) { + if (HAS_KEY(opts->preview)) { + VALIDATE_T("preview", kObjectTypeLuaRef, opts->preview.type, { + goto err; + }); + argt |= EX_PREVIEW; preview_luaref = api_new_luaref(opts->preview.data.luaref); - } else if (HAS_KEY(opts->preview)) { - api_set_error(err, kErrorTypeValidation, "Invalid value for 'preview'"); - goto err; } switch (command.type) { @@ -1185,8 +1190,9 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, rep = command.data.string.data; break; default: - api_set_error(err, kErrorTypeValidation, "'command' must be a string or Lua function"); - goto err; + VALIDATE(false, "%s", "Invalid command: expected Function or String", { + goto err; + }); } if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, -- cgit From 556f8646c01d1751cf39fe4df9c622899dceab9d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 14:19:28 -0500 Subject: refactor(api): consistent VALIDATE messages #22262 Problem: Validation messages are not consistently formatted. - Parameter names sometimes are NOT quoted. - Descriptive names (non-parameters) sometimes ARE quoted. Solution: Always quote the `name` value passed to a VALIDATE macro _unless_ the value has whitespace. --- src/nvim/api/command.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index cae3927dfd..81b70b07d0 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1017,7 +1017,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, VALIDATE_S(uc_validate_name(name.data), "command name", name.data, { goto err; }); - VALIDATE_S(!mb_islower(name.data[0]), "command name (must begin with an uppercase letter)", + VALIDATE_S(!mb_islower(name.data[0]), "command name (must start with uppercase)", name.data, { goto err; }); @@ -1163,7 +1163,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, goto err; }); } else if (HAS_KEY(opts->complete)) { - VALIDATE(false, "%s", "Invalid complete: expected Function or String", { + VALIDATE_EXP(false, "complete", "Function or String", NULL, { goto err; }); } @@ -1190,7 +1190,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, rep = command.data.string.data; break; default: - VALIDATE(false, "%s", "Invalid command: expected Function or String", { + VALIDATE_EXP(false, "command", "Function or String", NULL, { goto err; }); } -- cgit From 09b3432eaff3abcadb56d61b6f247f992b80b63f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 16 Feb 2023 10:07:18 -0500 Subject: fix(api): allow empty Lua table for nested dicts #22268 Problem: The Lua-API bridge allows Dict params to be empty Lua (list) tables at the function-signature level. But not for _nested_ Dicts, because they are not modeled: https://github.com/neovim/neovim/blob/fae754073289566051433fae74ec65783f9e7a6a/src/nvim/api/keysets.lua#L184 Some API functions like nvim_cmd check for kObjectTypeDictionary and don't handle the case of empty Lua tables (treated as "Array"). Solution: Introduce VALIDATE_T_DICT and use it in places where kObjectTypeDictionary was being checked directly. fixes #21005 --- src/nvim/api/command.c | 175 ++++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 82 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 81b70b07d0..6d63ae5e24 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -350,20 +350,24 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } \ } while (0) -#define VALIDATION_ERROR(...) \ +#define VALIDATE_MOD(cond, mod_, name_) \ do { \ - api_set_error(err, kErrorTypeValidation, __VA_ARGS__); \ - goto end; \ + if (!(cond)) { \ + api_set_error(err, kErrorTypeValidation, "Command cannot accept %s: %s", (mod_), (name_)); \ + goto end; \ + } \ } while (0) bool output; OBJ_TO_BOOL(output, opts->output, false, "'output'"); - // First, parse the command name and check if it exists and is valid. - if (!HAS_KEY(cmd->cmd) || cmd->cmd.type != kObjectTypeString - || cmd->cmd.data.string.data[0] == NUL) { - VALIDATION_ERROR("'cmd' must be a non-empty String"); - } + VALIDATE_R(HAS_KEY(cmd->cmd), "cmd", { + goto end; + }); + VALIDATE_EXP((cmd->cmd.type == kObjectTypeString && cmd->cmd.data.string.data[0] != NUL), + "cmd", "non-empty String", NULL, { + goto end; + }); cmdname = string_to_cstr(cmd->cmd.data.string); ea.cmd = cmdname; @@ -382,12 +386,12 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd; } - if (p == NULL || ea.cmdidx == CMD_SIZE) { - VALIDATION_ERROR("Command not found: %s", cmdname); - } - if (is_cmd_ni(ea.cmdidx)) { - VALIDATION_ERROR("Command not implemented: %s", cmdname); - } + VALIDATE((p != NULL && ea.cmdidx != CMD_SIZE), "Command not found: %s", cmdname, { + goto end; + }); + VALIDATE(!is_cmd_ni(ea.cmdidx), "Command not implemented: %s", cmdname, { + goto end; + }); // Get the command flags so that we can know what type of arguments the command uses. // Not required for a user command since `find_ex_command` already deals with it in that case. @@ -397,9 +401,9 @@ 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)) { - if (cmd->args.type != kObjectTypeArray) { - VALIDATION_ERROR("'args' must be an Array"); - } + VALIDATE_T("args", kObjectTypeArray, cmd->args.type, { + goto end; + }); // Process all arguments. Convert non-String arguments to String and check if String arguments // have non-whitespace characters. @@ -421,14 +425,15 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error snprintf(data_str, NUMBUFLEN, "%" PRId64, elem.data.integer); break; case kObjectTypeString: - if (string_iswhite(elem.data.string)) { - VALIDATION_ERROR("String command argument must have at least one non-whitespace " - "character"); - } + VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, { + goto end; + }); data_str = xstrndup(elem.data.string.data, elem.data.string.size); break; default: - VALIDATION_ERROR("Invalid type for command argument"); + VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), { + goto end; + }); break; } @@ -456,9 +461,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error break; } - if (!argc_valid) { - VALIDATION_ERROR("Incorrect number of arguments supplied"); - } + VALIDATE(argc_valid, "%s", "Wrong number of arguments", { + goto end; + }); } // Simply pass the first argument (if it exists) as the arg pointer to `set_cmd_addr_type()` @@ -466,22 +471,23 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error set_cmd_addr_type(&ea, args.size > 0 ? args.items[0].data.string.data : NULL); if (HAS_KEY(cmd->range)) { - if (!(ea.argt & EX_RANGE)) { - VALIDATION_ERROR("Command cannot accept a range"); - } else if (cmd->range.type != kObjectTypeArray) { - VALIDATION_ERROR("'range' must be an Array"); - } else if (cmd->range.data.array.size > 2) { - VALIDATION_ERROR("'range' cannot contain more than two elements"); - } + 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, { + goto end; + }); Array range = cmd->range.data.array; ea.addr_count = (int)range.size; for (size_t i = 0; i < range.size; i++) { Object elem = range.items[i]; - if (elem.type != kObjectTypeInteger || elem.data.integer < 0) { - VALIDATION_ERROR("'range' element must be a non-negative Integer"); - } + VALIDATE_EXP((elem.type == kObjectTypeInteger && elem.data.integer >= 0), + "range element", "non-negative Integer", NULL, { + goto end; + }); } if (range.size > 0) { @@ -489,9 +495,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error ea.line2 = (linenr_T)range.items[range.size - 1].data.integer; } - if (invalid_range(&ea) != NULL) { - VALIDATION_ERROR("Invalid range provided"); - } + VALIDATE_S((invalid_range(&ea) == NULL), "range", "", { + goto end; + }); } if (ea.addr_count == 0) { if (ea.argt & EX_DFLALL) { @@ -507,38 +513,38 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(cmd->count)) { - if (!(ea.argt & EX_COUNT)) { - VALIDATION_ERROR("Command cannot accept a count"); - } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { - VALIDATION_ERROR("'count' must be a non-negative Integer"); - } + 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, { + goto end; + }); set_cmd_count(&ea, (linenr_T)cmd->count.data.integer, true); } if (HAS_KEY(cmd->reg)) { - if (!(ea.argt & EX_REGSTR)) { - VALIDATION_ERROR("Command cannot accept a register"); - } else if (cmd->reg.type != kObjectTypeString || cmd->reg.data.string.size != 1) { - VALIDATION_ERROR("'reg' must be a single character"); - } + 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, { + goto end; + }); char regname = cmd->reg.data.string.data[0]; - if (regname == '=') { - VALIDATION_ERROR("Cannot use register \"="); - } else if (!valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx))) { - VALIDATION_ERROR("Invalid register: \"%c", regname); - } + VALIDATE((regname != '='), "%s", "Cannot use register \"=", { + goto end; + }); + VALIDATE(valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx)), + "Invalid register: \"%c", regname, { + goto end; + }); ea.regname = (uint8_t)regname; } OBJ_TO_BOOL(ea.forceit, cmd->bang, false, "'bang'"); - if (ea.forceit && !(ea.argt & EX_BANG)) { - VALIDATION_ERROR("Command cannot accept a bang"); - } + VALIDATE_MOD((!ea.forceit || (ea.argt & EX_BANG)), "bang", cmd->cmd.data.string.data); if (HAS_KEY(cmd->magic)) { - if (cmd->magic.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'magic' must be a Dictionary"); - } + VALIDATE_T_DICT("magic", cmd->magic, { + goto end; + }); Dict(cmd_magic) magic = { 0 }; if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field, @@ -559,9 +565,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(cmd->mods)) { - if (cmd->mods.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'mods' must be a Dictionary"); - } + 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)) { @@ -569,9 +575,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.filter)) { - if (mods.filter.type != kObjectTypeDictionary) { - VALIDATION_ERROR("'mods.filter' must be a Dictionary"); - } + VALIDATE_T_DICT("mods.filter", mods.filter, { + goto end; + }); Dict(cmd_mods_filter) filter = { 0 }; @@ -581,9 +587,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(filter.pattern)) { - if (filter.pattern.type != kObjectTypeString) { - VALIDATION_ERROR("'mods.filter.pattern' must be a String"); - } + VALIDATE_T2(filter.pattern, kObjectTypeString, { + goto end; + }); OBJ_TO_BOOL(cmdinfo.cmdmod.cmod_filter_force, filter.force, false, "'mods.filter.force'"); @@ -598,18 +604,20 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.tab)) { - if (mods.tab.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.tab' must be an Integer"); - } else if ((int)mods.tab.data.integer >= 0) { + VALIDATE_T2(mods.tab, kObjectTypeInteger, { + goto end; + }); + if ((int)mods.tab.data.integer >= 0) { // Silently ignore negative integers to allow mods.tab to be set to -1. cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } } if (HAS_KEY(mods.verbose)) { - if (mods.verbose.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.verbose' must be an Integer"); - } else if ((int)mods.verbose.data.integer >= 0) { + VALIDATE_T2(mods.verbose, kObjectTypeInteger, { + goto end; + }); + if ((int)mods.verbose.data.integer >= 0) { // Silently ignore negative integers to allow mods.verbose to be set to -1. cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1; } @@ -624,9 +632,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0); if (HAS_KEY(mods.split)) { - if (mods.split.type != kObjectTypeString) { - VALIDATION_ERROR("'mods.split' must be a String"); - } + VALIDATE_T2(mods.split, kObjectTypeString, { + goto end; + }); if (*mods.split.data.string.data == NUL) { // Empty string, do nothing. @@ -641,7 +649,9 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } else if (strcmp(mods.split.data.string.data, "botright") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BOT; } else { - VALIDATION_ERROR("Invalid value for 'mods.split'"); + VALIDATE_S(false, "mods.split", "", { + goto end; + }); } } @@ -666,9 +676,10 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error cmdinfo.cmdmod.cmod_flags |= CMOD_SILENT; } - if ((cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX) && !(ea.argt & EX_SBOXOK)) { - VALIDATION_ERROR("Command cannot be run in sandbox"); - } + VALIDATE(!((cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX) && !(ea.argt & EX_SBOXOK)), + "%s", "Command cannot be run in sandbox", { + goto end; + }); } // Finally, build the command line string that will be stored inside ea.cmdlinep. @@ -739,7 +750,7 @@ end: #undef OBJ_TO_BOOL #undef OBJ_TO_CMOD_FLAG -#undef VALIDATION_ERROR +#undef VALIDATE_MOD } /// Check if a string contains only whitespace characters. -- cgit From 6752f1005d26c93a033d856a60b7b296f3e51634 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 14 Dec 2022 19:58:18 +0100 Subject: docs: naming conventions, guidelines close #21063 --- src/nvim/api/command.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 6d63ae5e24..32378ed244 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -899,15 +899,13 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin } } -/// Create a new user command |user-commands| +/// Creates a global |user-commands| command. /// -/// {name} is the name of the new command. The name must begin with an uppercase letter. -/// -/// {command} is the replacement text or Lua function to execute. +/// For Lua usage see |lua-guide-commands-create|. /// /// Example: ///
vim
-///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {})
+///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true})
 ///    :SayHello
 ///    Hello world!
 /// 
@@ -929,15 +927,16 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - mods: (string) Command modifiers, if any || /// - smods: (table) Command modifiers in a structured format. Has the same /// structure as the "mods" key of |nvim_parse_cmd()|. -/// @param opts Optional command attributes. See |command-attributes| for more details. To use -/// boolean attributes (such as |:command-bang| or |:command-bar|) set the value to -/// "true". In addition to the string options listed in |:command-complete|, the -/// "complete" key also accepts a Lua function which works like the "customlist" -/// completion mode |:command-completion-customlist|. Additional parameters: -/// - desc: (string) Used for listing the command when a Lua function is used for -/// {command}. -/// - force: (boolean, default true) Override any previous definition. -/// - preview: (function) Preview callback for 'inccommand' |:command-preview| +/// @param opts Optional |command-attributes|. +/// - Set boolean attributes such as |:command-bang| or |:command-bar| to true (but +/// not |:command-buffer|, use |nvim_buf_create_user_command()| instead). +/// - "complete" |:command-complete| also accepts a Lua function which works like +/// |:command-completion-customlist|. +/// - Other parameters: +/// - desc: (string) Used for listing the command when a Lua function is used for +/// {command}. +/// - force: (boolean, default true) Override any previous definition. +/// - preview: (function) Preview callback for 'inccommand' |:command-preview| /// @param[out] err Error details, if any. void nvim_create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) @@ -955,7 +954,7 @@ void nvim_del_user_command(String name, Error *err) nvim_buf_del_user_command(-1, name, err); } -/// Create a new user command |user-commands| in the given buffer. +/// Creates a buffer-local command |user-commands|. /// /// @param buffer Buffer handle, or 0 for current buffer. /// @param[out] err Error details, if any. -- cgit From 6d0c61d90d316473eee0729363e20bf06825b09b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 21:09:11 +0800 Subject: fix(api): set script context when setting usercmd or option (#22624) --- src/nvim/api/command.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 32378ed244..de766c14b9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -938,10 +938,11 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - force: (boolean, default true) Override any previous definition. /// - preview: (function) Preview callback for 'inccommand' |:command-preview| /// @param[out] err Error details, if any. -void nvim_create_user_command(String name, Object command, Dict(user_command) *opts, Error *err) +void nvim_create_user_command(uint64_t channel_id, String name, Object command, + Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { - create_user_command(name, command, opts, 0, err); + create_user_command(channel_id, name, command, opts, 0, err); } /// Delete a user-defined command. @@ -959,7 +960,7 @@ void nvim_del_user_command(String name, Error *err) /// @param buffer Buffer handle, or 0 for current buffer. /// @param[out] err Error details, if any. /// @see nvim_create_user_command -void nvim_buf_create_user_command(Buffer buffer, String name, Object command, +void nvim_buf_create_user_command(uint64_t channel_id, Buffer buffer, String name, Object command, Dict(user_command) *opts, Error *err) FUNC_API_SINCE(9) { @@ -970,7 +971,7 @@ void nvim_buf_create_user_command(Buffer buffer, String name, Object command, buf_T *save_curbuf = curbuf; curbuf = target_buf; - create_user_command(name, command, opts, UC_BUFFER, err); + create_user_command(channel_id, name, command, opts, UC_BUFFER, err); curbuf = save_curbuf; } @@ -1011,8 +1012,8 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) api_set_error(err, kErrorTypeException, "Invalid command (not found): %s", name.data); } -void create_user_command(String name, Object command, Dict(user_command) *opts, int flags, - Error *err) +void create_user_command(uint64_t channel_id, String name, Object command, Dict(user_command) *opts, + int flags, Error *err) { uint32_t argt = 0; int64_t def = -1; @@ -1205,11 +1206,13 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, }); } - if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, - preview_luaref, addr_type_arg, luaref, force) != OK) { - api_set_error(err, kErrorTypeException, "Failed to create user command"); - // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg - } + WITH_SCRIPT_CONTEXT(channel_id, { + if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, + preview_luaref, addr_type_arg, luaref, force) != OK) { + api_set_error(err, kErrorTypeException, "Failed to create user command"); + // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg + } + }); return; -- cgit From 3285cd6eccd9b7f33cc32f992c2607c3fc4ca13f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 22 Mar 2023 10:09:28 +0000 Subject: refactor: do more in TRY_WRAP --- src/nvim/api/command.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index de766c14b9..1455f28050 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -697,8 +697,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error capture_ga = &capture_local; } - TRY_WRAP({ - try_start(); + TRY_WRAP(err, { if (output) { msg_silent++; msg_col = 0; // prevent leading spaces @@ -714,8 +713,6 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error // Put msg_col back where it was, since nothing should have been written. msg_col = save_msg_col; } - - try_end(err); }); if (ERROR_SET(err)) { -- cgit From fe9cbcb3a5c82932ecfb8f49d07e98a1fc2b31e5 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 25 Mar 2023 18:58:48 +0200 Subject: feat(api): nvim_exec2(), deprecate nvim_exec() #19032 Problem: The signature of nvim_exec() is not extensible per ":help api-contract". Solution: Introduce nvim_exec2() and deprecate nvim_exec(). --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 1455f28050..26ee9205b2 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -307,7 +307,7 @@ end: /// /// On execution error: fails with VimL error, updates v:errmsg. /// -/// @see |nvim_exec()| +/// @see |nvim_exec2()| /// @see |nvim_command()| /// /// @param cmd Command to execute. Must be a Dictionary that can contain the same values as -- cgit From 7190dba017e3aac0409c73ff1c954d18858cb3c9 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:39:50 +0200 Subject: refactor: remove use of reserved c++ keywords libnvim couldn't be easily used in C++ due to the use of reserved keywords. Additionally, add explicit casts to *alloc function calls used in inline functions, as C++ doesn't allow implicit casts from void pointers. --- src/nvim/api/command.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 26ee9205b2..7c01dc0e54 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1015,7 +1015,7 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( uint32_t argt = 0; int64_t def = -1; cmd_addr_T addr_type_arg = ADDR_NONE; - int compl = EXPAND_NOTHING; + int context = EXPAND_NOTHING; char *compl_arg = NULL; const char *rep = NULL; LuaRef luaref = LUA_NOREF; @@ -1161,11 +1161,11 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( } if (opts->complete.type == kObjectTypeLuaRef) { - compl = EXPAND_USER_LUA; + context = EXPAND_USER_LUA; compl_luaref = api_new_luaref(opts->complete.data.luaref); } else if (opts->complete.type == kObjectTypeString) { VALIDATE_S(OK == parse_compl_arg(opts->complete.data.string.data, - (int)opts->complete.data.string.size, &compl, &argt, + (int)opts->complete.data.string.size, &context, &argt, &compl_arg), "complete", opts->complete.data.string.data, { goto err; @@ -1204,8 +1204,8 @@ void create_user_command(uint64_t channel_id, String name, Object command, Dict( } WITH_SCRIPT_CONTEXT(channel_id, { - if (uc_add_command(name.data, name.size, rep, argt, def, flags, compl, compl_arg, compl_luaref, - preview_luaref, addr_type_arg, luaref, force) != OK) { + if (uc_add_command(name.data, name.size, rep, argt, def, flags, context, compl_arg, + compl_luaref, preview_luaref, addr_type_arg, luaref, force) != OK) { api_set_error(err, kErrorTypeException, "Failed to create user command"); // Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg } -- cgit From efb0896f21e03f64e3a14e7c09994e81956f47b9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 3 Apr 2023 15:21:24 +0200 Subject: refactor(api): make typed dicts appear as types in the source code problem: can we have Serde? solution: we have Serde at home This by itself is just a change of notation, that could be quickly merged to avoid messy merge conflicts, but upcoming changes are planned: - keysets no longer need to be defined in one single file. `keysets.h` is just the initial automatic conversion of the previous `keysets.lua`. keysets just used in a single api/{scope}.h can be moved to that file, later on. - Typed dicts will have more specific types than Object. this will enable most of the existing manual typechecking boilerplate to be eliminated. We will need some annotation for missing value, i e a boolean will need to be represented as a TriState (none/false/true) in some cases. - Eventually: optional parameters in form of a `Dict opts` final parameter will get added in some form to metadata. this will require a discussion/desicion about type forward compatibility. --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 7c01dc0e54..3df80e3fed 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -10,6 +10,7 @@ #include "lauxlib.h" #include "nvim/api/command.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" -- cgit From 08991b078267e5de0a19a136d00d4f71ad651a32 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 13 May 2023 21:33:22 +0200 Subject: docs: small fixes Co-authored-by: Christian Clason Co-authored-by: Gregory Anders Co-authored-by: HiPhish Co-authored-by: Julio B Co-authored-by: T727 <74924917+T-727@users.noreply.github.com> Co-authored-by: camoz Co-authored-by: champignoom <66909116+champignoom@users.noreply.github.com> --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 3df80e3fed..b1603c5d6e 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -916,6 +916,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin /// - args: (string) The args passed to the command, if any || /// - fargs: (table) The args split by unescaped whitespace (when more than one /// argument is allowed), if any || +/// - nargs: (string) Number of arguments |:command-nargs| /// - bang: (boolean) "true" if the command was executed with a ! modifier || /// - line1: (number) The starting line of the command range || /// - line2: (number) The final line of the command range || -- cgit From cfd4fdfea4d0e68ea50ad412b88b5289ded6fd6f Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Tue, 23 May 2023 14:25:10 +0600 Subject: refactor(api): new helper macros Adds new API helper macros `CSTR_AS_OBJ()`, `STATIC_CSTR_AS_OBJ()`, and `STATIC_CSTR_TO_OBJ()`, which cleans up a lot of the current code. These macros will also be used extensively in the upcoming option refactor PRs because then API Objects will be used to get/set options. This PR also modifies pre-existing code to use old API helper macros like `CSTR_TO_OBJ()` to make them cleaner. --- src/nvim/api/command.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index b1603c5d6e..6d715bcf46 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -245,7 +245,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) Dictionary filter = ARRAY_DICT_INIT; PUT(filter, "pattern", cmdinfo.cmdmod.cmod_filter_pat ? CSTR_TO_OBJ(cmdinfo.cmdmod.cmod_filter_pat) - : STRING_OBJ(STATIC_CSTR_TO_STRING(""))); + : STATIC_CSTR_TO_OBJ("")); PUT(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force)); PUT(mods, "filter", DICTIONARY_OBJ(filter)); @@ -438,7 +438,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error break; } - ADD(args, STRING_OBJ(cstr_as_string(data_str))); + ADD(args, CSTR_AS_OBJ(data_str)); } bool argc_valid; -- cgit From 4e6356559c8cd44dbcaa765d1f39e176064526ec Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 03:44:51 -0700 Subject: test: spellcheck :help (vimdoc) files #24109 Enforce consistent terminology (defined in `gen_help_html.lua:spell_dict`) for common misspellings. This does not spellcheck English in general (perhaps a future TODO, though it may be noisy). --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 6d715bcf46..eba209b424 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -306,7 +306,7 @@ end: /// make their usage simpler with |vim.cmd()|. For example, instead of /// `vim.cmd.bdelete{ count = 2 }`, you may do `vim.cmd.bdelete(2)`. /// -/// On execution error: fails with VimL error, updates v:errmsg. +/// On execution error: fails with Vimscript error, updates v:errmsg. /// /// @see |nvim_exec2()| /// @see |nvim_command()| -- cgit From e0453d7f5743ad2f515deea76e363d11a7e1fa96 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 28 Jun 2023 04:51:55 -0700 Subject: fix(api): nvim_cmd{cmd="win_getid"} parsed as :winsize #24181 Problem: `:lua vim.cmd.win_getid(30,10)` is interpreted as `:win[size] 30 10`. User intention was to call `vim.fn.win_getid(30,10)`. Solution: Check that the `cmd` actually matches the resolved command. --- src/nvim/api/command.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index eba209b424..3157132256 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -393,6 +393,12 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error VALIDATE(!is_cmd_ni(ea.cmdidx), "Command not implemented: %s", cmdname, { goto end; }); + const char *fullname = IS_USER_CMDIDX(ea.cmdidx) + ? get_user_command_name(ea.useridx, ea.cmdidx) + : get_command_name(NULL, ea.cmdidx); + VALIDATE(strncmp(fullname, cmdname, strlen(cmdname)) == 0, "Invalid command: \"%s\"", cmdname, { + goto end; + }); // Get the command flags so that we can know what type of arguments the command uses. // Not required for a user command since `find_ex_command` already deals with it in that case. -- cgit From a741c7fd0465c949a0016fcbee5f4526b65f8c02 Mon Sep 17 00:00:00 2001 From: Alexandre Teoi Date: Sat, 1 Jul 2023 10:33:51 -0300 Subject: fix(api): nvim_parse_cmd error message in pcall() #23297 Problem: nvim_parse_cmd() in pcall() may show an error message (side-effect): :lua pcall(vim.api.nvim_parse_cmd, vim.fn.getcmdline(), {}) E16: Invalid range Solution: Avoid emsg() in the nvim_parse_cmd() codepath. - refactor(api): add error message output parameter to get_address() - fix: null check emsg() parameter - refactor: remove emsg_off workaround from do_incsearch_highlighting() - refactor: remove emsg_off workaround from cmdpreview_may_show() - refactor: remove remaining calls to emsg() from parse_cmd_address() and get_address() - (refactor): lint set_cmd_dflall_range() - refactor: addr_error() - move output parameter to return value Fix #20339 TODO: These are the functions called by `get_address()`: ``` nvim_parse_cmd() -> parse_cmdline() -> parse_cmd_address() -> get_address() skipwhite() addr_error() qf_get_cur_idx() qf_get_cur_valid_idx() qf_get_size() qf_get_valid_size() mark_get() mark_check() assert() skip_regexp() magic_isset() > do_search() > searchit() ascii_isdigit() getdigits() getdigits_int32() compute_buffer_local_count() hasFolding() ``` From these functions, I found at least two that call emsg directly: - do_search() - seems to be simple to refactor - searchit() - will be more challenging because it may generate multiple error messages, which can't be handled by the current `errormsg` out-parameter. For example, it makes multiple calls to `vim_regexec_multi()` in a loop that possibly generate error messages, and later `searchit()` itself may generate another one: - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L631-L647 - https://github.com/neovim/neovim/blob/c194acbfc479d8e5839fa629363f93f6550d035c/src/nvim/search.c#L939-L954 --------- Co-authored-by: Justin M. Keyes --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 3157132256..b254e326f9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -109,7 +109,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) exarg_T ea; CmdParseInfo cmdinfo; char *cmdline = string_to_cstr(str); - char *errormsg = NULL; + const char *errormsg = NULL; if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) { if (errormsg != NULL) { -- cgit From d2f81330247ee060d557330b2716ccea8f789a50 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 12 Jul 2023 19:27:14 +0200 Subject: docs: misc Co-authored-by: Kevin Pham --- src/nvim/api/command.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index b254e326f9..75140beb88 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1230,6 +1230,8 @@ err: /// /// Currently only |user-commands| are supported, not builtin Ex commands. /// +/// @see |nvim_get_all_options_info()| +/// /// @param opts Optional parameters. Currently only supports /// {"builtin":false} /// @param[out] err Error details, if any. -- cgit From 7bc93e0e2f246dd78026a3472d929a0fe450f70d Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 1 Aug 2023 14:01:19 +0200 Subject: refactor(api): use typed keysets Initially this is just for geting rid of boilerplate, but eventually the types could get exposed as metadata --- src/nvim/api/command.c | 240 +++++++++++++++++++------------------------------ 1 file changed, 92 insertions(+), 148 deletions(-) (limited to 'src/nvim/api/command.c') 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); -- cgit From 2e92065686f62851318150a315591c30b8306a4b Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 14 Sep 2023 08:23:01 -0500 Subject: docs: replace
 with ``` (#25136)

---
 src/nvim/api/command.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

(limited to 'src/nvim/api/command.c')

diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 2b09cfc4b2..808d4e0b8d 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -860,11 +860,12 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin
 /// For Lua usage see |lua-guide-commands-create|.
 ///
 /// Example:
-/// 
vim
-///    :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true})
-///    :SayHello
-///    Hello world!
-/// 
+/// +/// ```vim +/// :call nvim_create_user_command('SayHello', 'echo "Hello world!"', {'bang': v:true}) +/// :SayHello +/// Hello world! +/// ``` /// /// @param name Name of the new user command. Must begin with an uppercase letter. /// @param command Replacement command to execute when this user command is executed. When called -- cgit From cf8b2c0e74fd5e723b0c15c2ce84e6900fd322d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Sep 2023 12:05:28 +0800 Subject: build(iwyu): add a few more _defs.h mappings (#25435) --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 808d4e0b8d..eb32f46143 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -9,6 +9,7 @@ #include "klib/kvec.h" #include "lauxlib.h" #include "nvim/api/command.h" +#include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" -- cgit From 09a17f91d0d362c6e58bfdbe3ccdeacffb0b44b9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 2 Oct 2023 10:45:33 +0800 Subject: refactor: move cmdline completion types to cmdexpand_defs.h (#25465) --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index eb32f46143..f4c6f646eb 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -17,6 +17,7 @@ #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" +#include "nvim/cmdexpand_defs.h" #include "nvim/decoration.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" -- cgit From cd63a9addd6e1114c3524fa041ece560550cfe7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 08:39:21 +0800 Subject: refactor: change some xstrndup() and xstrnsave() to xmemdupz() (#25959) When the given length is exactly the number of bytes to copy, xmemdupz() makes the intention clearer. --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f4c6f646eb..9d51f2a4dc 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -419,7 +419,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error VALIDATE_EXP(!string_iswhite(elem.data.string), "command arg", "non-whitespace", NULL, { goto end; }); - data_str = xstrndup(elem.data.string.data, elem.data.string.size); + data_str = string_to_cstr(elem.data.string); break; default: VALIDATE_EXP(false, "command arg", "valid type", api_typename(elem.type), { -- cgit From 353a4be7e84fdc101318215bdcc8a7e780d737fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 12 Nov 2023 13:13:58 +0100 Subject: build: remove PVS We already have an extensive suite of static analysis tools we use, which causes a fair bit of redundancy as we get duplicate warnings. PVS is also prone to give false warnings which creates a lot of work to identify and disable. --- src/nvim/api/command.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 9d51f2a4dc..10d8b4c768 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - #include #include #include -- cgit From a6e3d93421ba13c407a96fac9cc01fa41ec7ad98 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Thu, 16 Nov 2023 10:59:11 +0100 Subject: refactor: enable formatting for ternaries This requires removing the "Inner expression should be aligned" rule from clint as it prevents essentially any formatting regarding ternary operators. --- src/nvim/api/command.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 10d8b4c768..e1691bb910 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -379,8 +379,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error goto end; }); const char *fullname = IS_USER_CMDIDX(ea.cmdidx) - ? get_user_command_name(ea.useridx, ea.cmdidx) - : get_command_name(NULL, ea.cmdidx); + ? get_user_command_name(ea.useridx, ea.cmdidx) + : get_command_name(NULL, ea.cmdidx); VALIDATE(strncmp(fullname, cmdname, strlen(cmdname)) == 0, "Invalid command: \"%s\"", cmdname, { goto end; }); @@ -836,8 +836,8 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin offset += eap->arglens[i]; } // If there isn't an argument, make eap->arg point to end of cmdline. - eap->arg = argc > 0 ? eap->args[0] : - cmdline.items + cmdline.size - 1; // Subtract 1 to account for NUL + eap->arg = argc > 0 ? eap->args[0] + : cmdline.items + cmdline.size - 1; // Subtract 1 to account for NUL // Finally, make cmdlinep point to the cmdline string. *cmdlinep = cmdline.items; -- cgit From 574d25642fc9ca65b396633aeab6e2d32778b642 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 17:21:58 +0800 Subject: refactor: move Arena and ArenaMem to memory_defs.h (#26240) --- src/nvim/api/command.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index e1691bb910..5e46797ca4 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -1,10 +1,10 @@ #include +#include #include #include #include #include "klib/kvec.h" -#include "lauxlib.h" #include "nvim/api/command.h" #include "nvim/api/keysets.h" #include "nvim/api/private/defs.h" @@ -15,7 +15,6 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/cmdexpand_defs.h" -#include "nvim/decoration.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" -- cgit From 8b428ca8b79ebb7b36c3e403ff3bcb6924a635a6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 16:00:21 +0100 Subject: build(IWYU): fix includes for func_attr.h --- src/nvim/api/command.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 5e46797ca4..4af475d400 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -18,6 +18,7 @@ #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" +#include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" -- cgit From f4aedbae4cb1f206f5b7c6142697b71dd473059b Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 18:39:38 +0100 Subject: build(IWYU): fix includes for undo_defs.h --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 4af475d400..e44e4052ca 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -26,7 +26,7 @@ #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/ops.h" -#include "nvim/pos.h" +#include "nvim/pos_defs.h" #include "nvim/regexp.h" #include "nvim/strings.h" #include "nvim/types.h" -- cgit From e3f735ef101d670555f44226614a5c3557053b1f Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:13:32 +0100 Subject: refactor: fix includes for api/autocmd.h --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index e44e4052ca..2d3bc26e62 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -6,7 +6,7 @@ #include "klib/kvec.h" #include "nvim/api/command.h" -#include "nvim/api/keysets.h" +#include "nvim/api/keysets_defs.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" -- cgit From 6c14ae6bfaf51415b555e9a6b85d1d280976358d Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 Nov 2023 20:27:32 +0100 Subject: refactor: rename types.h to types_defs.h --- src/nvim/api/command.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 2d3bc26e62..f9e2c58dd9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -29,7 +29,7 @@ #include "nvim/pos_defs.h" #include "nvim/regexp.h" #include "nvim/strings.h" -#include "nvim/types.h" +#include "nvim/types_defs.h" #include "nvim/usercmd.h" #include "nvim/vim.h" #include "nvim/window.h" -- cgit From 79b6ff28ad1204fbb4199b9092f5c578d88cb28e Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 Nov 2023 20:31:00 +0100 Subject: refactor: fix headers with IWYU --- src/nvim/api/command.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api/command.c') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index f9e2c58dd9..2a57ce9a19 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -11,7 +11,7 @@ #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" #include "nvim/api/private/validate.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/cmdexpand_defs.h" @@ -22,7 +22,7 @@ #include "nvim/garray.h" #include "nvim/globals.h" #include "nvim/lua/executor.h" -#include "nvim/macros.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/ops.h" @@ -31,7 +31,7 @@ #include "nvim/strings.h" #include "nvim/types_defs.h" #include "nvim/usercmd.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -- cgit