1515from . import cmd2
1616from . import utils
1717from .ansi import ansi_safe_wcswidth , style_error
18+ from .argparse_custom import ATTR_CHOICES_CALLABLE , INFINITY , generate_range_error
1819from .argparse_custom import ATTR_SUPPRESS_TAB_HINT , ATTR_DESCRIPTIVE_COMPLETION_HEADER , ATTR_NARGS_RANGE
19- from .argparse_custom import ChoicesCallable , CompletionItem , ATTR_CHOICES_CALLABLE , INFINITY , generate_range_error
20+ from .argparse_custom import ChoicesCallable , CompletionError , CompletionItem
2021from .rl_utils import rl_force_redisplay
2122
2223# If no descriptive header is supplied, then this will be used instead
@@ -319,8 +320,12 @@ def consume_argument(arg_state: AutoCompleter._ArgumentState) -> None:
319320
320321 # Check if we are completing a flag's argument
321322 if flag_arg_state is not None :
322- completion_results = self ._complete_for_arg (flag_arg_state .action , text , line ,
323- begidx , endidx , consumed_arg_values )
323+ try :
324+ completion_results = self ._complete_for_arg (flag_arg_state .action , text , line ,
325+ begidx , endidx , consumed_arg_values )
326+ except CompletionError as ex :
327+ self ._print_completion_error (flag_arg_state .action , ex )
328+ return []
324329
325330 # If we have results, then return them
326331 if completion_results :
@@ -341,8 +346,12 @@ def consume_argument(arg_state: AutoCompleter._ArgumentState) -> None:
341346 action = self ._positional_actions [pos_index ]
342347 pos_arg_state = AutoCompleter ._ArgumentState (action )
343348
344- completion_results = self ._complete_for_arg (pos_arg_state .action , text , line ,
345- begidx , endidx , consumed_arg_values )
349+ try :
350+ completion_results = self ._complete_for_arg (pos_arg_state .action , text , line ,
351+ begidx , endidx , consumed_arg_values )
352+ except CompletionError as ex :
353+ self ._print_completion_error (pos_arg_state .action , ex )
354+ return []
346355
347356 # If we have results, then return them
348357 if completion_results :
@@ -456,7 +465,11 @@ def format_help(self, tokens: List[str]) -> str:
456465 def _complete_for_arg (self , arg_action : argparse .Action ,
457466 text : str , line : str , begidx : int , endidx : int ,
458467 consumed_arg_values : Dict [str , List [str ]]) -> List [str ]:
459- """Tab completion routine for an argparse argument"""
468+ """
469+ Tab completion routine for an argparse argument
470+ :return: list of completions
471+ :raises CompletionError if the completer or choices function this calls raises one
472+ """
460473 # Check if the arg provides choices to the user
461474 if arg_action .choices is not None :
462475 arg_choices = arg_action .choices
@@ -520,53 +533,72 @@ def _complete_for_arg(self, arg_action: argparse.Action,
520533 return self ._format_completions (arg_action , results )
521534
522535 @staticmethod
523- def _print_arg_hint (arg_action : argparse .Action ) -> None :
524- """Print argument hint to the terminal when tab completion results in no results"""
525-
526- # Check if hinting is disabled
527- suppress_hint = getattr (arg_action , ATTR_SUPPRESS_TAB_HINT , False )
528- if suppress_hint or arg_action .help == argparse .SUPPRESS or arg_action .dest == argparse .SUPPRESS :
529- return
530-
536+ def _format_message_prefix (arg_action : argparse .Action ) -> str :
537+ """Format the arg prefix text that appears before messages printed to the user"""
531538 # Check if this is a flag
532539 if arg_action .option_strings :
533540 flags = ', ' .join (arg_action .option_strings )
534541 param = ' ' + str (arg_action .dest ).upper ()
535- prefix = '{}{}' .format (flags , param )
542+ return '{}{}' .format (flags , param )
536543
537544 # Otherwise this is a positional
538545 else :
539- prefix = '{}' .format (str (arg_action .dest ).upper ())
546+ return '{}' .format (str (arg_action .dest ).upper ())
547+
548+ @staticmethod
549+ def _print_message (msg : str ) -> None :
550+ """Print a message instead of tab completions and redraw the prompt and input line"""
551+ print (msg )
552+ rl_force_redisplay ()
553+
554+ def _print_arg_hint (self , arg_action : argparse .Action ) -> None :
555+ """
556+ Print argument hint to the terminal when tab completion results in no results
557+ :param arg_action: action being tab completed
558+ """
559+ # Check if hinting is disabled
560+ suppress_hint = getattr (arg_action , ATTR_SUPPRESS_TAB_HINT , False )
561+ if suppress_hint or arg_action .help == argparse .SUPPRESS or arg_action .dest == argparse .SUPPRESS :
562+ return
540563
564+ prefix = self ._format_message_prefix (arg_action )
541565 prefix = ' {0: <{width}} ' .format (prefix , width = 20 )
542566 pref_len = len (prefix )
543567
544568 help_text = '' if arg_action .help is None else arg_action .help
545569 help_lines = help_text .splitlines ()
546570
547571 if len (help_lines ) == 1 :
548- print ('\n Hint:\n {}{}\n ' .format (prefix , help_lines [0 ]))
572+ self . _print_message ('\n Hint:\n {}{}\n ' .format (prefix , help_lines [0 ]))
549573 else :
550574 out_str = '\n {}' .format (prefix )
551575 out_str += '\n {0: <{width}}' .format ('' , width = pref_len ).join (help_lines )
552- print ('\n Hint:' + out_str + '\n ' )
576+ self . _print_message ('\n Hint:' + out_str + '\n ' )
553577
554- # Redraw prompt and input line
555- rl_force_redisplay ()
556-
557- @staticmethod
558- def _print_unfinished_flag_error (flag_arg_state : _ArgumentState ) -> None :
559- """Print an error during tab completion when the user has not finished the current flag"""
560- flags = ', ' .join (flag_arg_state .action .option_strings )
561- param = ' ' + str (flag_arg_state .action .dest ).upper ()
562- prefix = '{}{}' .format (flags , param )
578+ def _print_unfinished_flag_error (self , flag_arg_state : _ArgumentState ) -> None :
579+ """
580+ Print an error during tab completion when the user has not finished the current flag
581+ :param flag_arg_state: information about the unfinished flag action
582+ """
583+ prefix = self ._format_message_prefix (flag_arg_state .action )
563584
564585 out_str = "\n Error:\n "
565586 out_str += ' {0: <{width}} ' .format (prefix , width = 20 )
566587 out_str += generate_range_error (flag_arg_state .min , flag_arg_state .max )
567588
568589 out_str += ' ({} entered)' .format (flag_arg_state .count )
569- print (style_error ('{}\n ' .format (out_str )))
590+ self . _print_message (style_error ('{}\n ' .format (out_str )))
570591
571- # Redraw prompt and input line
572- rl_force_redisplay ()
592+ def _print_completion_error (self , arg_action : argparse .Action , completion_error : CompletionError ) -> None :
593+ """
594+ Print a CompletionError to the user
595+ :param arg_action: action being tab completed
596+ :param completion_error: error that occurred
597+ """
598+ prefix = self ._format_message_prefix (arg_action )
599+
600+ out_str = "\n Error:\n "
601+ out_str += ' {0: <{width}} ' .format (prefix , width = 20 )
602+ out_str += str (completion_error )
603+
604+ self ._print_message (style_error ('{}\n ' .format (out_str )))
0 commit comments