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