Exemple #1
0
    def Generate(self):
        """Generates markdown for the command, group or topic, into a string."""
        self._out('= {0}(1) =\n'.format(self._file_name.upper()))
        self._Section('NAME')
        self._out(
            '{{command}} - {index}\n'.format(index=self._command.index_help))
        if not self._is_topic:
            self._PrintSynopsisSection()
        self._PrintSectionIfExists('DESCRIPTION',
                                   default=usage_text.ExpandHelpText(
                                       self._command, self._command.long_help))
        if not self._is_topic:
            self._PrintPositionalsAndFlagsSections()
        if self._subgroups:
            self._PrintCommandSection('GROUP', self._subgroups)
        if self._subcommands:
            if self._is_topic:
                self._PrintCommandSection('TOPIC',
                                          self._subcommands,
                                          is_topic=True)
            else:
                self._PrintCommandSection('COMMAND', self._subcommands)
        self._PrintSectionIfExists('EXAMPLES')
        self._PrintSectionIfExists('SEE ALSO')
        self._PrintNotesSection()
        self._doc = self._buf.getvalue()

        # Apply edits to the generated markdown.
        self._ExpandFormatReferences()
        self._AddCommandLineLinkMarkdown()
        self._AddManPageLinkMarkdown()
        self._FixAirQuotesMarkdown()
        return self._doc
Exemple #2
0
 def Generate(self):
     """Generates markdown for the command, group or topic, into a string."""
     self._out('# {0}(1)\n'.format(self._file_name.upper()))
     self._Section('NAME')
     self._out(
         '{{command}} - {index}\n'.format(index=self._command.index_help))
     if not self._is_topic:
         self._PrintSynopsisSection()
     self._ExtractDetailedHelp()
     self._PrintSectionIfExists('DESCRIPTION',
                                default=usage_text.ExpandHelpText(
                                    self._command, self._description))
     if not self._is_topic:
         self._PrintPositionalsAndFlagsSections()
     if self._subgroups:
         self._PrintCommandSection('GROUP', self._subgroups)
     if self._subcommands:
         if self._is_topic:
             self._PrintCommandSection('TOPIC',
                                       self._subcommands,
                                       is_topic=True)
         else:
             self._PrintCommandSection('COMMAND', self._subcommands)
     final_sections = ['EXAMPLES', 'SEE ALSO']
     self._PrintAllExtraSections(excluded_sections=final_sections +
                                 ['NOTES'])
     for section in final_sections:
         self._PrintSectionIfExists(section)
     self._PrintNotesSection()
     return self._Edit(self._buf.getvalue())
Exemple #3
0
    def _ExpandFormatReferences(self):
        """Expand {...} references."""
        self._doc = usage_text.ExpandHelpText(self._command,
                                              self._buf.getvalue())

        # Split long $ ... example lines.
        pat = re.compile(
            r'(\$ .{%d,})$' %
            (self.SPLIT - self.FIRST_INDENT - self.SECTION_INDENT), re.M)
        pos = 0
        rep = ''
        while True:
            match = pat.search(self._doc, pos)
            if not match:
                break
            rep += (self._doc[pos:match.start(1)] +
                    self._Split(self._doc[match.start(1):match.end(1)]))
            pos = match.end(1)
        if rep:
            self._doc = rep + self._doc[pos:]
Exemple #4
0
    def _ExpandFormatReferences(self, doc):
        """Expand {...} references in doc."""
        doc = usage_text.ExpandHelpText(self._command, doc)

        # Split long $ ... example lines.
        pat = re.compile(
            r'^ *(\$ .{%d,})$' % (_SPLIT - _FIRST_INDENT - _SECTION_INDENT),
            re.M)
        pos = 0
        rep = ''
        while True:
            match = pat.search(doc, pos)
            if not match:
                break
            rep += (doc[pos:match.start(1)] +
                    ExampleCommandLineSplitter().Split(
                        doc[match.start(1):match.end(1)]))
            pos = match.end(1)
        if rep:
            doc = rep + doc[pos:]
        return doc
