@@ -2033,18 +2033,22 @@ def _run_macro(self, statement: Statement) -> bool:
20332033 :param statement: the parsed statement from the command line
20342034 :return: a flag indicating whether the interpretation of commands should stop
20352035 """
2036+ from itertools import islice
2037+
20362038 if statement .command not in self .macros .keys ():
20372039 raise KeyError ('{} is not a macro' .format (statement .command ))
20382040
20392041 macro = self .macros [statement .command ]
20402042
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 ),
20442047 traceback_war = False )
20452048 return False
20462049
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.
20482052 resolved = macro .value
20492053 reverse_arg_list = sorted (macro .arg_list , key = lambda ma : ma .start_index , reverse = True )
20502054
@@ -2059,6 +2063,10 @@ def _run_macro(self, statement: Statement) -> bool:
20592063 parts = resolved .rsplit (to_replace , maxsplit = 1 )
20602064 resolved = parts [0 ] + replacement + parts [1 ]
20612065
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+
20622070 # Run the resolved command
20632071 return self .onecmd_plus_hooks (resolved )
20642072
@@ -2407,7 +2415,7 @@ def macro_create(self, args: argparse.Namespace):
24072415
24082416 # Set the macro
24092417 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 )
24112419 self .poutput ("Macro '{}' {}" .format (args .name , result ))
24122420
24132421 def macro_delete (self , args : argparse .Namespace ):
@@ -2469,6 +2477,8 @@ def macro_list(self, args: argparse.Namespace):
24692477 "Notes:\n "
24702478 " To use the literal string {1} in your command, escape it this way: {{1}}.\n "
24712479 "\n "
2480+ " Extra arguments passed when calling a macro are tacked onto resolved command.\n "
2481+ "\n "
24722482 " An argument number can be repeated in a macro. In the following example the\n "
24732483 " first argument will populate both {1} instances.\n "
24742484 "\n "
0 commit comments