summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorKevin Van Brunt <kmvanbrunt@gmail.com>2018-10-12 13:26:27 -0400
committerKevin Van Brunt <kmvanbrunt@gmail.com>2018-10-12 13:26:27 -0400
commit53b976a7aeae88f811391820ca93aaa21b6501e9 (patch)
tree5ff4f56b0eee7191b6079039eadb722966e8565d /cmd2
parentb216987165d7783903e02db006cf5055f2615796 (diff)
downloadcmd2-git-53b976a7aeae88f811391820ca93aaa21b6501e9.tar.gz
You can now call a macro with extra arguments
Diffstat (limited to 'cmd2')
-rw-r--r--cmd2/cmd2.py20
-rw-r--r--cmd2/parsing.py4
2 files changed, 17 insertions, 7 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index e09f428d..66ae0968 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -2033,18 +2033,22 @@ class Cmd(cmd.Cmd):
:param statement: the parsed statement from the command line
:return: a flag indicating whether the interpretation of commands should stop
"""
+ from itertools import islice
+
if statement.command not in self.macros.keys():
raise KeyError('{} is not a macro'.format(statement.command))
macro = self.macros[statement.command]
- # For macros, every argument must be provided and there can be no extra arguments.
- if len(statement.arg_list) != macro.required_arg_count:
- self.perror("The macro '{}' expects {} argument(s)".format(statement.command, macro.required_arg_count),
+ # Make sure enough arguments were passed in
+ if len(statement.arg_list) < macro.minimum_arg_count:
+ self.perror("The macro '{}' expects at least {} argument(s)".format(statement.command,
+ macro.minimum_arg_count),
traceback_war=False)
return False
- # Resolve the arguments in reverse
+ # Resolve the arguments in reverse and read their values from statement.argv since those
+ # are unquoted. Macro args should have been quoted when the macro was created.
resolved = macro.value
reverse_arg_list = sorted(macro.arg_list, key=lambda ma: ma.start_index, reverse=True)
@@ -2059,6 +2063,10 @@ class Cmd(cmd.Cmd):
parts = resolved.rsplit(to_replace, maxsplit=1)
resolved = parts[0] + replacement + parts[1]
+ # Append extra arguments and use statement.arg_list since these arguments need their quotes preserved
+ for arg in islice(statement.arg_list, macro.minimum_arg_count, None):
+ resolved += ' ' + arg
+
# Run the resolved command
return self.onecmd_plus_hooks(resolved)
@@ -2407,7 +2415,7 @@ class Cmd(cmd.Cmd):
# Set the macro
result = "overwritten" if args.name in self.macros else "created"
- self.macros[args.name] = Macro(name=args.name, value=value, required_arg_count=max_arg_num, arg_list=arg_list)
+ self.macros[args.name] = Macro(name=args.name, value=value, minimum_arg_count=max_arg_num, arg_list=arg_list)
self.poutput("Macro '{}' {}".format(args.name, result))
def macro_delete(self, args: argparse.Namespace):
@@ -2469,6 +2477,8 @@ class Cmd(cmd.Cmd):
"Notes:\n"
" To use the literal string {1} in your command, escape it this way: {{1}}.\n"
"\n"
+ " Extra arguments passed when calling a macro are tacked onto resolved command.\n"
+ "\n"
" An argument number can be repeated in a macro. In the following example the\n"
" first argument will populate both {1} instances.\n"
"\n"
diff --git a/cmd2/parsing.py b/cmd2/parsing.py
index e90eac43..d5c67ae0 100644
--- a/cmd2/parsing.py
+++ b/cmd2/parsing.py
@@ -55,8 +55,8 @@ class Macro:
# The string the macro resolves to
value = attr.ib(validator=attr.validators.instance_of(str))
- # The required number of args the user has to pass to this macro
- required_arg_count = attr.ib(validator=attr.validators.instance_of(int))
+ # The minimum number of args the user has to pass to this macro
+ minimum_arg_count = attr.ib(validator=attr.validators.instance_of(int))
# Used to fill in argument placeholders in the macro
arg_list = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list))