@@ -209,8 +209,8 @@ def register_custom_actions(parser: argparse.ArgumentParser) -> None:
209
209
parser .register ('action' , 'append' , _AppendRangeAction )
210
210
211
211
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()."""
214
214
# if it's an empty string, it was meant to be a positional
215
215
if not token :
216
216
return False
@@ -340,6 +340,10 @@ def complete_command(self, tokens: List[str], text: str, line: str, begidx: int,
340
340
# Skip any flags or flag parameter tokens
341
341
next_pos_arg_index = 0
342
342
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
+
343
347
pos_arg = AutoCompleter ._ArgumentState ()
344
348
pos_action = None
345
349
@@ -363,7 +367,7 @@ def consume_flag_argument() -> None:
363
367
"""Consuming token as a flag argument"""
364
368
# we're consuming flag arguments
365
369
# 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 :
367
371
flag_arg .count += 1
368
372
369
373
# does this complete a option item for the flag
@@ -432,8 +436,20 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
432
436
433
437
for idx , token in enumerate (tokens ):
434
438
is_last_token = idx >= len (tokens ) - 1
439
+
435
440
# Only start at the start token index
436
441
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
+
437
453
# If a remainder action is found, force all future tokens to go to that
438
454
if remainder ['arg' ] is not None :
439
455
if remainder ['action' ] == pos_action :
@@ -442,23 +458,25 @@ def process_action_nargs(action: argparse.Action, arg_state: AutoCompleter._Argu
442
458
elif remainder ['action' ] == flag_action :
443
459
consume_flag_argument ()
444
460
continue
461
+
445
462
current_is_positional = False
446
463
# Are we consuming flag arguments?
447
464
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
459
477
460
478
# 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 :
462
480
# reset some tracking values
463
481
flag_arg .reset ()
464
482
# 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
524
542
else :
525
543
consume_flag_argument ()
526
544
545
+ if remainder ['arg' ] is not None :
546
+ skip_remaining_flags = True
547
+
527
548
# 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 :
529
550
flag_arg .needed = flag_arg .count < flag_arg .min
530
551
531
552
# Here we're done parsing all of the prior arguments. We know what the next argument is.
532
553
554
+ completion_results = []
555
+
533
556
# if we don't have a flag to populate with arguments and the last token starts with
534
557
# a flag prefix then we'll complete the list of flag options
535
- completion_results = []
536
558
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 :
538
560
return AutoCompleter .basic_complete (text , line , begidx , endidx ,
539
561
[flag for flag in self ._flags if flag not in matched_flags ])
540
562
# we're not at a positional argument, see if we're in a flag argument
541
563
elif not current_is_positional :
542
- # current_items = []
543
564
if flag_action is not None :
544
565
consumed = consumed_arg_values [flag_action .dest ]\
545
566
if flag_action .dest in consumed_arg_values else []
0 commit comments