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