Exemple #5
0
def Markdown(command):
    """Generates a markdown help document for command.

  Args:
    command: calliope._CommandCommon, Help extracted from this calliope command
        or group.

  Returns:
    The generated markdown string.
  """
    command.LoadAllSubElements()

    buf = StringIO.StringIO()
    out = buf.write
    detailed_help = getattr(command, 'detailed_help', {})
    command_name = ' '.join(command.GetPath())
    file_name = '_'.join(command.GetPath())

    def UserInput(msg):
        """Returns msg with user input markdown.

    Args:
      msg: str, The user input string.

    Returns:
      The msg string with embedded user input markdown.
    """
        return (usage_text.MARKDOWN_CODE + usage_text.MARKDOWN_ITALIC + msg +
                usage_text.MARKDOWN_ITALIC + usage_text.MARKDOWN_CODE)

    def Section(name, sep=True):
        """Prints the section header markdown for name.

    Args:
      name: str, The manpage section name.
      sep: boolean, Add trailing newline.
    """
        out('\n\n== {name} ==\n'.format(name=name))
        if sep:
            out('\n')

    def PrintSectionIfExists(name, default=None):
        """Print a section of the .help file, from a part of the detailed_help.

    Args:
      name: str, The manpage section name.
      default: str, Default help_stuff if section name is not defined.
    """
        help_stuff = detailed_help.get(name, default)
        if not help_stuff:
            return
        if callable(help_stuff):
            help_message = help_stuff()
        else:
            help_message = help_stuff
        Section(name)
        out('{message}\n'.format(
            message=textwrap.dedent(help_message).strip()))

    def PrintCommandSection(name, subcommands):
        """Prints a group or command section.

    Args:
      name: str, The section name singular form.
      subcommands: dict, The subcommand dict.
    """
        # Determine if the section has any content.
        content = ''
        for subcommand, help_info in sorted(subcommands.iteritems()):
            if command.IsHidden() or not help_info.is_hidden:
                # If this group is already hidden, we can safely include hidden
                # sub-items.  Else, only include them if they are not hidden.
                content += '\n*link:{cmd}[{cmd}]*::\n\n{txt}\n'.format(
                    cmd=subcommand, txt=help_info.help_text)
        if content:
            Section(name + 'S')
            out('{cmd} is one of the following:\n'.format(cmd=UserInput(name)))
            out(content)

    def Details(arg):
        """Returns the detailed help message for the given arg."""
        help_stuff = getattr(arg, 'detailed_help', (arg.help or '') + '\n')
        if callable(help_stuff):
            help_message = help_stuff()
        else:
            help_message = help_stuff
        return textwrap.dedent(help_message).replace('\n\n', '\n+\n').strip()

    def Split(line):
        """Splits long example command lines.

    Args:
      line: str, The line to split.

    Returns:
      str, The split line.
    """
        ret = ''
        m = SPLIT - FIRST_INDENT - SECTION_INDENT
        n = len(line)
        while n > m:
            indent = SUBSEQUENT_INDENT
            j = m
            noflag = 0
            while True:
                if line[j] == ' ':
                    # Break at a flag if possible.
                    j += 1
                    if line[j] == '-':
                        break
                    # Look back one more operand to see if it's a flag.
                    if noflag:
                        j = noflag
                        break
                    noflag = j
                    j -= 2
                else:
                    # Line is too long -- force an operand split with no indentation.
                    j -= 1
                    if not j:
                        j = m
                        indent = 0
                        break
            ret += line[:j] + '\\\n' + ' ' * indent
            line = line[j:]
            n = len(line)
            m = SPLIT - SUBSEQUENT_INDENT - SECTION_INDENT
        return ret + line

    subcommands = command.GetSubCommandHelps()
    subgroups = command.GetSubGroupHelps()

    out('= {0}(1) =\n'.format(file_name.upper()))

    helptext = detailed_help.get('brief', command.short_help)
    if not helptext:
        helptext = ''
    elif len(helptext) > 1:
        if helptext[0].isupper() and not helptext[1].isupper():
            helptext = helptext[0].lower() + helptext[1:]
        if helptext[-1] == '.':
            helptext = helptext[:-1]
    Section('NAME')
    out('{{command}} - {helptext}\n'.format(helptext=helptext))

    # Post-processing will make the synopsis a hanging indent.
    # MARKDOWN_CODE is the default SYNOPSIS font style.
    code = usage_text.MARKDOWN_CODE
    em = usage_text.MARKDOWN_ITALIC
    Section('SYNOPSIS')
    out('{code}{command}{code}'.format(code=code, command=command_name))

    # Output the positional args up to the first REMAINDER or '-- *' args. The
    # rest will be picked up after the flag args are output. argparse does not
    # have an explicit '--' arg intercept, so we use the metavar value as a '--'
    # sentinel.
    positional_args = command.ai.positional_args[:]
    while positional_args:
        arg = positional_args[0]
        if arg.nargs == argparse.REMAINDER or arg.metavar.startswith('-- '):
            break
        positional_args.pop(0)
        out(usage_text.PositionalDisplayString(arg, markdown=True))

    # rel is the relative path offset used to generate ../* to the reference root.
    rel = 1
    if subcommands and subgroups:
        out(' ' + em + 'GROUP' + em + ' | ' + em + 'COMMAND' + em)
    elif subcommands:
        out(' ' + em + 'COMMAND' + em)
    elif subgroups:
        out(' ' + em + 'GROUP' + em)
    else:
        rel = 2

    # Places all flags into a dict. Flags that are in a mutually
    # exlusive group are mapped group_id -> [flags]. All other flags
    # are mapped dest -> [flag].
    groups = collections.defaultdict(list)
    for flag in (command.ai.flag_args + [
            arg for arg in command.ai.ancestor_flag_args
            if usage_text.ShouldPrintAncestorFlag(arg)
    ]):
        group_id = command.ai.mutex_groups.get(flag.dest, flag.dest)
        groups[group_id].append(flag)

    for group in sorted(groups.values(), key=lambda g: g[0].option_strings):
        if len(group) == 1:
            arg = group[0]
            if arg.help == argparse.SUPPRESS:
                continue
            msg = usage_text.FlagDisplayString(arg, markdown=True)
            if arg.required:
                out(' {msg}'.format(msg=msg))
            else:
                out(' [{msg}]'.format(msg=msg))
        else:
            group.sort(key=lambda f: f.option_strings)
            group = [flag for flag in group if flag.help != argparse.SUPPRESS]
            msg = ' | '.join(
                usage_text.FlagDisplayString(arg, markdown=True)
                for arg in group)
            # TODO(user): Figure out how to plumb through the required
            # attribute of a required flag.
            out(' [{msg}]'.format(msg=msg))

    # positional_args will only be non-empty if we had -- ... or REMAINDER left.
    for arg in positional_args:
        out(usage_text.PositionalDisplayString(arg, markdown=True))

    PrintSectionIfExists('DESCRIPTION',
                         default=usage_text.ExpandHelpText(
                             command, command.long_help))
    PrintSectionIfExists('SEE ALSO')

    if command.ai.positional_args:
        Section('POSITIONAL ARGUMENTS', sep=False)
        for arg in command.ai.positional_args:
            out('\n{0}::\n'.format(
                usage_text.PositionalDisplayString(arg,
                                                   markdown=True).lstrip()))
            out('\n{arghelp}\n'.format(arghelp=Details(arg)))

    Section('FLAGS', sep=False)
    root = ' ' not in command_name
    local_args = []
    global_args = []
    for arg in command.ai.flag_args:
        if arg.help != argparse.SUPPRESS:
            if not root and arg.option_strings[0] in ['--help', '-h']:
                global_args.append(arg)
            else:
                local_args.append(arg)
    for arg in command.ai.ancestor_flag_args:
        if arg.help != argparse.SUPPRESS:
            if usage_text.ShouldPrintAncestorFlag(arg):
                global_args.append(arg)

    local_args = sorted(local_args, key=lambda f: f.option_strings)
    global_args = sorted(global_args, key=lambda f: f.option_strings)
    if local_args and global_args:
        local_args.append([])
    for arg in local_args + global_args:
        if not arg:
            out('\n=== GLOBAL FLAGS ===\n')
            continue
        out('\n{0}::\n'.format(usage_text.FlagDisplayString(arg,
                                                            markdown=True)))
        out('\n{arghelp}\n'.format(arghelp=Details(arg)))

    if subgroups:
        PrintCommandSection('GROUP', subgroups)
    if subcommands:
        PrintCommandSection('COMMAND', subcommands)

    PrintSectionIfExists('EXAMPLES')

    if command.IsHidden() or command.ReleaseTrack(for_help=True).help_note:
        Section('NOTES')
        if command.IsHidden():
            # This string must match gen-help-docs.sh to prevent the generated html
            # from being bundled.
            out('This command is an internal implementation detail and may change or '
                'disappear without notice.\n\n')
        if command.ReleaseTrack(for_help=True).help_note:
            out(command.ReleaseTrack(for_help=True).help_note + '\n\n')

    # This allows formatting to succeed if the help has any {somekey} in the text.
    doc = usage_text.ExpandHelpText(command, buf.getvalue())

    # Split long $ ... example lines.
    pat = re.compile(r'(\$ .{%d,})$' % (SPLIT - FIRST_INDENT - SECTION_INDENT),
                     re.M)
    pos = 0
    rep = ''
    while True:
        match = pat.search(doc, pos)
        if not match:
            break
        rep += doc[pos:match.start(1)] + Split(
            doc[match.start(1):match.end(1)])
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # $ command ... example refs.
    top = command.GetPath()[0]
    # This pattern matches "$ {top} {arg}*" where each arg is lower case and does
    # not start with example-, my-, or sample-. This follows the style guide rule
    # that user-supplied args to example commands contain upper case chars or
    # start with example-, my-, or sample-.
    pat = re.compile(r'\$ (' + top +
                     '((?: (?!(example|my|sample)-)[a-z][-a-z]*)*))[ `\n]')
    pos = 0
    rep = ''
    while True:
        match = pat.search(doc, pos)
        if not match:
            break
        cmd = match.group(1)
        i = cmd.find('set ')
        if i >= 0:
            # This terminates the command at the first positional ending with set.
            # This handles gcloud set and unset subcommands where 'set' and 'unset'
            # are the last command args, the remainder user-specified.
            i += 3
            rem = cmd[i:]
            cmd = cmd[0:i]
        else:
            rem = ''
        ref = match.group(2)
        if ref:
            ref = ref[1:]
        ref = '/'.join(['..'] * (len(command.GetPath()) - rel) +
                       ref.split(' '))
        lnk = 'link:' + ref + '[' + cmd + ']' + rem
        rep += doc[pos:match.start(1)] + lnk
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # gcloud ...(1) man page refs.
    pat = re.compile(r'(\*?(' + top + r'((?:[-_ a-z])*))\*?)\(1\)')
    pos = 0
    rep = ''
    while True:
        match = pat.search(doc, pos)
        if not match:
            break
        cmd = match.group(2).replace('_', ' ')
        ref = match.group(3).replace('_', ' ')
        if ref:
            ref = ref[1:]
        ref = '/'.join(['..'] * (len(command.GetPath()) - rel) +
                       ref.split(' '))
        lnk = '*link:' + ref + '[' + cmd + ']*'
        rep += doc[pos:match.start(2)] + lnk
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # ``*'' emphasis quotes => UserInput(*)
    pat = re.compile(r'(``([^`]*)\'\')')
    pos = 0
    rep = ''
    while True:
        match = pat.search(doc, pos)
        if not match:
            break
        rep += doc[pos:match.start(1)] + UserInput(match.group(2))
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    return doc
Exemple #6
0
def Markdown(command, post):
    """Generates a markdown help document for command.

  Args:
    command: calliope._CommandCommon, Help extracted from this calliope command
        or group.
    post: func(str), Markdown post-processor.
  """

    buf = StringIO.StringIO()
    out = buf.write
    detailed_help = getattr(command, 'detailed_help', {})
    command_name = ' '.join(command.GetPath())
    file_name = '_'.join(command.GetPath())

    def UserInput(msg):
        """Returns msg with user input markdown.

    Args:
      msg: str, The user input string.

    Returns:
      The msg string with embedded user input markdown.
    """
        return (usage_text.MARKDOWN_CODE + usage_text.MARKDOWN_ITALIC + msg +
                usage_text.MARKDOWN_ITALIC + usage_text.MARKDOWN_CODE)

    def Section(name, sep=True):
        """Prints the section header markdown for name.

    Args:
      name: str, The manpage section name.
      sep: boolean, Add trailing newline.
    """
        out('\n\n== {name} ==\n'.format(name=name))
        if sep:
            out('\n')

    def PrintSectionIfExists(name, default=None):
        """Print a section of the .help file, from a part of the detailed_help.

    Args:
      name: str, The manpage section name.
      default: str, Default help_stuff if section name is not defined.
    """
        help_stuff = detailed_help.get(name, default)
        if not help_stuff:
            return
        if callable(help_stuff):
            help_message = help_stuff()
        else:
            help_message = help_stuff
        Section(name)
        out('{message}\n'.format(
            message=textwrap.dedent(help_message).strip()))

    def PrintCommandSection(name, subcommands):
        """Prints a group or command section.

    Args:
      name: str, The section name singular form.
      subcommands: dict, The subcommand dict.
    """
        # Determine if the section has any content.
        content = ''
        for subcommand, help_info in sorted(subcommands.iteritems()):
            if command.is_hidden or not help_info.is_hidden:
                # If this group is already hidden, we can safely include hidden
                # sub-items.  Else, only include them if they are not hidden.
                content += '\n*link:{cmd}[{cmd}]*::\n\n{txt}\n'.format(
                    cmd=subcommand, txt=help_info.help_text)
        if content:
            Section(name + 'S')
            out('{cmd} is one of the following:\n'.format(cmd=UserInput(name)))
            out(content)

    def Details(arg):
        """Returns the detailed help message for the given arg."""
        help_stuff = getattr(arg, 'detailed_help', arg.help + '\n')
        if callable(help_stuff):
            help_message = help_stuff()
        else:
            help_message = help_stuff
        return textwrap.dedent(help_message).replace('\n\n', '\n+\n').strip()

    def Split(line):
        """Splits long example command lines.

    Args:
      line: str, The line to split.

    Returns:
      str, The split line.
    """
        ret = ''
        m = SPLIT - FIRST_INDENT - SECTION_INDENT
        n = len(line)
        while n > m:
            indent = SUBSEQUENT_INDENT
            j = m
            noflag = 0
            while 1:
                if line[j] == ' ':
                    # Break at a flag if possible.
                    j += 1
                    if line[j] == '-':
                        break
                    # Look back one more operand to see if it's a flag.
                    if noflag:
                        j = noflag
                        break
                    noflag = j
                    j -= 2
                else:
                    # Line is too long -- force an operand split with no indentation.
                    j -= 1
                    if not j:
                        j = m
                        indent = 0
                        break
            ret += line[:j] + '\\\n' + ' ' * indent
            line = line[j:]
            n = len(line)
            m = SPLIT - SUBSEQUENT_INDENT - SECTION_INDENT
        return ret + line

    subcommands = command.GetSubCommandHelps()
    subgroups = command.GetSubGroupHelps()

    out('= {0}(1) =\n'.format(file_name.upper()))

    helptext = detailed_help.get('brief', command.short_help)
    if not helptext:
        helptext = ''
    elif len(helptext) > 1:
        if helptext[0].isupper() and not helptext[1].isupper():
            helptext = helptext[0].lower() + helptext[1:]
        if helptext[-1] == '.':
            helptext = helptext[:-1]
    Section('NAME')
    out('{{command}} - {helptext}\n'.format(helptext=helptext))

    # Post-processing will make the synopsis a hanging indent.
    # MARKDOWN_CODE is the default SYNOPSIS font style.
    code = usage_text.MARKDOWN_CODE
    em = usage_text.MARKDOWN_ITALIC
    Section('SYNOPSIS')
    out('{code}{command}{code}'.format(code=code, command=command_name))

    # pylint:disable=protected-access
    for arg in command._ai.positional_args:
        out(usage_text.PositionalDisplayString(arg, markdown=True))

    # rel is the relative path offset used to generate ../* to the reference root.
    rel = 1
    if subcommands and subgroups:
        out(' ' + em + 'GROUP' + em + ' | ' + em + 'COMMAND' + em)
    elif subcommands:
        out(' ' + em + 'COMMAND' + em)
    elif subgroups:
        out(' ' + em + 'GROUP' + em)
    else:
        rel = 2

    # Places all flags into a dict. Flags that are in a mutually
    # exlusive group are mapped group_id -> [flags]. All other flags
    # are mapped dest -> [flag].
    groups = collections.defaultdict(list)
    for flag in command._ai.flag_args + command._ai.ancestor_flag_args:
        group_id = command._ai.mutex_groups.get(flag.dest, flag.dest)
        groups[group_id].append(flag)

    for group in sorted(groups.values(), key=lambda g: g[0].option_strings):
        if len(group) == 1:
            arg = group[0]
            if arg.help == argparse.SUPPRESS:
                continue
            msg = usage_text.FlagDisplayString(arg, markdown=True)
            if arg.required:
                out(' {msg}'.format(msg=msg))
            else:
                out(' [{msg}]'.format(msg=msg))
        else:
            group.sort(key=lambda f: f.option_strings)
            group = [flag for flag in group if flag.help != argparse.SUPPRESS]
            msg = ' | '.join(
                usage_text.FlagDisplayString(arg, markdown=True)
                for arg in group)
            # TODO(user): Figure out how to plumb through the required
            # attribute of a required flag.
            out(' [{msg}]'.format(msg=msg))

    # This is the end of the synopsis markdown.
    out('::\n--\n--\n')

    PrintSectionIfExists('DESCRIPTION',
                         default=usage_text.ExpandHelpText(
                             command, command.long_help))
    PrintSectionIfExists('SEE ALSO')

    if command._ai.positional_args:
        Section('POSITIONAL ARGUMENTS', sep=False)
        for arg in command._ai.positional_args:
            out('\n{0}::\n'.format(
                usage_text.PositionalDisplayString(arg, markdown=True)))
            out('\n{arghelp}\n'.format(arghelp=Details(arg)))

    Section('FLAGS', sep=False)
    root = ' ' not in command_name
    local_args = []
    global_args = []
    for arg in command._ai.flag_args:
        if arg.help != argparse.SUPPRESS:
            if not root and arg.option_strings[0] in ['--help', '-h']:
                global_args.append(arg)
            else:
                local_args.append(arg)
    for arg in command._ai.ancestor_flag_args:
        if arg.help != argparse.SUPPRESS:
            global_args.append(arg)

    local_args = sorted(local_args, key=lambda f: f.option_strings)
    global_args = sorted(global_args, key=lambda f: f.option_strings)
    if local_args and global_args:
        local_args.append([])
    for arg in local_args + global_args:
        if not arg:
            out('\n=== GLOBAL FLAGS ===\n')
            continue
        out('\n{0}::\n'.format(usage_text.FlagDisplayString(arg,
                                                            markdown=True)))
        out('\n{arghelp}\n'.format(arghelp=Details(arg)))

    if subgroups:
        PrintCommandSection('GROUP', subgroups)
    if subcommands:
        PrintCommandSection('COMMAND', subcommands)

    PrintSectionIfExists('EXAMPLES')

    if command.is_hidden or command.release_stage:
        Section('NOTES')
        if command.is_hidden:
            # This string must match gen-help-docs.sh to prevent the generated html
            # from being bundled.
            out('This command is an internal implementation detail and may change or '
                'disappear without notice.\n\n')
        if command.release_stage:
            out(command.release_stage.note + '\n\n')

    top = command.GetPath()[0]

    # This allows formatting to succeed if the help has any {somekey} in the text.
    doc = usage_text.ExpandHelpText(command, buf.getvalue())

    # Markdown fixups.
    # link:uri[text] not handled by markdown are captured by our doc generator.

    # Split long $ ... example lines.
    pat = re.compile(r'(\$ .{%d,})\n' %
                     (SPLIT - FIRST_INDENT - SECTION_INDENT))
    pos = 0
    rep = ''
    while 1:
        match = pat.search(doc, pos)
        if not match:
            break
        rep += doc[pos:match.start(1)] + Split(
            doc[match.start(1):match.end(1)])
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # [[ => [{empty}[
    # This prevents [[XXX]...] being interpreted as an unrendered XXX attribute.
    pat = re.compile(r'(\[\[)')
    pos = 0
    rep = ''
    while 1:
        match = pat.search(doc, pos)
        if not match:
            break
        rep += doc[pos:match.start(1)] + '[{empty}'
        # NOTE: This is different from the other edits here. We back up over the
        # second [ so that [[[ => [{empty}[{empty}[ etc.
        pos = match.end(1) - 1
    if rep:
        doc = rep + doc[pos:]

    # $ command ... example refs.
    pat = re.compile(r'\$ (' + top + '((?: [a-z][-a-z]*)*))[ `\n]')
    pos = 0
    rep = ''
    while 1:
        match = pat.search(doc, pos)
        if not match:
            break
        cmd = match.group(1)
        ref = match.group(2)
        if ref:
            ref = ref[1:]
        ref = '/'.join(['..'] * (len(command.GetPath()) - rel) +
                       ref.split(' '))
        lnk = 'link:' + ref + '[' + cmd + ']'
        rep += doc[pos:match.start(1)] + lnk
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # gcloud ...(1) man page refs.
    pat = re.compile(r'(\*?(' + top + r'((?:[-_ a-z])*))\*?)\(1\)')
    pos = 0
    rep = ''
    while 1:
        match = pat.search(doc, pos)
        if not match:
            break
        cmd = match.group(2).replace('_', ' ')
        ref = match.group(3).replace('_', ' ')
        if ref:
            ref = ref[1:]
        ref = '/'.join(['..'] * (len(command.GetPath()) - rel) +
                       ref.split(' '))
        lnk = '*link:' + ref + '[' + cmd + ']*'
        rep += doc[pos:match.start(2)] + lnk
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    # ``*'' emphasis quotes => UserInput(*)
    pat = re.compile(r'(``([^`]*)\'\')')
    pos = 0
    rep = ''
    while 1:
        match = pat.search(doc, pos)
        if not match:
            break
        rep += doc[pos:match.start(1)] + UserInput(match.group(2))
        pos = match.end(1)
    if rep:
        doc = rep + doc[pos:]

    post(doc)