xref: /linux/tools/lib/python/kdoc/enrich_formatter.py (revision 72c395024dac5e215136cbff793455f065603b06)
1cde49466SMauro Carvalho Chehab#!/usr/bin/env python3
2cde49466SMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0
3cde49466SMauro Carvalho Chehab# Copyright (c) 2025 by Mauro Carvalho Chehab <mchehab@kernel.org>.
4cde49466SMauro Carvalho Chehab
5cde49466SMauro Carvalho Chehab"""
6cde49466SMauro Carvalho ChehabAncillary argparse HelpFormatter class that works on a similar way as
7cde49466SMauro Carvalho Chehabargparse.RawDescriptionHelpFormatter, e.g. description maintains line
8cde49466SMauro Carvalho Chehabbreaks, but it also implement transformations to the help text. The
9cde49466SMauro Carvalho Chehabactual transformations ar given by enrich_text(), if the output is tty.
10cde49466SMauro Carvalho Chehab
11cde49466SMauro Carvalho ChehabCurrently, the follow transformations are done:
12cde49466SMauro Carvalho Chehab
13cde49466SMauro Carvalho Chehab    - Positional arguments are shown in upper cases;
14cde49466SMauro Carvalho Chehab    - if output is TTY, ``var`` and positional arguments are shown prepended
15cde49466SMauro Carvalho Chehab      by an ANSI SGR code. This is usually translated to bold. On some
16cde49466SMauro Carvalho Chehab      terminals, like, konsole, this is translated into a colored bold text.
17cde49466SMauro Carvalho Chehab"""
18cde49466SMauro Carvalho Chehab
19cde49466SMauro Carvalho Chehabimport argparse
20cde49466SMauro Carvalho Chehabimport re
21cde49466SMauro Carvalho Chehabimport sys
22cde49466SMauro Carvalho Chehab
23cde49466SMauro Carvalho Chehabclass EnrichFormatter(argparse.HelpFormatter):
24cde49466SMauro Carvalho Chehab    """
25cde49466SMauro Carvalho Chehab    Better format the output, making easier to identify the positional args
26cde49466SMauro Carvalho Chehab    and how they're used at the __doc__ description.
27cde49466SMauro Carvalho Chehab    """
28cde49466SMauro Carvalho Chehab    def __init__(self, *args, **kwargs):
29*7ef684c9SMauro Carvalho Chehab        """
30*7ef684c9SMauro Carvalho Chehab        Initialize class and check if is TTY.
31*7ef684c9SMauro Carvalho Chehab        """
32cde49466SMauro Carvalho Chehab        super().__init__(*args, **kwargs)
33cde49466SMauro Carvalho Chehab        self._tty = sys.stdout.isatty()
34cde49466SMauro Carvalho Chehab
35cde49466SMauro Carvalho Chehab    def enrich_text(self, text):
36*7ef684c9SMauro Carvalho Chehab        r"""
37*7ef684c9SMauro Carvalho Chehab        Handle ReST markups (currently, only \`\`text\`\` markups).
38*7ef684c9SMauro Carvalho Chehab        """
39cde49466SMauro Carvalho Chehab        if self._tty and text:
40cde49466SMauro Carvalho Chehab            # Replace ``text`` with ANSI SGR (bold)
41cde49466SMauro Carvalho Chehab            return re.sub(r'\`\`(.+?)\`\`',
42cde49466SMauro Carvalho Chehab                          lambda m: f'\033[1m{m.group(1)}\033[0m', text)
43cde49466SMauro Carvalho Chehab        return text
44cde49466SMauro Carvalho Chehab
45cde49466SMauro Carvalho Chehab    def _fill_text(self, text, width, indent):
46*7ef684c9SMauro Carvalho Chehab        """
47*7ef684c9SMauro Carvalho Chehab        Enrich descriptions with markups on it.
48*7ef684c9SMauro Carvalho Chehab        """
49cde49466SMauro Carvalho Chehab        enriched = self.enrich_text(text)
50cde49466SMauro Carvalho Chehab        return "\n".join(indent + line for line in enriched.splitlines())
51cde49466SMauro Carvalho Chehab
52cde49466SMauro Carvalho Chehab    def _format_usage(self, usage, actions, groups, prefix):
53*7ef684c9SMauro Carvalho Chehab        """
54*7ef684c9SMauro Carvalho Chehab        Enrich positional arguments at usage: line.
55*7ef684c9SMauro Carvalho Chehab        """
56cde49466SMauro Carvalho Chehab
57cde49466SMauro Carvalho Chehab        prog = self._prog
58cde49466SMauro Carvalho Chehab        parts = []
59cde49466SMauro Carvalho Chehab
60cde49466SMauro Carvalho Chehab        for action in actions:
61cde49466SMauro Carvalho Chehab            if action.option_strings:
62cde49466SMauro Carvalho Chehab                opt = action.option_strings[0]
63cde49466SMauro Carvalho Chehab                if action.nargs != 0:
64cde49466SMauro Carvalho Chehab                    opt += f" {action.dest.upper()}"
65cde49466SMauro Carvalho Chehab                parts.append(f"[{opt}]")
66cde49466SMauro Carvalho Chehab            else:
67cde49466SMauro Carvalho Chehab                # Positional argument
68cde49466SMauro Carvalho Chehab                parts.append(self.enrich_text(f"``{action.dest.upper()}``"))
69cde49466SMauro Carvalho Chehab
70cde49466SMauro Carvalho Chehab        usage_text = f"{prefix or 'usage: '} {prog} {' '.join(parts)}\n"
71cde49466SMauro Carvalho Chehab        return usage_text
72cde49466SMauro Carvalho Chehab
73cde49466SMauro Carvalho Chehab    def _format_action_invocation(self, action):
74*7ef684c9SMauro Carvalho Chehab        """
75*7ef684c9SMauro Carvalho Chehab        Enrich argument names.
76*7ef684c9SMauro Carvalho Chehab        """
77cde49466SMauro Carvalho Chehab        if not action.option_strings:
78cde49466SMauro Carvalho Chehab            return self.enrich_text(f"``{action.dest.upper()}``")
79cde49466SMauro Carvalho Chehab
80cde49466SMauro Carvalho Chehab        return ", ".join(action.option_strings)
81