mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	feat(api): add nvim_parse_cmdline
				
					
				
			Adds an API function to parse a command line string and get command information from it.
This commit is contained in:
		@@ -1350,6 +1350,69 @@ nvim_out_write({str})                                       *nvim_out_write()*
 | 
			
		||||
                Parameters: ~
 | 
			
		||||
                    {str}  Message
 | 
			
		||||
 | 
			
		||||
nvim_parse_cmd({str}, {opts})                               *nvim_parse_cmd()*
 | 
			
		||||
                Parse command line.
 | 
			
		||||
 | 
			
		||||
                Doesn't check the validity of command arguments.
 | 
			
		||||
 | 
			
		||||
                Attributes: ~
 | 
			
		||||
                    {fast}
 | 
			
		||||
 | 
			
		||||
                Parameters: ~
 | 
			
		||||
                    {str}   Command line string to parse. Cannot contain "\n".
 | 
			
		||||
                    {opts}  Optional parameters. Reserved for future use.
 | 
			
		||||
 | 
			
		||||
                Return: ~
 | 
			
		||||
                    Dictionary containing command information, with these
 | 
			
		||||
                    keys:
 | 
			
		||||
                    • cmd: (string) Command name.
 | 
			
		||||
                    • line1: (number) Starting line of command range. Only
 | 
			
		||||
                      applicable if command can take a range.
 | 
			
		||||
                    • line2: (number) Final line of command range. Only
 | 
			
		||||
                      applicable if command can take a range.
 | 
			
		||||
                    • 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|.
 | 
			
		||||
                      • 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|.
 | 
			
		||||
 | 
			
		||||
nvim_paste({data}, {crlf}, {phase})                             *nvim_paste()*
 | 
			
		||||
                Pastes at cursor, in any mode.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1421,7 +1421,7 @@ which by default correspond to the current line, last line and the whole
 | 
			
		||||
buffer, relate to arguments, (loaded) buffers, windows or tab pages.
 | 
			
		||||
 | 
			
		||||
Possible values are (second column is the short name used in listing):
 | 
			
		||||
    -addr=lines		  	Range of lines (this is the default)
 | 
			
		||||
    -addr=lines		  line	Range of lines (this is the default)
 | 
			
		||||
    -addr=arguments	  arg	Range for arguments
 | 
			
		||||
    -addr=buffers	  buf	Range for buffers (also not loaded buffers)
 | 
			
		||||
    -addr=loaded_buffers  load	Range for loaded buffers
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@
 | 
			
		||||
#include "nvim/eval/typval.h"
 | 
			
		||||
#include "nvim/eval/userfunc.h"
 | 
			
		||||
#include "nvim/ex_cmds2.h"
 | 
			
		||||
#include "nvim/ex_cmds_defs.h"
 | 
			
		||||
#include "nvim/ex_docmd.h"
 | 
			
		||||
#include "nvim/file_search.h"
 | 
			
		||||
#include "nvim/fileio.h"
 | 
			
		||||
