diff --git a/src/azure/cli/_help.py b/src/azure/cli/_help.py index 4a01333b918..bf5957bf16d 100644 --- a/src/azure/cli/_help.py +++ b/src/azure/cli/_help.py @@ -13,6 +13,8 @@ __all__ = ['print_detailed_help', 'print_welcome_message', 'GroupHelpFile', 'CommandHelpFile'] +FIRST_LINE_PREFIX = ': ' + def show_help(nouns, parser, is_group): delimiters = ' '.join(nouns) help_file = CommandHelpFile(delimiters, parser) \ @@ -61,7 +63,7 @@ def print_description_list(help_files): for help_file in sorted(help_files, key=lambda h: h.name): _print_indent('{0}{1}{2}'.format(help_file.name, _get_column_indent(help_file.name, max_name_length), - ': ' + help_file.short_summary \ + FIRST_LINE_PREFIX + help_file.short_summary \ if help_file.short_summary \ else ''), indent) @@ -97,13 +99,16 @@ def print_arguments(help_file): print('') print(p.group_name) last_group_name = p.group_name - _print_indent('{0}{1}{2}{3}'.format(p.name, - _get_column_indent(p.name + required_text, - max_name_length), - required_text, - ': ' + short_summary if short_summary else ''), - indent, - max_name_length + indent*4 + 2) + _print_indent( + '{0}{1}{2}{3}'.format( + p.name, + _get_column_indent(p.name + required_text, max_name_length), + required_text, + FIRST_LINE_PREFIX + short_summary if short_summary else '' + ), + indent, + _get_hanging_indent(max_name_length, indent) + ) indent = 2 if p.long_summary: @@ -123,7 +128,7 @@ def _print_header(help_file): indent += 1 _print_indent('{0}{1}'.format('az ' + help_file.command, - ': ' + help_file.short_summary + FIRST_LINE_PREFIX + help_file.short_summary if help_file.short_summary else ''), indent) @@ -137,11 +142,12 @@ def _print_groups(help_file): def _print_items(items): for c in sorted(items, key=lambda h: h.name): - _print_indent('{0}{1}{2}'.format(c.name, - _get_column_indent(c.name, max_name_length), - ': ' + c.short_summary if c.short_summary else ''), - indent) - + column_indent = _get_column_indent(c.name, max_name_length) + summary = FIRST_LINE_PREFIX + c.short_summary if c.short_summary else '' + summary = summary.replace('\n', ' ') + hanging_indent = max_name_length + indent*4 + 2 + _print_indent( + '{0}{1}{2}'.format(c.name, column_indent, summary), indent, hanging_indent) _print_indent('') indent = 1 @@ -160,7 +166,7 @@ def _print_items(items): _print_items(subcommands) def _get_choices_defaults_str(p): - choice_str = ' Allowed values: {0}.'.format(', '.join([str(x) for x in p.choices])) \ + choice_str = ' Allowed values: {0}.'.format(', '.join(sorted([str(x) for x in p.choices]))) \ if p.choices else '' default_str = ' Default: {0}.'.format(p.default) \ if p.default and p.default != argparse.SUPPRESS else '' @@ -212,7 +218,13 @@ def __init__(self, delimiters): self.examples = '' def load(self, options): - self.short_summary = getattr(options, 'description', None) + description = getattr(options, 'description', None) + try: + self.short_summary = description[:description.index('.')] + self.long_summary = description[description.index('.') + 1:].lstrip() + except (ValueError, AttributeError): + self.short_summary = description + file_data = (_load_help_file_from_string(options.help_file) if hasattr(options, '_defaults') else None) @@ -339,7 +351,6 @@ def __init__(self, _data): self.name = _data['name'] self.text = _data['text'] - def _print_indent(s, indent=0, subsequent_spaces=-1): tw = textwrap.TextWrapper(initial_indent=' '*indent, subsequent_indent=(' '*indent @@ -354,6 +365,9 @@ def _print_indent(s, indent=0, subsequent_spaces=-1): def _get_column_indent(text, max_name_length): return ' '*(max_name_length - len(text)) +def _get_hanging_indent(max_length, indent): + return max_length + (indent * 4) + len(FIRST_LINE_PREFIX) + def _normalize_text(s): if not s or len(s) < 2: return s or '' diff --git a/src/azure/cli/commands/__init__.py b/src/azure/cli/commands/__init__.py index 4047ee780b3..e8e03b95a7f 100644 --- a/src/azure/cli/commands/__init__.py +++ b/src/azure/cli/commands/__init__.py @@ -17,7 +17,7 @@ from azure.cli._util import CLIError import azure.cli._logging as _logging -from ._introspection import extract_args_from_signature +from ._introspection import extract_args_from_signature, extract_full_summary_from_signature logger = _logging.get_az_logger(__name__) @@ -233,6 +233,7 @@ def _execute_command(kwargs): name = ' '.join(name.split()) cmd = CliCommand(name, _execute_command, simple_output_query=simple_output_query) + cmd.description = extract_full_summary_from_signature(operation) cmd.arguments.update(extract_args_from_signature(operation)) return cmd diff --git a/src/azure/cli/commands/_introspection.py b/src/azure/cli/commands/_introspection.py index 87755854237..c51a9109f28 100644 --- a/src/azure/cli/commands/_introspection.py +++ b/src/azure/cli/commands/_introspection.py @@ -6,11 +6,24 @@ import inspect import re +def extract_full_summary_from_signature(operation): + """ Extract the summary from the doccomments of the command. """ + lines = inspect.getdoc(operation) + regex = r'\s*(:param)\s+(.+)\s*:(.*)' + summary = '' + if lines: + match = re.search(regex, lines) + if match: + summary = lines[:match.regs[0][0]] + else: + summary = lines + return summary + def _option_descriptions(operation): - """Pull out parameter help from doccomments of the command - """ + """ Extract parameter help from doccomments of the command. """ option_descs = {} lines = inspect.getdoc(operation) + param_breaks = ["'''", '"""', ':param', ':type', ':return', ':rtype'] if lines: lines = lines.splitlines() index = 0 @@ -26,7 +39,7 @@ def _option_descriptions(operation): index += 1 while index < len(lines): temp = lines[index].strip() - if temp.startswith(':'): + if any(temp.startswith(x) for x in param_breaks): break else: if temp: