2222 cast ,
2323)
2424
25- from rich .text import Text
26-
27- from .constants import INFINITY
28- from .rich_utils import Cmd2SimpleTable
29-
30- if TYPE_CHECKING : # pragma: no cover
31- from .cmd2 import Cmd
32-
3325from rich .table import Column
26+ from rich .text import Text
3427
3528from .argparse_custom import (
36- ChoicesCallable ,
29+ Cmd2ArgumentParser ,
3730 generate_range_error ,
3831)
3932from .command_definition import CommandSet
4235 Completions ,
4336 all_display_numeric ,
4437)
38+ from .constants import INFINITY
4539from .exceptions import CompletionError
40+ from .rich_utils import Cmd2SimpleTable
41+ from .types import (
42+ ChoicesProviderUnbound ,
43+ CmdOrSet ,
44+ CompleterUnbound ,
45+ )
46+
47+ if TYPE_CHECKING : # pragma: no cover
48+ from .cmd2 import Cmd
49+
4650
4751# Name of the choice/completer function argument that, if present, will be passed a dictionary of
4852# command line tokens up through the token being completed mapped to their argparse destination name.
4953ARG_TOKENS = 'arg_tokens'
5054
5155
52- def _build_hint (parser : argparse . ArgumentParser , arg_action : argparse .Action ) -> str :
56+ def _build_hint (parser : Cmd2ArgumentParser , arg_action : argparse .Action ) -> str :
5357 """Build completion hint for a given argument."""
5458 # Check if hinting is disabled for this argument
5559 suppress_hint = arg_action .get_suppress_tab_hint () # type: ignore[attr-defined]
@@ -64,12 +68,12 @@ def _build_hint(parser: argparse.ArgumentParser, arg_action: argparse.Action) ->
6468 return formatter .format_help ()
6569
6670
67- def _single_prefix_char (token : str , parser : argparse . ArgumentParser ) -> bool :
71+ def _single_prefix_char (token : str , parser : Cmd2ArgumentParser ) -> bool :
6872 """Is a token just a single flag prefix character."""
6973 return len (token ) == 1 and token [0 ] in parser .prefix_chars
7074
7175
72- def _looks_like_flag (token : str , parser : argparse . ArgumentParser ) -> bool :
76+ def _looks_like_flag (token : str , parser : Cmd2ArgumentParser ) -> bool :
7377 """Determine if a token looks like a flag.
7478
7579 Unless an argument has nargs set to argparse.REMAINDER, then anything that looks like a flag
@@ -140,12 +144,12 @@ def __init__(self, flag_arg_state: _ArgumentState) -> None:
140144
141145
142146class _NoResultsError (CompletionError ):
143- def __init__ (self , parser : argparse . ArgumentParser , arg_action : argparse .Action ) -> None :
147+ def __init__ (self , parser : Cmd2ArgumentParser , arg_action : argparse .Action ) -> None :
144148 """CompletionError which occurs when there are no results.
145149
146150 If hinting is allowed on this argument, then its hint text will display.
147151
148- :param parser: ArgumentParser instance which owns the action being completed
152+ :param parser: Cmd2ArgumentParser instance which owns the action being completed
149153 :param arg_action: action being completed.
150154 """
151155 # Set apply_style to False because we don't want hints to look like errors
@@ -157,14 +161,14 @@ class ArgparseCompleter:
157161
158162 def __init__ (
159163 self ,
160- parser : argparse . ArgumentParser ,
164+ parser : Cmd2ArgumentParser ,
161165 cmd2_app : 'Cmd' ,
162166 * ,
163167 parent_tokens : Mapping [str , MutableSequence [str ]] | None = None ,
164168 ) -> None :
165169 """Create an ArgparseCompleter.
166170
167- :param parser: ArgumentParser instance
171+ :param parser: Cmd2ArgumentParser instance
168172 :param cmd2_app: reference to the Cmd2 application that owns this ArgparseCompleter
169173 :param parent_tokens: optional Mapping of parent parsers' arg names to their tokens
170174 This is only used by ArgparseCompleter when recursing on subcommand parsers
@@ -187,7 +191,7 @@ def __init__(
187191 self ._positional_actions : list [argparse .Action ] = []
188192
189193 # This will be set if self._parser has subcommands
190- self ._subcommand_action : argparse ._SubParsersAction [argparse . ArgumentParser ] | None = None
194+ self ._subcommand_action : argparse ._SubParsersAction [Cmd2ArgumentParser ] | None = None
191195
192196 # Start digging through the argparse structures.
193197 # _actions is the top level container of parameter definitions
@@ -707,33 +711,32 @@ def print_help(self, tokens: Sequence[str], file: IO[str] | None = None) -> None
707711 return
708712 self ._parser .print_help (file = file )
709713
710- def _get_raw_choices (self , arg_state : _ArgumentState ) -> list [CompletionItem ] | ChoicesCallable | None :
711- """Extract choices from action or return the choices_callable."""
712- if arg_state .action .choices is not None :
713- # If choices are subcommands, then get their help text to populate display_meta.
714- if isinstance (arg_state .action , argparse ._SubParsersAction ):
715- parser_help = {}
716- for action in arg_state .action ._choices_actions :
717- if action .dest in arg_state .action .choices :
718- subparser = arg_state .action .choices [action .dest ]
719- parser_help [subparser ] = action .help or ''
720-
721- return [
722- CompletionItem (name , display_meta = parser_help .get (subparser , '' ))
723- for name , subparser in arg_state .action .choices .items ()
724- ]
725-
726- # Standard choices
714+ def _choices_to_items (self , arg_state : _ArgumentState ) -> list [CompletionItem ]:
715+ """Convert choices from action to list of CompletionItems."""
716+ if arg_state .action .choices is None :
717+ return []
718+
719+ # If choices are subcommands, then get their help text to populate display_meta.
720+ if isinstance (arg_state .action , argparse ._SubParsersAction ):
721+ parser_help = {}
722+ for action in arg_state .action ._choices_actions :
723+ if action .dest in arg_state .action .choices :
724+ subparser = arg_state .action .choices [action .dest ]
725+ parser_help [subparser ] = action .help or ''
726+
727727 return [
728- choice if isinstance (choice , CompletionItem ) else CompletionItem (choice ) for choice in arg_state .action .choices
728+ CompletionItem (name , display_meta = parser_help .get (subparser , '' ))
729+ for name , subparser in arg_state .action .choices .items ()
729730 ]
730731
731- choices_callable : ChoicesCallable | None = arg_state .action .get_choices_callable () # type: ignore[attr-defined]
732- return choices_callable
732+ # Standard choices
733+ return [
734+ choice if isinstance (choice , CompletionItem ) else CompletionItem (choice ) for choice in arg_state .action .choices
735+ ]
733736
734737 def _prepare_callable_params (
735738 self ,
736- choices_callable : ChoicesCallable ,
739+ to_call : ChoicesProviderUnbound [ CmdOrSet ] | CompleterUnbound [ CmdOrSet ] ,
737740 arg_state : _ArgumentState ,
738741 text : str ,
739742 consumed_arg_values : dict [str , list [str ]],
@@ -744,14 +747,14 @@ def _prepare_callable_params(
744747 kwargs : dict [str , Any ] = {}
745748
746749 # Resolve the 'self' instance for the method
747- self_arg = self ._cmd2_app ._resolve_func_self (choices_callable . to_call , cmd_set )
750+ self_arg = self ._cmd2_app ._resolve_func_self (to_call , cmd_set )
748751 if self_arg is None :
749- raise CompletionError ("Could not find CommandSet instance matching defining type for completer " )
752+ raise CompletionError ("Could not find CommandSet instance matching defining type" )
750753
751754 args .append (self_arg )
752755
753756 # Check if the function expects 'arg_tokens'
754- to_call_params = inspect .signature (choices_callable . to_call ).parameters
757+ to_call_params = inspect .signature (to_call ).parameters
755758 if ARG_TOKENS in to_call_params :
756759 arg_tokens = {** self ._parent_tokens , ** consumed_arg_values }
757760 arg_tokens .setdefault (arg_state .action .dest , []).append (text )
@@ -775,26 +778,33 @@ def _complete_arg(
775778 :return: a Completions object
776779 :raises CompletionError: if the completer or choices function this calls raises one
777780 """
778- raw_choices = self ._get_raw_choices (arg_state )
779- if not raw_choices :
780- return Completions ()
781-
782- # Check if the argument uses a completer function
783- if isinstance (raw_choices , ChoicesCallable ) and raw_choices .is_completer :
784- args , kwargs = self ._prepare_callable_params (raw_choices , arg_state , text , consumed_arg_values , cmd_set )
781+ # Check if the argument uses a completer
782+ completer = arg_state .action .get_completer () # type: ignore[attr-defined]
783+ if completer is not None :
784+ args , kwargs = self ._prepare_callable_params (
785+ completer ,
786+ arg_state ,
787+ text ,
788+ consumed_arg_values ,
789+ cmd_set ,
790+ )
785791 args .extend ([text , line , begidx , endidx ])
786- completions = raw_choices . completer (* args , ** kwargs )
792+ completions : Completions = completer (* args , ** kwargs )
787793
788- # Otherwise it uses a choices list or choices provider function
794+ # Otherwise it uses a choices provider or choices list
789795 else :
790- all_choices : list [CompletionItem ] = []
791-
792- if isinstance (raw_choices , ChoicesCallable ):
793- args , kwargs = self ._prepare_callable_params (raw_choices , arg_state , text , consumed_arg_values , cmd_set )
794- choices_func = raw_choices .choices_provider
795- all_choices = list (choices_func (* args , ** kwargs ))
796+ choices_provider = arg_state .action .get_choices_provider () # type: ignore[attr-defined]
797+ if choices_provider is not None :
798+ args , kwargs = self ._prepare_callable_params (
799+ choices_provider ,
800+ arg_state ,
801+ text ,
802+ consumed_arg_values ,
803+ cmd_set ,
804+ )
805+ all_choices = list (choices_provider (* args , ** kwargs ))
796806 else :
797- all_choices = raw_choices
807+ all_choices = self . _choices_to_items ( arg_state )
798808
799809 # Filter used values and run basic completion
800810 used_values = consumed_arg_values .get (arg_state .action .dest , [])
0 commit comments