@@ -576,7 +576,6 @@ class Cmd(cmd.Cmd):
576576 Line-oriented command interpreters are often useful for test harnesses, internal tools, and rapid prototypes.
577577 """
578578 # Attributes which are NOT dynamically settable at runtime
579-
580579 allow_cli_args = True # Should arguments passed on the command-line be processed as commands?
581580 allow_redirection = True # Should output redirection and pipes be allowed
582581 blankLinesAllowed = False
@@ -588,6 +587,7 @@ class Cmd(cmd.Cmd):
588587 default_to_shell = False # Attempt to run unrecognized commands as shell commands
589588 defaultExtension = 'txt' # For ``save``, ``load``, etc.
590589 excludeFromHistory = '''run r list l history hi ed edit li eof''' .split ()
590+ exclude_from_help = ['do_eof' ] # Commands to exclude from the help menu
591591
592592 # make sure your terminators are not in legalChars!
593593 legalChars = u'!#$%.:?@_-' + pyparsing .alphanums + pyparsing .alphas8bit
@@ -666,11 +666,13 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, use_ipython=False
666666 # noinspection PyUnresolvedReferences
667667 self .keywords = self .reserved_words + [fname [3 :] for fname in dir (self )
668668 if fname .startswith ('do_' )]
669- self .parser_manager = ParserManager (redirector = self .redirector , terminators = self .terminators , multilineCommands = self .multilineCommands ,
670- legalChars = self .legalChars , commentGrammars = self .commentGrammars ,
671- commentInProgress = self .commentInProgress , case_insensitive = self .case_insensitive ,
672- blankLinesAllowed = self .blankLinesAllowed , prefixParser = self .prefixParser ,
673- preparse = self .preparse , postparse = self .postparse , shortcuts = self .shortcuts )
669+ self .parser_manager = ParserManager (redirector = self .redirector , terminators = self .terminators ,
670+ multilineCommands = self .multilineCommands ,
671+ legalChars = self .legalChars , commentGrammars = self .commentGrammars ,
672+ commentInProgress = self .commentInProgress ,
673+ case_insensitive = self .case_insensitive ,
674+ blankLinesAllowed = self .blankLinesAllowed , prefixParser = self .prefixParser ,
675+ preparse = self .preparse , postparse = self .postparse , shortcuts = self .shortcuts )
674676 self ._transcript_files = transcript_files
675677
676678 # Used to enable the ability for a Python script to quit the application
@@ -1126,19 +1128,60 @@ def do_cmdenvironment(self, args):
11261128 def do_help (self , arg ):
11271129 """List available commands with "help" or detailed help with "help cmd"."""
11281130 if arg :
1131+ # Getting help for a specific command
11291132 funcname = self ._func_named (arg )
11301133 if funcname :
11311134 fn = getattr (self , funcname )
11321135 try :
1136+ # Use Optparse help for @options commands
11331137 fn .optionParser .print_help (file = self .stdout )
11341138 except AttributeError :
1139+ # No special behavior needed, delegate to cmd base class do_help()
11351140 cmd .Cmd .do_help (self , funcname [3 :])
11361141 else :
1137- cmd .Cmd .do_help (self , arg )
1142+ # Show a menu of what commands help can be gotten for
1143+ self ._help_menu ()
1144+
1145+ def _help_menu (self ):
1146+ """Show a list of commands which help can be displayed for.
1147+ """
1148+ # Get a list of all method names
1149+ names = self .get_names ()
1150+
1151+ # Remove any command names which are explicitly excluded from the help menu
1152+ for name in self .exclude_from_help :
1153+ names .remove (name )
1154+
1155+ cmds_doc = []
1156+ cmds_undoc = []
1157+ help_dict = {}
1158+ for name in names :
1159+ if name [:5 ] == 'help_' :
1160+ help_dict [name [5 :]] = 1
1161+ names .sort ()
1162+ # There can be duplicates if routines overridden
1163+ prevname = ''
1164+ for name in names :
1165+ if name [:3 ] == 'do_' :
1166+ if name == prevname :
1167+ continue
1168+ prevname = name
1169+ command = name [3 :]
1170+ if command in help_dict :
1171+ cmds_doc .append (command )
1172+ del help_dict [command ]
1173+ elif getattr (self , name ).__doc__ :
1174+ cmds_doc .append (command )
1175+ else :
1176+ cmds_undoc .append (command )
1177+ self .stdout .write ("%s\n " % str (self .doc_leader ))
1178+ self .print_topics (self .doc_header , cmds_doc , 15 , 80 )
1179+ self .print_topics (self .misc_header , list (help_dict .keys ()), 15 , 80 )
1180+ self .print_topics (self .undoc_header , cmds_undoc , 15 , 80 )
11381181
11391182 # noinspection PyUnusedLocal
11401183 def do_shortcuts (self , args ):
1141- """Lists single-key shortcuts available."""
1184+ """Lists shortcuts (aliases) available."""
11421185 result = "\n " .join ('%s: %s' % (sc [0 ], sc [1 ]) for sc in sorted (self .shortcuts ))
11431186 self .stdout .write ("Single-key shortcuts for other commands:\n {}\n " .format (result ))
11441187
@@ -1466,7 +1509,7 @@ def do_py(self, arg):
14661509 py: Enters interactive Python mode.
14671510 End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``.
14681511 Non-python commands can be issued with ``cmd("your command")``.
1469- Run python code from external files with ``run("filename.py")``
1512+ Run python code from external script files with ``run("filename.py")``
14701513 """
14711514 if self ._in_py :
14721515 self .perror ("Recursively entering interactive Python consoles is not allowed." , traceback_war = False )
@@ -1759,7 +1802,7 @@ def _read_file_or_url(self, fname):
17591802 def do__relative_load (self , arg = None ):
17601803 """Runs commands in script at file or URL.
17611804
1762- Usage: load [file_path]
1805+ Usage: _relative_load [file_path]
17631806
17641807 optional argument:
17651808 file_path a file path or URL pointing to a script
@@ -1769,6 +1812,8 @@ def do__relative_load(self, arg=None):
17691812
17701813If this is called from within an already-running script, the filename will be interpreted
17711814relative to the already-running script's directory.
1815+
1816+ NOTE: This command is intended to only be used within text file scripts.
17721817 """
17731818 if arg :
17741819 arg = arg .split (None , 1 )
@@ -1922,28 +1967,31 @@ def cmdloop(self, intro=None):
19221967 self .postloop ()
19231968
19241969
1970+ # noinspection PyPep8Naming
19251971class ParserManager :
1926-
1927- def __init__ (self , redirector , terminators , multilineCommands , legalChars , commentGrammars ,
1928- commentInProgress , case_insensitive , blankLinesAllowed , prefixParser ,
1929- preparse , postparse , shortcuts ):
1930- "Creates and uses parsers for user input according to app's paramters."
1972+ """
1973+ Class which encapsulates all of the pyparsing parser functionality for cmd2 in a single location.
1974+ """
1975+ def __init__ (self , redirector , terminators , multilineCommands , legalChars , commentGrammars , commentInProgress ,
1976+ case_insensitive , blankLinesAllowed , prefixParser , preparse , postparse , shortcuts ):
1977+ """Creates and uses parsers for user input according to app's paramters."""
19311978
19321979 self .commentGrammars = commentGrammars
19331980 self .preparse = preparse
19341981 self .postparse = postparse
19351982 self .shortcuts = shortcuts
19361983
1937- self .main_parser = self ._build_main_parser (
1938- redirector = redirector , terminators = terminators , multilineCommands = multilineCommands ,
1939- legalChars = legalChars ,
1940- commentInProgress = commentInProgress , case_insensitive = case_insensitive ,
1941- blankLinesAllowed = blankLinesAllowed , prefixParser = prefixParser )
1942- self .input_source_parser = self ._build_input_source_parser (legalChars = legalChars , commentInProgress = commentInProgress )
1984+ self .main_parser = self ._build_main_parser (redirector = redirector , terminators = terminators ,
1985+ multilineCommands = multilineCommands , legalChars = legalChars ,
1986+ commentInProgress = commentInProgress ,
1987+ case_insensitive = case_insensitive ,
1988+ blankLinesAllowed = blankLinesAllowed , prefixParser = prefixParser )
1989+ self .input_source_parser = self ._build_input_source_parser (legalChars = legalChars ,
1990+ commentInProgress = commentInProgress )
19431991
19441992 def _build_main_parser (self , redirector , terminators , multilineCommands , legalChars ,
19451993 commentInProgress , case_insensitive , blankLinesAllowed , prefixParser ):
1946- "Builds a PyParsing parser for interpreting user commands."
1994+ """ Builds a PyParsing parser for interpreting user commands."" "
19471995
19481996 # Build several parsing components that are eventually compiled into overall parser
19491997 output_destination_parser = (pyparsing .Literal (redirector * 2 ) |
@@ -1959,7 +2007,8 @@ def _build_main_parser(self, redirector, terminators, multilineCommands, legalCh
19592007 pipe = pyparsing .Keyword ('|' , identChars = '|' )
19602008 do_not_parse = self .commentGrammars | commentInProgress | pyparsing .quotedString
19612009 after_elements = \
1962- pyparsing .Optional (pipe + pyparsing .SkipTo (output_destination_parser ^ string_end , ignore = do_not_parse )('pipeTo' )) + \
2010+ pyparsing .Optional (pipe + pyparsing .SkipTo (output_destination_parser ^ string_end ,
2011+ ignore = do_not_parse )('pipeTo' )) + \
19632012 pyparsing .Optional (output_destination_parser +
19642013 pyparsing .SkipTo (string_end ,
19652014 ignore = do_not_parse ).setParseAction (lambda x : x [0 ].strip ())('outputTo' ))
@@ -1972,24 +2021,23 @@ def _build_main_parser(self, redirector, terminators, multilineCommands, legalCh
19722021 blankLineTerminator = (pyparsing .lineEnd + pyparsing .lineEnd )('terminator' )
19732022 blankLineTerminator .setResultsName ('terminator' )
19742023 blankLineTerminationParser = ((multilineCommand ^ oneline_command ) +
1975- pyparsing .SkipTo (blankLineTerminator ,
1976- ignore = do_not_parse ).setParseAction (
1977- lambda x : x [0 ].strip ())('args' ) +
1978- blankLineTerminator )('statement' )
2024+ pyparsing .SkipTo (blankLineTerminator , ignore = do_not_parse ).setParseAction (
2025+ lambda x : x [0 ].strip ())('args' ) + blankLineTerminator )('statement' )
19792026
19802027 multilineParser = (((multilineCommand ^ oneline_command ) +
1981- pyparsing .SkipTo (terminator_parser ,
1982- ignore = do_not_parse ).setParseAction (
1983- lambda x : x [0 ].strip ())('args' ) + terminator_parser )('statement' ) +
1984- pyparsing .SkipTo (output_destination_parser ^ pipe ^ string_end , ignore = do_not_parse ).setParseAction (
1985- lambda x : x [0 ].strip ())('suffix' ) + after_elements )
2028+ pyparsing .SkipTo (terminator_parser ,
2029+ ignore = do_not_parse ).setParseAction (lambda x : x [0 ].strip ())('args' ) +
2030+ terminator_parser )('statement' ) +
2031+ pyparsing .SkipTo (output_destination_parser ^ pipe ^ string_end ,
2032+ ignore = do_not_parse ).setParseAction (lambda x : x [0 ].strip ())('suffix' ) +
2033+ after_elements )
19862034 multilineParser .ignore (commentInProgress )
19872035
19882036 singleLineParser = ((oneline_command +
1989- pyparsing .SkipTo (terminator_parser ^ string_end ^ pipe ^ output_destination_parser ,
1990- ignore = do_not_parse ).setParseAction (
1991- lambda x : x [0 ].strip ())('args' ))('statement' ) +
1992- pyparsing .Optional (terminator_parser ) + after_elements )
2037+ pyparsing .SkipTo (terminator_parser ^ string_end ^ pipe ^ output_destination_parser ,
2038+ ignore = do_not_parse ).setParseAction (
2039+ lambda x : x [0 ].strip ())('args' ))('statement' ) +
2040+ pyparsing .Optional (terminator_parser ) + after_elements )
19932041
19942042 blankLineTerminationParser = blankLineTerminationParser .setResultsName ('statement' )
19952043
@@ -2003,8 +2051,9 @@ def _build_main_parser(self, redirector, terminators, multilineCommands, legalCh
20032051 parser .ignore (self .commentGrammars )
20042052 return parser
20052053
2006- def _build_input_source_parser (self , legalChars , commentInProgress ):
2007- "Builds a PyParsing parser for alternate user input sources (from file, pipe, etc.)"
2054+ @staticmethod
2055+ def _build_input_source_parser (legalChars , commentInProgress ):
2056+ """Builds a PyParsing parser for alternate user input sources (from file, pipe, etc.)"""
20082057
20092058 input_mark = pyparsing .Literal ('<' )
20102059 input_mark .setParseAction (lambda x : '' )
@@ -2049,8 +2098,6 @@ def parsed(self, raw):
20492098 return p
20502099
20512100
2052-
2053-
20542101class HistoryItem (str ):
20552102 """Class used to represent an item in the History list.
20562103
0 commit comments