Skip to content

Commit f4f2b9e

Browse files
committed
Added verbose help output with help -v or help --verbose
Reads the __doc__ for a command function and provides the first block of text for each command. Updated help_categories.py to demonstrate a multi-line comment block for a command.
1 parent da28564 commit f4f2b9e

File tree

2 files changed

+67
-13
lines changed

2 files changed

+67
-13
lines changed

cmd2.py

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ class RlType(Enum):
209209
# Used for tab completion and word breaks. Do not change.
210210
QUOTES = ['"', "'"]
211211
REDIRECTION_CHARS = ['|', '<', '>']
212+
213+
# optional attribute, when tagged on a function, allows cmd2 to categorize commands
212214
HELP_CATEGORY = 'help_category'
213215

214216

@@ -2891,7 +2893,10 @@ def complete_unalias(self, text, line, begidx, endidx):
28912893
@with_argument_list
28922894
def do_help(self, arglist):
28932895
"""List available commands with "help" or detailed help with "help cmd"."""
2894-
if arglist:
2896+
if not arglist or (len(arglist) == 1 and arglist[0] in ('--verbose', '-v')):
2897+
verbose = len(arglist) == 1 and arglist[0] in ('--verbose', '-v')
2898+
self._help_menu(verbose)
2899+
else:
28952900
# Getting help for a specific command
28962901
funcname = self._func_named(arglist[0])
28972902
if funcname:
@@ -2912,11 +2917,8 @@ def do_help(self, arglist):
29122917
else:
29132918
# This could be a help topic
29142919
cmd.Cmd.do_help(self, arglist[0])
2915-
else:
2916-
# Show a menu of what commands help can be gotten for
2917-
self._help_menu()
29182920

2919-
def _help_menu(self):
2921+
def _help_menu(self, verbose=False):
29202922
"""Show a list of commands which help can be displayed for.
29212923
"""
29222924
# Get a sorted list of help topics
@@ -2947,19 +2949,62 @@ def _help_menu(self):
29472949

29482950
if len(cmds_cats) == 0:
29492951
# No categories found, fall back to standard behavior
2950-
self.poutput("%s\n" % str(self.doc_leader))
2951-
self.print_topics(self.doc_header, cmds_doc, 15, 80)
2952+
self.poutput("{}\n".format(str(self.doc_leader)))
2953+
self._print_topics(self.doc_header, cmds_doc, verbose)
29522954
else:
29532955
# Categories found, Organize all commands by category
2954-
self.poutput("%s\n" % str(self.doc_leader))
2955-
self.poutput("%s\n\n" % str(self.doc_header))
2956-
for category in cmds_cats:
2957-
self.print_topics(category, cmds_cats[category], 15, 80)
2958-
self.print_topics('Other', cmds_doc, 15, 80)
2956+
self.poutput('{}\n'.format(str(self.doc_leader)))
2957+
self.poutput('{}\n\n'.format(str(self.doc_header)))
2958+
for category in sorted(cmds_cats.keys()):
2959+
self._print_topics(category, cmds_cats[category], verbose)
2960+
self._print_topics('Other', cmds_doc, verbose)
2961+
29592962

29602963
self.print_topics(self.misc_header, help_topics, 15, 80)
29612964
self.print_topics(self.undoc_header, cmds_undoc, 15, 80)
29622965

2966+
def _print_topics(self, header, cmds, verbose):
2967+
"""Customized version of print_topics that can switch between verbose or traditional output"""
2968+
if cmds:
2969+
if not verbose:
2970+
self.print_topics(header, cmds, 15, 80)
2971+
else:
2972+
self.stdout.write('{}\n'.format(str(header)))
2973+
widest = 0
2974+
# measure the commands
2975+
for command in cmds:
2976+
width = wcswidth(command)
2977+
if width > widest:
2978+
widest = width
2979+
# add a 4-space pad
2980+
widest += 4
2981+
if widest < 20:
2982+
widest = 20
2983+
2984+
if self.ruler:
2985+
self.stdout.write('{:{ruler}<{width}}\n'.format('', ruler=self.ruler, width=80))
2986+
2987+
for command in cmds:
2988+
# Attempt to locate the first documentation block
2989+
doc = getattr(self, self._func_named(command)).__doc__
2990+
doc_block = []
2991+
found_first = False
2992+
for doc_line in doc.splitlines():
2993+
str(doc_line).strip()
2994+
if len(doc_line.strip()) > 0:
2995+
doc_block.append(doc_line.strip())
2996+
found_first = True
2997+
else:
2998+
if found_first:
2999+
break
3000+
3001+
for doc_line in doc_block:
3002+
self.stdout.write('{: <{col_width}}{doc}\n'.format(command,
3003+
col_width=widest,
3004+
doc=doc_line))
3005+
command = ''
3006+
self.stdout.write("\n")
3007+
29633008
def do_shortcuts(self, _):
29643009
"""Lists shortcuts (aliases) available."""
29653010
result = "\n".join('%s: %s' % (sc[0], sc[1]) for sc in sorted(self.shortcuts))
@@ -3226,6 +3271,8 @@ def cmd_with_subs_completer(self, text, line, begidx, endidx):
32263271
# noinspection PyBroadException
32273272
def do_py(self, arg):
32283273
"""
3274+
Invoke python command, shell, or script
3275+
32293276
py <command>: Executes a Python command.
32303277
py: Enters interactive Python mode.
32313278
End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``.

examples/help_categories.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,14 @@ def do_thread_dump(self, _):
100100
self.poutput('Thread Dump')
101101

102102
def do_sslconnectorciphers(self, _):
103-
"""SSL Connector Ciphers command"""
103+
"""
104+
SSL Connector Ciphers command is an example of a command that contains
105+
multiple lines of help information for the user. Each line of help in a
106+
contiguous set of lines will be printed and aligned in the verbose output
107+
provided with 'help --verbose'
108+
109+
This is after a blank line and won't de displayed in the verbose help
110+
"""
104111
self.poutput('SSL Connector Ciphers')
105112

106113
def do_vminfo(self, _):

0 commit comments

Comments
 (0)