4242import time
4343from code import InteractiveConsole
4444from collections import (
45+ defaultdict ,
4546 deque ,
4647 namedtuple ,
4748)
6061 IO ,
6162 TYPE_CHECKING ,
6263 Any ,
64+ ClassVar ,
6365 TextIO ,
6466 TypeVar ,
6567 Union ,
123125 Completions ,
124126)
125127from .constants import (
126- CMDSET_ATTR_DEFAULT_HELP_CATEGORY ,
127128 COMMAND_FUNC_PREFIX ,
128129 COMPLETER_FUNC_PREFIX ,
129130 HELP_FUNC_PREFIX ,
@@ -328,9 +329,22 @@ class Cmd:
328329 Line-oriented command interpreters are often useful for test harnesses, internal tools, and rapid prototypes.
329330 """
330331
331- DEFAULT_COMPLETEKEY = 'tab'
332- DEFAULT_EDITOR = utils .find_editor ()
333- DEFAULT_PROMPT = '(Cmd) '
332+ DEFAULT_COMPLETEKEY : ClassVar [str ] = "tab"
333+ DEFAULT_EDITOR : ClassVar [str | None ] = utils .find_editor ()
334+ DEFAULT_PROMPT : ClassVar [str ] = "(Cmd) "
335+
336+ # Default category used for documented commands (those with a docstring,
337+ # help function, or argparse decorator) defined in this class that have
338+ # not been explicitly categorized with the @with_category decorator.
339+ # This value is inherited by subclasses but they can set their own
340+ # DEFAULT_CATEGORY to place their commands into a custom category.
341+ DEFAULT_CATEGORY : ClassVar [str ] = "Cmd2 Commands"
342+
343+ # Header for table listing help topics not related to a command.
344+ MISC_HEADER : ClassVar [str ] = "Miscellaneous Help Topics"
345+
346+ # Header for table listing commands that have no help info.
347+ UNDOC_HEADER : ClassVar [str ] = "Undocumented Commands"
334348
335349 def __init__ (
336350 self ,
@@ -537,19 +551,6 @@ def __init__(
537551 # Set text which prints right before all of the help tables are listed.
538552 self .doc_leader = ""
539553
540- # Set header for table listing documented commands.
541- self .doc_header = "Documented Commands"
542-
543- # Set header for table listing help topics not related to a command.
544- self .misc_header = "Miscellaneous Help Topics"
545-
546- # Set header for table listing commands that have no help info.
547- self .undoc_header = "Undocumented Commands"
548-
549- # If any command has been categorized, then all other documented commands that
550- # haven't been categorized will display under this section in the help output.
551- self .default_category = "Uncategorized Commands"
552-
553554 # The error that prints when no help information can be found
554555 self .help_error = "No help on {}"
555556
@@ -840,8 +841,6 @@ def register_command_set(self, cmdset: CommandSet) -> None:
840841 ),
841842 )
842843
843- default_category = getattr (cmdset , CMDSET_ATTR_DEFAULT_HELP_CATEGORY , None )
844-
845844 installed_attributes = []
846845 try :
847846 for cmd_func_name , command_method in methods :
@@ -864,9 +863,6 @@ def register_command_set(self, cmdset: CommandSet) -> None:
864863
865864 self ._cmd_to_command_sets [command ] = cmdset
866865
867- if default_category and not hasattr (command_method , constants .CMD_ATTR_HELP_CATEGORY ):
868- utils .categorize (command_method , default_category )
869-
870866 # If this command is in a disabled category, then disable it
871867 command_category = getattr (command_method , constants .CMD_ATTR_HELP_CATEGORY , None )
872868 if command_category in self .disabled_categories :
@@ -4214,12 +4210,11 @@ def complete_help_subcommands(
42144210 completer = argparse_completer .DEFAULT_AP_COMPLETER (argparser , self )
42154211 return completer .complete_subcommand_help (text , line , begidx , endidx , arg_tokens ['subcommands' ])
42164212
4217- def _build_command_info (self ) -> tuple [dict [str , list [str ]], list [str ], list [str ], list [ str ] ]:
4213+ def _build_command_info (self ) -> tuple [dict [str , list [str ]], list [str ], list [str ]]:
42184214 """Categorizes and sorts visible commands and help topics for display.
42194215
42204216 :return: tuple containing:
42214217 - dictionary mapping category names to lists of command names
4222- - list of documented command names
42234218 - list of undocumented command names
42244219 - list of help topic names that are not also commands
42254220 """
@@ -4228,9 +4223,9 @@ def _build_command_info(self) -> tuple[dict[str, list[str]], list[str], list[str
42284223
42294224 # Get a sorted list of visible command names
42304225 visible_commands = sorted (self .get_visible_commands (), key = utils .DEFAULT_STR_SORT_KEY )
4231- cmds_doc : list [str ] = []
4226+ cmds_cats : dict [ str , list [str ]] = defaultdict ( list )
42324227 cmds_undoc : list [str ] = []
4233- cmds_cats : dict [ str , list [ str ]] = {}
4228+
42344229 for command in visible_commands :
42354230 func = cast (CommandFunc , self .cmd_func (command ))
42364231 has_help_func = False
@@ -4245,13 +4240,15 @@ def _build_command_info(self) -> tuple[dict[str, list[str]], list[str], list[str
42454240
42464241 if hasattr (func , constants .CMD_ATTR_HELP_CATEGORY ):
42474242 category : str = getattr (func , constants .CMD_ATTR_HELP_CATEGORY )
4248- cmds_cats .setdefault (category , [])
42494243 cmds_cats [category ].append (command )
42504244 elif func .__doc__ or has_help_func or has_parser :
4251- cmds_doc .append (command )
4245+ # Determine the category based on the defining class
4246+ defining_cls = get_defining_class (func )
4247+ category = getattr (defining_cls , 'DEFAULT_CATEGORY' , self .DEFAULT_CATEGORY )
4248+ cmds_cats [category ].append (command )
42524249 else :
42534250 cmds_undoc .append (command )
4254- return cmds_cats , cmds_doc , cmds_undoc , help_topics
4251+ return cmds_cats , cmds_undoc , help_topics
42554252
42564253 @classmethod
42574254 def _build_help_parser (cls ) -> Cmd2ArgumentParser :
@@ -4284,7 +4281,7 @@ def do_help(self, args: argparse.Namespace) -> None:
42844281 self .last_result = True
42854282
42864283 if not args .command or args .verbose :
4287- cmds_cats , cmds_doc , cmds_undoc , help_topics = self ._build_command_info ()
4284+ cmds_cats , cmds_undoc , help_topics = self ._build_command_info ()
42884285
42894286 if self .doc_leader :
42904287 self .poutput ()
@@ -4294,10 +4291,6 @@ def do_help(self, args: argparse.Namespace) -> None:
42944291 # Print any categories first and then the remaining documented commands.
42954292 sorted_categories = sorted (cmds_cats .keys (), key = utils .DEFAULT_STR_SORT_KEY )
42964293 all_cmds = {category : cmds_cats [category ] for category in sorted_categories }
4297- if all_cmds :
4298- all_cmds [self .default_category ] = cmds_doc
4299- else :
4300- all_cmds [self .doc_header ] = cmds_doc
43014294
43024295 # Used to provide verbose table separation for better readability.
43034296 previous_table_printed = False
@@ -4312,8 +4305,8 @@ def do_help(self, args: argparse.Namespace) -> None:
43124305 if previous_table_printed and (help_topics or cmds_undoc ):
43134306 self .poutput ()
43144307
4315- self .print_topics (self .misc_header , help_topics , 15 , 80 )
4316- self .print_topics (self .undoc_header , cmds_undoc , 15 , 80 )
4308+ self .print_topics (self .MISC_HEADER , help_topics , 15 , 80 )
4309+ self .print_topics (self .UNDOC_HEADER , cmds_undoc , 15 , 80 )
43174310
43184311 else :
43194312 # Getting help for a specific command
0 commit comments