@@ -2033,18 +2033,22 @@ def _run_macro(self, statement: Statement) -> bool:
2033
2033
:param statement: the parsed statement from the command line
2034
2034
:return: a flag indicating whether the interpretation of commands should stop
2035
2035
"""
2036
+ from itertools import islice
2037
+
2036
2038
if statement .command not in self .macros .keys ():
2037
2039
raise KeyError ('{} is not a macro' .format (statement .command ))
2038
2040
2039
2041
macro = self .macros [statement .command ]
2040
2042
2041
- # For macros, every argument must be provided and there can be no extra arguments.
2042
- if len (statement .arg_list ) != macro .required_arg_count :
2043
- self .perror ("The macro '{}' expects {} argument(s)" .format (statement .command , macro .required_arg_count ),
2043
+ # Make sure enough arguments were passed in
2044
+ if len (statement .arg_list ) < macro .minimum_arg_count :
2045
+ self .perror ("The macro '{}' expects at least {} argument(s)" .format (statement .command ,
2046
+ macro .minimum_arg_count ),
2044
2047
traceback_war = False )
2045
2048
return False
2046
2049
2047
- # Resolve the arguments in reverse
2050
+ # Resolve the arguments in reverse and read their values from statement.argv since those
2051
+ # are unquoted. Macro args should have been quoted when the macro was created.
2048
2052
resolved = macro .value
2049
2053
reverse_arg_list = sorted (macro .arg_list , key = lambda ma : ma .start_index , reverse = True )
2050
2054
@@ -2059,6 +2063,10 @@ def _run_macro(self, statement: Statement) -> bool:
2059
2063
parts = resolved .rsplit (to_replace , maxsplit = 1 )
2060
2064
resolved = parts [0 ] + replacement + parts [1 ]
2061
2065
2066
+ # Append extra arguments and use statement.arg_list since these arguments need their quotes preserved
2067
+ for arg in islice (statement .arg_list , macro .minimum_arg_count , None ):
2068
+ resolved += ' ' + arg
2069
+
2062
2070
# Run the resolved command
2063
2071
return self .onecmd_plus_hooks (resolved )
2064
2072
@@ -2407,7 +2415,7 @@ def macro_create(self, args: argparse.Namespace):
2407
2415
2408
2416
# Set the macro
2409
2417
result = "overwritten" if args .name in self .macros else "created"
2410
- self .macros [args .name ] = Macro (name = args .name , value = value , required_arg_count = max_arg_num , arg_list = arg_list )
2418
+ self .macros [args .name ] = Macro (name = args .name , value = value , minimum_arg_count = max_arg_num , arg_list = arg_list )
2411
2419
self .poutput ("Macro '{}' {}" .format (args .name , result ))
2412
2420
2413
2421
def macro_delete (self , args : argparse .Namespace ):
@@ -2469,6 +2477,8 @@ def macro_list(self, args: argparse.Namespace):
2469
2477
"Notes:\n "
2470
2478
" To use the literal string {1} in your command, escape it this way: {{1}}.\n "
2471
2479
"\n "
2480
+ " Extra arguments passed when calling a macro are tacked onto resolved command.\n "
2481
+ "\n "
2472
2482
" An argument number can be repeated in a macro. In the following example the\n "
2473
2483
" first argument will populate both {1} instances.\n "
2474
2484
"\n "
0 commit comments