@@ -209,8 +209,8 @@ def register_custom_actions(parser: argparse.ArgumentParser) -> None:
209209 parser .register ('action' , 'append' , _AppendRangeAction )
210210
211211
212- def token_resembles_flag (token : str , parser : argparse .ArgumentParser ) -> bool :
213- """Determine if a token looks like a flag. Based on argparse._parse_optional()."""
212+ def is_potential_flag (token : str , parser : argparse .ArgumentParser ) -> bool :
213+ """Determine if a token looks like a potential flag. Based on argparse._parse_optional()."""
214214 # if it's an empty string, it was meant to be a positional
215215 if not token :
216216 return False
@@ -340,6 +340,10 @@ def complete_command(self, tokens: List[str], text: str, line: str, begidx: int,
340340 # Skip any flags or flag parameter tokens
341341 next_pos_arg_index = 0
342342
343+ # This gets set to True when flags will no longer be processed as argparse flags
344+ # That can happen when -- is used or an argument with nargs=argparse.REMAINDER is used
345+ skip_remaining_flags = False
346+
343347 pos_arg = AutoCompleter ._ArgumentState ()
344348 pos_action = None
345349
@@ -363,7 +367,7 @@ def consume_flag_argument() -> None:
363367 """Consuming token as a flag argument"""
364368 # we're consuming flag arguments
365369 # if the token does not look like a new flag, then count towards flag arguments
366- if not token_resembles_flag (token , self ._parser ) and flag_action is not None :
370+ if not is_potential_flag (token , self ._parser ) and flag_action is not None :
367371 flag_arg .count += 1
368372
369373 # does this complete a option item for the flag
@@ -432,8 +436,20 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
432436
433437 for idx , token in enumerate (tokens ):
434438 is_last_token = idx >= len (tokens ) - 1
439+
435440 # Only start at the start token index
436441 if idx >= self ._token_start_index :
442+
443+ # all args after -- are non-flags
444+ if remainder ['arg' ] is None and token == '--' :
445+ flag_action = None
446+ flag_arg .reset ()
447+ if is_last_token :
448+ break
449+ else :
450+ skip_remaining_flags = True
451+ continue
452+
437453 # If a remainder action is found, force all future tokens to go to that
438454 if remainder ['arg' ] is not None :
439455 if remainder ['action' ] == pos_action :
@@ -442,23 +458,25 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
442458 elif remainder ['action' ] == flag_action :
443459 consume_flag_argument ()
444460 continue
461+
445462 current_is_positional = False
446463 # Are we consuming flag arguments?
447464 if not flag_arg .needed :
448- # Special case when each of the following is true:
449- # - We're not in the middle of consuming flag arguments
450- # - The current positional argument count has hit the max count
451- # - The next positional argument is a REMAINDER argument
452- # Argparse will now treat all future tokens as arguments to the positional including tokens that
453- # look like flags so the completer should skip any flag related processing once this happens
454- skip_flag = False
455- if (pos_action is not None ) and pos_arg .count >= pos_arg .max and \
456- next_pos_arg_index < len (self ._positional_actions ) and \
457- self ._positional_actions [next_pos_arg_index ].nargs == argparse .REMAINDER :
458- skip_flag = True
465+
466+ if not skip_remaining_flags :
467+ # Special case when each of the following is true:
468+ # - We're not in the middle of consuming flag arguments
469+ # - The current positional argument count has hit the max count
470+ # - The next positional argument is a REMAINDER argument
471+ # Argparse will now treat all future tokens as arguments to the positional including tokens that
472+ # look like flags so the completer should skip any flag related processing once this happens
473+ if (pos_action is not None ) and pos_arg .count >= pos_arg .max and \
474+ next_pos_arg_index < len (self ._positional_actions ) and \
475+ self ._positional_actions [next_pos_arg_index ].nargs == argparse .REMAINDER :
476+ skip_remaining_flags = True
459477
460478 # At this point we're no longer consuming flag arguments. Is the current argument a potential flag?
461- if token_resembles_flag (token , self ._parser ) and not skip_flag :
479+ if is_potential_flag (token , self ._parser ) and not skip_remaining_flags :
462480 # reset some tracking values
463481 flag_arg .reset ()
464482 # don't reset positional tracking because flags can be interspersed anywhere between positionals
@@ -524,22 +542,25 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
524542 else :
525543 consume_flag_argument ()
526544
545+ if remainder ['arg' ] is not None :
546+ skip_remaining_flags = True
547+
527548 # don't reset this if we're on the last token - this allows completion to occur on the current token
528- if not is_last_token and flag_arg .min is not None :
549+ elif not is_last_token and flag_arg .min is not None :
529550 flag_arg .needed = flag_arg .count < flag_arg .min
530551
531552 # Here we're done parsing all of the prior arguments. We know what the next argument is.
532553
554+ completion_results = []
555+
533556 # if we don't have a flag to populate with arguments and the last token starts with
534557 # a flag prefix then we'll complete the list of flag options
535- completion_results = []
536558 if not flag_arg .needed and len (tokens [- 1 ]) > 0 and tokens [- 1 ][0 ] in self ._parser .prefix_chars and \
537- remainder [ 'arg' ] is None :
559+ not skip_remaining_flags :
538560 return AutoCompleter .basic_complete (text , line , begidx , endidx ,
539561 [flag for flag in self ._flags if flag not in matched_flags ])
540562 # we're not at a positional argument, see if we're in a flag argument
541563 elif not current_is_positional :
542- # current_items = []
543564 if flag_action is not None :
544565 consumed = consumed_arg_values [flag_action .dest ]\
545566 if flag_action .dest in consumed_arg_values else []
0 commit comments