@@ -2460,3 +2461,203 @@ void nvim_del_user_command(String name, Error *err)
 | 
			
		||||
{
 | 
			
		||||
  nvim_buf_del_user_command(-1, name, err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// 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.
 | 
			
		||||
///         - line1: (number) Starting line of command range. Only applicable if command can take a
 | 
			
		||||
///                  range.
 | 
			
		||||
///         - line2: (number) Final line of command range. Only applicable if command can take a
 | 
			
		||||
///                  range.
 | 
			
		||||
///         - 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|.
 | 
			
		||||
///             - 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_u *cmdline = vim_strsave((char_u *)str.data);
 | 
			
		||||
 | 
			
		||||
  if (!parse_cmdline(cmdline, &ea, &cmdinfo)) {
 | 
			
		||||
    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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (ea.cmdidx == CMD_USER) {
 | 
			
		||||
    PUT(result, "cmd", CSTR_TO_OBJ((char *)USER_CMD(ea.useridx)->uc_name));
 | 
			
		||||
  } else if (ea.cmdidx == CMD_USER_BUF) {
 | 
			
		||||
    PUT(result, "cmd", CSTR_TO_OBJ((char *)USER_CMD_GA(&curbuf->b_ucmds, ea.useridx)->uc_name));
 | 
			
		||||
  } else {
 | 
			
		||||
    PUT(result, "cmd", CSTR_TO_OBJ((char *)get_command_name(NULL, ea.cmdidx)));
 | 
			
		||||
  }
 | 
			
		||||
  PUT(result, "line1", INTEGER_OBJ(ea.line1));
 | 
			
		||||
  PUT(result, "line2", INTEGER_OBJ(ea.line2));
 | 
			
		||||
  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(cmdmod.tab));
 | 
			
		||||
  PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.verbose));
 | 
			
		||||
  PUT(mods, "browse", BOOLEAN_OBJ(cmdmod.browse));
 | 
			
		||||
  PUT(mods, "confirm", BOOLEAN_OBJ(cmdmod.confirm));
 | 
			
		||||
  PUT(mods, "hide", BOOLEAN_OBJ(cmdmod.hide));
 | 
			
		||||
  PUT(mods, "keepalt", BOOLEAN_OBJ(cmdmod.keepalt));
 | 
			
		||||
  PUT(mods, "keepjumps", BOOLEAN_OBJ(cmdmod.keepjumps));
 | 
			
		||||
  PUT(mods, "keepmarks", BOOLEAN_OBJ(cmdmod.keepmarks));
 | 
			
		||||
  PUT(mods, "keeppatterns", BOOLEAN_OBJ(cmdmod.keeppatterns));
 | 
			
		||||
  PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdmod.lockmarks));
 | 
			
		||||
  PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdmod.noswapfile));
 | 
			
		||||
  PUT(mods, "vertical", BOOLEAN_OBJ(cmdmod.split & WSP_VERT));
 | 
			
		||||
 | 
			
		||||
  const char *split;
 | 
			
		||||
  if (cmdmod.split & WSP_BOT) {
 | 
			
		||||
    split = "botright";
 | 
			
		||||
  } else if (cmdmod.split & WSP_TOP) {
 | 
			
		||||
    split = "topleft";
 | 
			
		||||
  } else if (cmdmod.split & WSP_BELOW) {
 | 
			
		||||
    split = "belowright";
 | 
			
		||||
  } else if (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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -261,4 +261,18 @@ typedef struct {
 | 
			
		||||
  bool filter_force;           ///< set for :filter!
 | 
			
		||||
} cmdmod_T;
 | 
			
		||||
 | 
			
		||||
/// Stores command modifier info used by `nvim_parse_cmd`
 | 
			
		||||
typedef struct {
 | 
			
		||||
  bool silent;
 | 
			
		||||
  bool emsg_silent;
 | 
			
		||||
  bool sandbox;
 | 
			
		||||
  bool noautocmd;
 | 
			
		||||
  long verbose;
 | 
			
		||||
  cmdmod_T cmdmod;
 | 
			
		||||
  struct {
 | 
			
		||||
    bool file;
 | 
			
		||||
    bool bar;
 | 
			
		||||
  } magic;
 | 
			
		||||
} CmdParseInfo;
 | 
			
		||||
 | 
			
		||||
#endif  // NVIM_EX_CMDS_DEFS_H
 | 
			
		||||
 
 | 
			
		||||
@@ -1216,6 +1216,226 @@ static char *skip_colon_white(const char *p, bool skipleadingwhite)
 | 
			
		||||
  return (char *)p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Set the addr type for command
 | 
			
		||||
///
 | 
			
		||||
/// @param p pointer to character after command name in cmdline
 | 
			
		||||
static void set_cmd_addr_type(exarg_T *eap, char_u *p)
 | 
			
		||||
{
 | 
			
		||||
  // ea.addr_type for user commands is set by find_ucmd
 | 
			
		||||
  if (IS_USER_CMDIDX(eap->cmdidx)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (eap->cmdidx != CMD_SIZE) {
 | 
			
		||||
    eap->addr_type = cmdnames[(int)eap->cmdidx].cmd_addr_type;
 | 
			
		||||
  } else {
 | 
			
		||||
    eap->addr_type = ADDR_LINES;
 | 
			
		||||
  }
 | 
			
		||||
  // :wincmd range depends on the argument
 | 
			
		||||
  if (eap->cmdidx == CMD_wincmd && p != NULL) {
 | 
			
		||||
    get_wincmd_addr_type((char *)skipwhite((char_u *)p), eap);
 | 
			
		||||
  }
 | 
			
		||||
  // :.cc in quickfix window uses line number
 | 
			
		||||
  if ((eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) && bt_quickfix(curbuf)) {
 | 
			
		||||
    eap->addr_type = ADDR_OTHER;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Set default command range based on the addr type of the command
 | 
			
		||||
static void set_cmd_default_range(exarg_T *eap)
 | 
			
		||||
{
 | 
			
		||||
  buf_T *buf;
 | 
			
		||||
 | 
			
		||||
  eap->line1 = 1;
 | 
			
		||||
  switch (eap->addr_type) {
 | 
			
		||||
  case ADDR_LINES:
 | 
			
		||||
  case ADDR_OTHER:
 | 
			
		||||
    eap->line2 = curbuf->b_ml.ml_line_count;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_LOADED_BUFFERS:
 | 
			
		||||
    buf = firstbuf;
 | 
			
		||||
    while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
 | 
			
		||||
      buf = buf->b_next;
 | 
			
		||||
    }
 | 
			
		||||
    eap->line1 = buf->b_fnum;
 | 
			
		||||
    buf = lastbuf;
 | 
			
		||||
    while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
 | 
			
		||||
      buf = buf->b_prev;
 | 
			
		||||
    }
 | 
			
		||||
    eap->line2 = buf->b_fnum;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_BUFFERS:
 | 
			
		||||
    eap->line1 = firstbuf->b_fnum;
 | 
			
		||||
    eap->line2 = lastbuf->b_fnum;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_WINDOWS:
 | 
			
		||||
    eap->line2 = LAST_WIN_NR;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_TABS:
 | 
			
		||||
    eap->line2 = LAST_TAB_NR;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_TABS_RELATIVE:
 | 
			
		||||
    eap->line2 = 1;
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_ARGUMENTS:
 | 
			
		||||
    if (ARGCOUNT == 0) {
 | 
			
		||||
      eap->line1 = eap->line2 = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
      eap->line2 = ARGCOUNT;
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_QUICKFIX_VALID:
 | 
			
		||||
    eap->line2 = (linenr_T)qf_get_valid_size(eap);
 | 
			
		||||
    if (eap->line2 == 0) {
 | 
			
		||||
      eap->line2 = 1;
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  case ADDR_NONE:
 | 
			
		||||
  case ADDR_UNSIGNED:
 | 
			
		||||
  case ADDR_QUICKFIX:
 | 
			
		||||
    iemsg(_("INTERNAL: Cannot use EX_DFLALL "
 | 
			
		||||
            "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Parse command line and return information about the first command.
 | 
			
		||||
///
 | 
			
		||||
/// @return Success or failure
 | 
			
		||||
bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
 | 
			
		||||
{
 | 
			
		||||
  char *errormsg = NULL;
 | 
			
		||||
  char *cmd;
 | 
			
		||||
  char *p;
 | 
			
		||||
 | 
			
		||||
  // Initialize cmdinfo
 | 
			
		||||
  memset(cmdinfo, 0, sizeof(*cmdinfo));
 | 
			
		||||
 | 
			
		||||
  // Initialize eap
 | 
			
		||||
  memset(eap, 0, sizeof(*eap));
 | 
			
		||||
  eap->line1 = 1;
 | 
			
		||||
  eap->line2 = 1;
 | 
			
		||||
  eap->cmd = (char *)cmdline;
 | 
			
		||||
  eap->cmdlinep = &cmdline;
 | 
			
		||||
  eap->getline = NULL;
 | 
			
		||||
  eap->cookie = NULL;
 | 
			
		||||
 | 
			
		||||
  // Parse command modifiers
 | 
			
		||||
  if (parse_command_modifiers(eap, &errormsg, false) == FAIL) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  // Revert the side-effects of `parse_command_modifiers`
 | 
			
		||||
  if (eap->save_msg_silent != -1) {
 | 
			
		||||
    cmdinfo->silent = !!msg_silent;
 | 
			
		||||
    msg_silent = eap->save_msg_silent;
 | 
			
		||||
  }
 | 
			
		||||
  if (eap->did_esilent) {
 | 
			
		||||
    cmdinfo->emsg_silent = true;
 | 
			
		||||
    emsg_silent--;
 | 
			
		||||
  }
 | 
			
		||||
  if (eap->did_sandbox) {
 | 
			
		||||
    cmdinfo->sandbox = true;
 | 
			
		||||
    sandbox--;
 | 
			
		||||
  }
 | 
			
		||||
  if (cmdmod.save_ei != NULL) {
 | 
			
		||||
    cmdinfo->noautocmd = true;
 | 
			
		||||
    set_string_option_direct("ei", -1, cmdmod.save_ei, OPT_FREE, SID_NONE);
 | 
			
		||||
    free_string_option(cmdmod.save_ei);
 | 
			
		||||
  }
 | 
			
		||||
  if (eap->verbose_save != -1) {
 | 
			
		||||
    cmdinfo->verbose = p_verbose;
 | 
			
		||||
    p_verbose = eap->verbose_save;
 | 
			
		||||
  }
 | 
			
		||||
  cmdinfo->cmdmod = cmdmod;
 | 
			
		||||
 | 
			
		||||
  // Save location after command modifiers
 | 
			
		||||
  cmd = eap->cmd;
 | 
			
		||||
  // Skip ranges to find command name since we need the command to know what kind of range it uses
 | 
			
		||||
  eap->cmd = skip_range(eap->cmd, NULL);
 | 
			
		||||
  if (*eap->cmd == '*') {
 | 
			
		||||
    eap->cmd = (char *)skipwhite((char_u *)eap->cmd + 1);
 | 
			
		||||
  }
 | 
			
		||||
  p = find_command(eap, NULL);
 | 
			
		||||
 | 
			
		||||
  // Set command attribute type and parse command range
 | 
			
		||||
  set_cmd_addr_type(eap, (char_u *)p);
 | 
			
		||||
  eap->cmd = cmd;
 | 
			
		||||
  if (parse_cmd_address(eap, &errormsg, false) == FAIL) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Skip colon and whitespace
 | 
			
		||||
  eap->cmd = skip_colon_white(eap->cmd, true);
 | 
			
		||||
  // Fail if command is a comment or if command doesn't exist
 | 
			
		||||
  if (*eap->cmd == NUL || *eap->cmd == '"') {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  // Fail if command is invalid
 | 
			
		||||
  if (eap->cmdidx == CMD_SIZE) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Correctly set 'forceit' for commands
 | 
			
		||||
  if (*p == '!' && eap->cmdidx != CMD_substitute
 | 
			
		||||
      && eap->cmdidx != CMD_smagic && eap->cmdidx != CMD_snomagic) {
 | 
			
		||||
    p++;
 | 
			
		||||
    eap->forceit = true;
 | 
			
		||||
  } else {
 | 
			
		||||
    eap->forceit = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Parse arguments.
 | 
			
		||||
  if (!IS_USER_CMDIDX(eap->cmdidx)) {
 | 
			
		||||
    eap->argt = cmdnames[(int)eap->cmdidx].cmd_argt;
 | 
			
		||||
  }
 | 
			
		||||
  // Skip to start of argument.
 | 
			
		||||
  // Don't do this for the ":!" command, because ":!! -l" needs the space.
 | 
			
		||||
  if (eap->cmdidx == CMD_bang) {
 | 
			
		||||
    eap->arg = (char_u *)p;
 | 
			
		||||
  } else {
 | 
			
		||||
    eap->arg = skipwhite((char_u *)p);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Don't treat ":r! filter" like a bang
 | 
			
		||||
  if (eap->cmdidx == CMD_read) {
 | 
			
		||||
    if (eap->forceit) {
 | 
			
		||||
      eap->forceit = false;                     // :r! filter
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Check for '|' to separate commands and '"' to start comments.
 | 
			
		||||
  // Don't do this for ":read !cmd" and ":write !cmd".
 | 
			
		||||
  if ((eap->argt & EX_TRLBAR)) {
 | 
			
		||||
    separate_nextcmd(eap);
 | 
			
		||||
  }
 | 
			
		||||
  // Fail if command doesn't support bang but is used with a bang
 | 
			
		||||
  if (!(eap->argt & EX_BANG) && eap->forceit) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  // Fail if command doesn't support a range but it is given a range
 | 
			
		||||
  if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  // Set default range for command if required
 | 
			
		||||
  if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) {
 | 
			
		||||
    set_cmd_default_range(eap);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Remove leading whitespace and colon from next command
 | 
			
		||||
  if (eap->nextcmd) {
 | 
			
		||||
    eap->nextcmd = (char_u *)skip_colon_white((char *)eap->nextcmd, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set the "magic" values (characters that get treated specially)
 | 
			
		||||
  if (eap->argt & EX_XFILE) {
 | 
			
		||||
    cmdinfo->magic.file = true;
 | 
			
		||||
  }
 | 
			
		||||
  if (eap->argt & EX_TRLBAR) {
 | 
			
		||||
    cmdinfo->magic.bar = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Execute one Ex command.
 | 
			
		||||
///
 | 
			
		||||
/// If 'sourcing' is TRUE, the command will be included in the error message.
 | 
			
		||||
@@ -1361,23 +1581,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
 | 
			
		||||
  // The ea.cmd pointer is updated to point to the first character following the
 | 
			
		||||
  // range spec. If an initial address is found, but no second, the upper bound
 | 
			
		||||
  // is equal to the lower.
 | 
			
		||||
 | 
			
		||||
  // ea.addr_type for user commands is set by find_ucmd
 | 
			
		||||
  if (!IS_USER_CMDIDX(ea.cmdidx)) {
 | 
			
		||||
    if (ea.cmdidx != CMD_SIZE) {
 | 
			
		||||
      ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type;
 | 
			
		||||
    } else {
 | 
			
		||||
      ea.addr_type = ADDR_LINES;
 | 
			
		||||
    }
 | 
			
		||||
    // :wincmd range depends on the argument
 | 
			
		||||
    if (ea.cmdidx == CMD_wincmd && p != NULL) {
 | 
			
		||||
      get_wincmd_addr_type((char *)skipwhite((char_u *)p), &ea);
 | 
			
		||||
    }
 | 
			
		||||
    // :.cc in quickfix window uses line number
 | 
			
		||||
    if ((ea.cmdidx == CMD_cc || ea.cmdidx == CMD_ll) && bt_quickfix(curbuf)) {
 | 
			
		||||
      ea.addr_type = ADDR_OTHER;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  set_cmd_addr_type(&ea, (char_u *)p);
 | 
			
		||||
 | 
			
		||||
  ea.cmd = cmd;
 | 
			
		||||
  if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
 | 
			
		||||
@@ -1690,59 +1894,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((ea.argt & EX_DFLALL) && ea.addr_count == 0) {
 | 
			
		||||
    buf_T *buf;
 | 
			
		||||
 | 
			
		||||
    ea.line1 = 1;
 | 
			
		||||
    switch (ea.addr_type) {
 | 
			
		||||
    case ADDR_LINES:
 | 
			
		||||
    case ADDR_OTHER:
 | 
			
		||||
      ea.line2 = curbuf->b_ml.ml_line_count;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_LOADED_BUFFERS:
 | 
			
		||||
      buf = firstbuf;
 | 
			
		||||
      while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
 | 
			
		||||
        buf = buf->b_next;
 | 
			
		||||
      }
 | 
			
		||||
      ea.line1 = buf->b_fnum;
 | 
			
		||||
      buf = lastbuf;
 | 
			
		||||
      while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
 | 
			
		||||
        buf = buf->b_prev;
 | 
			
		||||
      }
 | 
			
		||||
      ea.line2 = buf->b_fnum;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_BUFFERS:
 | 
			
		||||
      ea.line1 = firstbuf->b_fnum;
 | 
			
		||||
      ea.line2 = lastbuf->b_fnum;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_WINDOWS:
 | 
			
		||||
      ea.line2 = LAST_WIN_NR;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_TABS:
 | 
			
		||||
      ea.line2 = LAST_TAB_NR;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_TABS_RELATIVE:
 | 
			
		||||
      ea.line2 = 1;
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_ARGUMENTS:
 | 
			
		||||
      if (ARGCOUNT == 0) {
 | 
			
		||||
        ea.line1 = ea.line2 = 0;
 | 
			
		||||
      } else {
 | 
			
		||||
        ea.line2 = ARGCOUNT;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_QUICKFIX_VALID:
 | 
			
		||||
      ea.line2 = (linenr_T)qf_get_valid_size(&ea);
 | 
			
		||||
      if (ea.line2 == 0) {
 | 
			
		||||
        ea.line2 = 1;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case ADDR_NONE:
 | 
			
		||||
    case ADDR_UNSIGNED:
 | 
			
		||||
    case ADDR_QUICKFIX:
 | 
			
		||||
      iemsg(_("INTERNAL: Cannot use EX_DFLALL "
 | 
			
		||||
              "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    set_cmd_default_range(&ea);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // accept numbered register only when no count allowed (:put)
 | 
			
		||||
 
 | 
			
		||||
@@ -3098,4 +3098,296 @@ describe('API', function()
 | 
			
		||||
      end)
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
  describe('nvim_parse_cmd', function()
 | 
			
		||||
    it('works', function()
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'echo',
 | 
			
		||||
        args = { 'foo' },
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 1,
 | 
			
		||||
        line2 = 1,
 | 
			
		||||
        addr = 'none',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = false,
 | 
			
		||||
            bar = false
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '*',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('echo foo', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works with ranges', function()
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'substitute',
 | 
			
		||||
        args = { '/math.random/math.max/' },
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 4,
 | 
			
		||||
        line2 = 6,
 | 
			
		||||
        addr = 'line',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = false,
 | 
			
		||||
            bar = false
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '*',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('4,6s/math.random/math.max/', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works with bang', function()
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'write',
 | 
			
		||||
        args = {},
 | 
			
		||||
        bang = true,
 | 
			
		||||
        line1 = 1,
 | 
			
		||||
        line2 = 1,
 | 
			
		||||
        addr = 'line',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = true,
 | 
			
		||||
            bar = true
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '?',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        },
 | 
			
		||||
      }, meths.parse_cmd('w!', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works with modifiers', function()
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'split',
 | 
			
		||||
        args = { 'foo.txt' },
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 1,
 | 
			
		||||
        line2 = 1,
 | 
			
		||||
        addr = '?',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = true,
 | 
			
		||||
            bar = true
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '?',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = true,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = true,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "topleft",
 | 
			
		||||
          tab = 2,
 | 
			
		||||
          verbose = 15
 | 
			
		||||
        },
 | 
			
		||||
      }, meths.parse_cmd('15verbose silent! aboveleft topleft tab split foo.txt', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works with user commands', function()
 | 
			
		||||
      command('command -bang -nargs=+ -range -addr=lines MyCommand echo foo')
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'MyCommand',
 | 
			
		||||
        args = { 'test', 'it' },
 | 
			
		||||
        bang = true,
 | 
			
		||||
        line1 = 4,
 | 
			
		||||
        line2 = 6,
 | 
			
		||||
        addr = 'line',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = false,
 | 
			
		||||
            bar = false
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '+',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('4,6MyCommand! test it', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works for commands separated by bar', function()
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'argadd',
 | 
			
		||||
        args = { 'a.txt' },
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 0,
 | 
			
		||||
        line2 = 0,
 | 
			
		||||
        addr = 'arg',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = true,
 | 
			
		||||
            bar = true
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '*',
 | 
			
		||||
        nextcmd = 'argadd b.txt',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('argadd a.txt | argadd b.txt', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('works for nargs=1', function()
 | 
			
		||||
      command('command -nargs=1 MyCommand echo <q-args>')
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'MyCommand',
 | 
			
		||||
        args = { 'test it' },
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 1,
 | 
			
		||||
        line2 = 1,
 | 
			
		||||
        addr = 'none',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = false,
 | 
			
		||||
            bar = false
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '1',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('MyCommand test it', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('sets correct default range', function()
 | 
			
		||||
      command('command -range=% -addr=buffers MyCommand echo foo')
 | 
			
		||||
      command('new')
 | 
			
		||||
      eq({
 | 
			
		||||
        cmd = 'MyCommand',
 | 
			
		||||
        args = {},
 | 
			
		||||
        bang = false,
 | 
			
		||||
        line1 = 1,
 | 
			
		||||
        line2 = 2,
 | 
			
		||||
        addr = 'buf',
 | 
			
		||||
        magic = {
 | 
			
		||||
            file = false,
 | 
			
		||||
            bar = false
 | 
			
		||||
        },
 | 
			
		||||
        nargs = '0',
 | 
			
		||||
        nextcmd = '',
 | 
			
		||||
        mods = {
 | 
			
		||||
          browse = false,
 | 
			
		||||
          confirm = false,
 | 
			
		||||
          emsg_silent = false,
 | 
			
		||||
          hide = false,
 | 
			
		||||
          keepalt = false,
 | 
			
		||||
          keepjumps = false,
 | 
			
		||||
          keepmarks = false,
 | 
			
		||||
          keeppatterns = false,
 | 
			
		||||
          lockmarks = false,
 | 
			
		||||
          noautocmd = false,
 | 
			
		||||
          noswapfile = false,
 | 
			
		||||
          sandbox = false,
 | 
			
		||||
          silent = false,
 | 
			
		||||
          vertical = false,
 | 
			
		||||
          split = "",
 | 
			
		||||
          tab = 0,
 | 
			
		||||
          verbose = 0
 | 
			
		||||
        }
 | 
			
		||||
      }, meths.parse_cmd('MyCommand', {}))
 | 
			
		||||
    end)
 | 
			
		||||
    it('errors for invalid command', function()
 | 
			
		||||
      eq('Error while parsing command line', pcall_err(meths.parse_cmd, 'Fubar', {}))
 | 
			
		||||
      command('command! Fubar echo foo')
 | 
			
		||||
      eq('Error while parsing command line', pcall_err(meths.parse_cmd, 'Fubar!', {}))
 | 
			
		||||
      eq('Error while parsing command line', pcall_err(meths.parse_cmd, '4,6Fubar', {}))
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user