aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/vimscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/vimscript.c')
-rw-r--r--src/nvim/api/vimscript.c617
1 files changed, 0 insertions, 617 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 6d0b9c7d99..478e146781 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -26,8 +26,6 @@
# include "api/vimscript.c.generated.h"
#endif
-#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
-
/// Executes Vimscript (multiline block of Ex commands), like anonymous
/// |:source|.
///
@@ -747,618 +745,3 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
viml_parser_destroy(&pstate);
return ret;
}
-
-/// Parse command line.
-///
-/// Doesn't check the validity of command arguments.
-///
-/// @param str Command line string to parse. Cannot contain "\n".
-/// @param opts Optional parameters. Reserved for future use.
-/// @param[out] err Error details, if any.
-/// @return Dictionary containing command information, with these keys:
-/// - cmd: (string) Command name.
-/// - range: (array) Command <range>. Can have 0-2 elements depending on how many items the
-/// range contains. Has no elements if command doesn't accept a range or if
-/// no range was specified, one element if only a single range item was
-/// specified and two elements if both range items were specified.
-/// - count: (number) Any |<count>| that was supplied to the command. -1 if command cannot
-/// take a count.
-/// - reg: (number) The optional command |<register>|, if specified. Empty string if not
-/// specified or if command cannot take a register.
-/// - bang: (boolean) Whether command contains a |<bang>| (!) modifier.
-/// - args: (array) Command arguments.
-/// - addr: (string) Value of |:command-addr|. Uses short name.
-/// - nargs: (string) Value of |:command-nargs|.
-/// - nextcmd: (string) Next command if there are multiple commands separated by a |:bar|.
-/// Empty if there isn't a next command.
-/// - magic: (dictionary) Which characters have special meaning in the command arguments.
-/// - file: (boolean) The command expands filenames. Which means characters such as "%",
-/// "#" and wildcards are expanded.
-/// - bar: (boolean) The "|" character is treated as a command separator and the double
-/// quote character (\") is treated as the start of a comment.
-/// - mods: (dictionary) |:command-modifiers|.
-/// - silent: (boolean) |:silent|.
-/// - emsg_silent: (boolean) |:silent!|.
-/// - sandbox: (boolean) |:sandbox|.
-/// - noautocmd: (boolean) |:noautocmd|.
-/// - browse: (boolean) |:browse|.
-/// - confirm: (boolean) |:confirm|.
-/// - hide: (boolean) |:hide|.
-/// - keepalt: (boolean) |:keepalt|.
-/// - keepjumps: (boolean) |:keepjumps|.
-/// - keepmarks: (boolean) |:keepmarks|.
-/// - keeppatterns: (boolean) |:keeppatterns|.
-/// - lockmarks: (boolean) |:lockmarks|.
-/// - noswapfile: (boolean) |:noswapfile|.
-/// - tab: (integer) |:tab|.
-/// - verbose: (integer) |:verbose|. -1 when omitted.
-/// - vertical: (boolean) |:vertical|.
-/// - split: (string) Split modifier string, is an empty string when there's no split
-/// modifier. If there is a split modifier it can be one of:
-/// - "aboveleft": |:aboveleft|.
-/// - "belowright": |:belowright|.
-/// - "topleft": |:topleft|.
-/// - "botright": |:botright|.
-Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
- FUNC_API_SINCE(10) FUNC_API_FAST
-{
- Dictionary result = ARRAY_DICT_INIT;
-
- if (opts.size > 0) {
- api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
- return result;
- }
-
- // Parse command line
- exarg_T ea;
- CmdParseInfo cmdinfo;
- char *cmdline = string_to_cstr(str);
- char *errormsg = NULL;
-
- if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) {
- if (errormsg != NULL) {
- api_set_error(err, kErrorTypeException, "Error while parsing command line: %s", errormsg);
- } else {
- api_set_error(err, kErrorTypeException, "Error while parsing command line");
- }
- goto end;
- }
-
- // Parse arguments
- Array args = ARRAY_DICT_INIT;
- size_t length = STRLEN(ea.arg);
-
- // For nargs = 1 or '?', pass the entire argument list as a single argument,
- // 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)));
- }
- } else {
- size_t end = 0;
- size_t len = 0;
- char *buf = xcalloc(length, sizeof(char));
- bool done = false;
-
- while (!done) {
- done = uc_split_args_iter(ea.arg, length, &end, buf, &len);
- if (len > 0) {
- ADD(args, STRING_OBJ(cstrn_to_string(buf, len)));
- }
- }
-
- xfree(buf);
- }
-
- ucmd_T *cmd = NULL;
- if (ea.cmdidx == CMD_USER) {
- cmd = USER_CMD(ea.useridx);
- } else if (ea.cmdidx == CMD_USER_BUF) {
- cmd = USER_CMD_GA(&curbuf->b_ucmds, ea.useridx);
- }
-
- if (cmd != NULL) {
- PUT(result, "cmd", CSTR_TO_OBJ((char *)cmd->uc_name));
- } else {
- PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx)));
- }
-
- if ((ea.argt & EX_RANGE) && ea.addr_count > 0) {
- Array range = ARRAY_DICT_INIT;
- if (ea.addr_count > 1) {
- ADD(range, INTEGER_OBJ(ea.line1));
- }
- ADD(range, INTEGER_OBJ(ea.line2));
- PUT(result, "range", ARRAY_OBJ(range));
- } else {
- PUT(result, "range", ARRAY_OBJ(ARRAY_DICT_INIT));
- }
-
- if (ea.argt & EX_COUNT) {
- if (ea.addr_count > 0) {
- PUT(result, "count", INTEGER_OBJ(ea.line2));
- } else if (cmd != NULL) {
- PUT(result, "count", INTEGER_OBJ(cmd->uc_def));
- } else {
- PUT(result, "count", INTEGER_OBJ(0));
- }
- } else {
- PUT(result, "count", INTEGER_OBJ(-1));
- }
-
- char reg[2];
- reg[0] = (char)ea.regname;
- reg[1] = '\0';
- PUT(result, "reg", CSTR_TO_OBJ(reg));
-
- PUT(result, "bang", BOOLEAN_OBJ(ea.forceit));
- PUT(result, "args", ARRAY_OBJ(args));
-
- char nargs[2];
- if (ea.argt & EX_EXTRA) {
- if (ea.argt & EX_NOSPC) {
- if (ea.argt & EX_NEEDARG) {
- nargs[0] = '1';
- } else {
- nargs[0] = '?';
- }
- } else if (ea.argt & EX_NEEDARG) {
- nargs[0] = '+';
- } else {
- nargs[0] = '*';
- }
- } else {
- nargs[0] = '0';
- }
- nargs[1] = '\0';
- PUT(result, "nargs", CSTR_TO_OBJ(nargs));
-
- const char *addr;
- switch (ea.addr_type) {
- case ADDR_LINES:
- addr = "line";
- break;
- case ADDR_ARGUMENTS:
- addr = "arg";
- break;
- case ADDR_BUFFERS:
- addr = "buf";
- break;
- case ADDR_LOADED_BUFFERS:
- addr = "load";
- break;
- case ADDR_WINDOWS:
- addr = "win";
- break;
- case ADDR_TABS:
- addr = "tab";
- break;
- case ADDR_QUICKFIX:
- addr = "qf";
- break;
- case ADDR_NONE:
- addr = "none";
- break;
- default:
- addr = "?";
- break;
- }
- PUT(result, "addr", CSTR_TO_OBJ(addr));
- PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd));
-
- Dictionary mods = ARRAY_DICT_INIT;
- PUT(mods, "silent", BOOLEAN_OBJ(cmdinfo.silent));
- PUT(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.emsg_silent));
- PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.sandbox));
- PUT(mods, "noautocmd", BOOLEAN_OBJ(cmdinfo.noautocmd));
- PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.tab));
- PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.verbose));
- PUT(mods, "browse", BOOLEAN_OBJ(cmdinfo.cmdmod.browse));
- PUT(mods, "confirm", BOOLEAN_OBJ(cmdinfo.cmdmod.confirm));
- PUT(mods, "hide", BOOLEAN_OBJ(cmdinfo.cmdmod.hide));
- PUT(mods, "keepalt", BOOLEAN_OBJ(cmdinfo.cmdmod.keepalt));
- PUT(mods, "keepjumps", BOOLEAN_OBJ(cmdinfo.cmdmod.keepjumps));
- PUT(mods, "keepmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.keepmarks));
- PUT(mods, "keeppatterns", BOOLEAN_OBJ(cmdinfo.cmdmod.keeppatterns));
- PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.lockmarks));
- PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdinfo.cmdmod.noswapfile));
- PUT(mods, "vertical", BOOLEAN_OBJ(cmdinfo.cmdmod.split & WSP_VERT));
-
- const char *split;
- if (cmdinfo.cmdmod.split & WSP_BOT) {
- split = "botright";
- } else if (cmdinfo.cmdmod.split & WSP_TOP) {
- split = "topleft";
- } else if (cmdinfo.cmdmod.split & WSP_BELOW) {
- split = "belowright";
- } else if (cmdinfo.cmdmod.split & WSP_ABOVE) {
- split = "aboveleft";
- } else {
- split = "";
- }
- PUT(mods, "split", CSTR_TO_OBJ(split));
-
- PUT(result, "mods", DICTIONARY_OBJ(mods));
-
- Dictionary magic = ARRAY_DICT_INIT;
- PUT(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file));
- PUT(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar));
- PUT(result, "magic", DICTIONARY_OBJ(magic));
-end:
- xfree(cmdline);
- return result;
-}
-
-/// Executes an Ex command.
-///
-/// Unlike |nvim_command()| this command takes a structured Dictionary instead of a String. This
-/// allows for easier construction and manipulation of an Ex command. This also allows for things
-/// such as having spaces inside a command argument, expanding filenames in a command that otherwise
-/// doesn't expand filenames, etc.
-///
-/// On execution error: fails with VimL error, updates v:errmsg.
-///
-/// @see |nvim_exec()|
-/// @see |nvim_command()|
-///
-/// @param cmd Command to execute. Must be a Dictionary that can contain the same values as
-/// the return value of |nvim_parse_cmd()| except "addr", "nargs" and "nextcmd"
-/// which are ignored if provided. All values except for "cmd" are optional.
-/// @param opts Optional parameters.
-/// - output: (boolean, default false) Whether to return command output.
-/// @param[out] err Error details, if any.
-/// @return Command output (non-error, non-shell |:!|) if `output` is true, else empty string.
-String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error *err)
- FUNC_API_SINCE(10)
-{
- exarg_T ea;
- memset(&ea, 0, sizeof(ea));
- ea.verbose_save = -1;
- ea.save_msg_silent = -1;
-
- CmdParseInfo cmdinfo;
- memset(&cmdinfo, 0, sizeof(cmdinfo));
- cmdinfo.verbose = -1;
-
- char *cmdline = NULL;
- char *cmdname = NULL;
- char **args = NULL;
- size_t argc = 0;
-
- String retv = (String)STRING_INIT;
-
-#define OBJ_TO_BOOL(var, value, default, varname) \
- do { \
- var = api_object_to_bool(value, varname, default, err); \
- if (ERROR_SET(err)) { \
- goto end; \
- } \
- } while (0)
-
-#define VALIDATION_ERROR(...) \
- do { \
- api_set_error(err, kErrorTypeValidation, __VA_ARGS__); \
- 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");
- }
-
- cmdname = string_to_cstr(cmd->cmd.data.string);
- ea.cmd = cmdname;
-
- char *p = find_ex_command(&ea, NULL);
-
- // If this looks like an undefined user command and there are CmdUndefined
- // autocommands defined, trigger the matching autocommands.
- if (p != NULL && ea.cmdidx == CMD_SIZE && ASCII_ISUPPER(*ea.cmd)
- && has_event(EVENT_CMDUNDEFINED)) {
- p = xstrdup(cmdname);
- int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
- xfree(p);
- // If the autocommands did something and didn't cause an error, try
- // finding the command again.
- 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);
- }
-
- // 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.
- if (!IS_USER_CMDIDX(ea.cmdidx)) {
- ea.argt = get_cmd_argt(ea.cmdidx);
- }
-
- // 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");
- }
- // Check if every argument is valid
- for (size_t i = 0; i < cmd->args.data.array.size; i++) {
- Object elem = cmd->args.data.array.items[i];
- if (elem.type != kObjectTypeString) {
- VALIDATION_ERROR("Command argument must be a String");
- } else if (string_iswhite(elem.data.string)) {
- VALIDATION_ERROR("Command argument must have non-whitespace characters");
- }
- }
-
- argc = cmd->args.data.array.size;
- bool argc_valid;
-
- // Check if correct number of arguments is used.
- switch (ea.argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
- case EX_EXTRA | EX_NOSPC | EX_NEEDARG:
- argc_valid = argc == 1;
- break;
- case EX_EXTRA | EX_NOSPC:
- argc_valid = argc <= 1;
- break;
- case EX_EXTRA | EX_NEEDARG:
- argc_valid = argc >= 1;
- break;
- case EX_EXTRA:
- argc_valid = true;
- break;
- default:
- argc_valid = argc == 0;
- break;
- }
-
- if (!argc_valid) {
- argc = 0; // Ensure that args array isn't erroneously freed at the end.
- VALIDATION_ERROR("Incorrect number of arguments supplied");
- }
-
- if (argc != 0) {
- args = xcalloc(argc, sizeof(char *));
-
- for (size_t i = 0; i < argc; i++) {
- args[i] = string_to_cstr(cmd->args.data.array.items[i].data.string);
- }
- }
- }
-
- // Simply pass the first argument (if it exists) as the arg pointer to `set_cmd_addr_type()`
- // since it only ever checks the first argument.
- set_cmd_addr_type(&ea, argc > 0 ? (char_u *)args[0] : 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");
- }
-
- 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");
- }
- }
-
- if (range.size > 0) {
- ea.line1 = (linenr_T)range.items[0].data.integer;
- ea.line2 = (linenr_T)range.items[range.size - 1].data.integer;
- }
-
- if (invalid_range(&ea) != NULL) {
- VALIDATION_ERROR("Invalid range provided");
- }
- }
- if (ea.addr_count == 0) {
- if (ea.argt & EX_DFLALL) {
- set_cmd_dflall_range(&ea); // Default range for range=%
- } else {
- ea.line1 = ea.line2 = get_cmd_default_range(&ea); // Default range.
-
- if (ea.addr_type == ADDR_OTHER) {
- // Default is 1, not cursor.
- ea.line2 = 1;
- }
- }
- }
-
- 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");
- }
- set_cmd_count(&ea, 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");
- }
- 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);
- }
- 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");
- }
-
- if (HAS_KEY(cmd->magic)) {
- if (cmd->magic.type != kObjectTypeDictionary) {
- VALIDATION_ERROR("'magic' must be a Dictionary");
- }
-
- Dict(cmd_magic) magic = { 0 };
- if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field,
- cmd->magic.data.dictionary, 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'");
- } else {
- cmdinfo.magic.file = ea.argt & EX_XFILE;
- cmdinfo.magic.bar = ea.argt & EX_TRLBAR;
- }
-
- if (HAS_KEY(cmd->mods)) {
- if (cmd->mods.type != kObjectTypeDictionary) {
- VALIDATION_ERROR("'mods' must be a Dictionary");
- }
-
- Dict(cmd_mods) mods = { 0 };
- if (!api_dict_to_keydict(&mods, KeyDict_cmd_mods_get_field, cmd->mods.data.dictionary, err)) {
- goto end;
- }
-
- if (HAS_KEY(mods.tab)) {
- if (mods.tab.type != kObjectTypeInteger || mods.tab.data.integer < 0) {
- VALIDATION_ERROR("'mods.tab' must be a non-negative Integer");
- }
- cmdinfo.cmdmod.tab = (int)mods.tab.data.integer + 1;
- }
-
- if (HAS_KEY(mods.verbose)) {
- if (mods.verbose.type != kObjectTypeInteger) {
- VALIDATION_ERROR("'mods.verbose' must be a Integer");
- } else if (mods.verbose.data.integer >= 0) {
- // Silently ignore negative integers to allow mods.verbose to be set to -1.
- cmdinfo.verbose = mods.verbose.data.integer;
- }
- }
-
- bool vertical;
- OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'");
- cmdinfo.cmdmod.split |= (vertical ? WSP_VERT : 0);
-
- if (HAS_KEY(mods.split)) {
- if (mods.split.type != kObjectTypeString) {
- VALIDATION_ERROR("'mods.split' must be a String");
- }
-
- if (*mods.split.data.string.data == NUL) {
- // Empty string, do nothing.
- } else if (STRCMP(mods.split.data.string.data, "aboveleft") == 0
- || STRCMP(mods.split.data.string.data, "leftabove") == 0) {
- cmdinfo.cmdmod.split |= WSP_ABOVE;
- } else if (STRCMP(mods.split.data.string.data, "belowright") == 0
- || STRCMP(mods.split.data.string.data, "rightbelow") == 0) {
- cmdinfo.cmdmod.split |= WSP_BELOW;
- } else if (STRCMP(mods.split.data.string.data, "topleft") == 0) {
- cmdinfo.cmdmod.split |= WSP_TOP;
- } else if (STRCMP(mods.split.data.string.data, "botright") == 0) {
- cmdinfo.cmdmod.split |= WSP_BOT;
- } else {
- VALIDATION_ERROR("Invalid value for 'mods.split'");
- }
- }
-
- OBJ_TO_BOOL(cmdinfo.silent, mods.silent, false, "'mods.silent'");
- OBJ_TO_BOOL(cmdinfo.emsg_silent, mods.emsg_silent, false, "'mods.emsg_silent'");
- OBJ_TO_BOOL(cmdinfo.sandbox, mods.sandbox, false, "'mods.sandbox'");
- OBJ_TO_BOOL(cmdinfo.noautocmd, mods.noautocmd, false, "'mods.noautocmd'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.browse, mods.browse, false, "'mods.browse'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.confirm, mods.confirm, false, "'mods.confirm'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.hide, mods.hide, false, "'mods.hide'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.keepalt, mods.keepalt, false, "'mods.keepalt'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.keepjumps, mods.keepjumps, false, "'mods.keepjumps'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.keepmarks, mods.keepmarks, false, "'mods.keepmarks'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.keeppatterns, mods.keeppatterns, false, "'mods.keeppatterns'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.lockmarks, mods.lockmarks, false, "'mods.lockmarks'");
- OBJ_TO_BOOL(cmdinfo.cmdmod.noswapfile, mods.noswapfile, false, "'mods.noswapfile'");
-
- if (cmdinfo.sandbox && !(ea.argt & EX_SBOXOK)) {
- VALIDATION_ERROR("Command cannot be run in sandbox");
- }
- }
-
- // Finally, build the command line string that will be stored inside ea.cmdlinep.
- // This also sets the values of ea.cmd, ea.arg, ea.args and ea.arglens.
- build_cmdline_str(&cmdline, &ea, &cmdinfo, args, argc);
- ea.cmdlinep = &cmdline;
-
- garray_T capture_local;
- const int save_msg_silent = msg_silent;
- garray_T * const save_capture_ga = capture_ga;
-
- if (output) {
- ga_init(&capture_local, 1, 80);
- capture_ga = &capture_local;
- }
-
- TRY_WRAP({
- try_start();
- if (output) {
- msg_silent++;
- }
-
- WITH_SCRIPT_CONTEXT(channel_id, {
- execute_cmd(&ea, &cmdinfo, false);
- });
-
- if (output) {
- capture_ga = save_capture_ga;
- msg_silent = save_msg_silent;
- }
-
- try_end(err);
- });
-
- if (ERROR_SET(err)) {
- goto clear_ga;
- }
-
- if (output && capture_local.ga_len > 1) {
- retv = (String){
- .data = capture_local.ga_data,
- .size = (size_t)capture_local.ga_len,
- };
- // redir usually (except :echon) prepends a newline.
- if (retv.data[0] == '\n') {
- memmove(retv.data, retv.data + 1, retv.size - 1);
- retv.data[retv.size - 1] = '\0';
- retv.size = retv.size - 1;
- }
- goto end;
- }
-clear_ga:
- if (output) {
- ga_clear(&capture_local);
- }
-end:
- xfree(cmdline);
- xfree(cmdname);
- xfree(ea.args);
- xfree(ea.arglens);
- for (size_t i = 0; i < argc; i++) {
- xfree(args[i]);
- }
- xfree(args);
-
- return retv;
-
-#undef OBJ_TO_BOOL
-#undef VALIDATION_ERROR
-}