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