from __future__ import annotations from typing import Iterable import rich.repr from rich.console import Console, ConsoleOptions, RenderResult from rich.highlighter import ReprHighlighter from rich.markup import render from rich.text import Text _highlighter = ReprHighlighter() def _markup_and_highlight(text: str) -> Text: """Highlight and render markup in a string of text, returning a styled Text object. Args: text: The text to highlight and markup. Returns: The Text, with highlighting and markup applied. """ return _highlighter(render(text)) class Example: """Renderable for an example, which can appear below bullet points in the help text. Attributes: markup: The markup to display for this example """ def __init__(self, markup: str) -> None: self.markup: str = markup def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: yield _markup_and_highlight(f" [dim]e.g. [/][i]{self.markup}[/]") @rich.repr.auto class Bullet: """Renderable for a single 'bullet point' containing information and optionally some examples pertaining to that information. Attributes: markup: The markup to display examples: An optional list of examples to display below this bullet. """ def __init__(self, markup: str, examples: Iterable[Example] | None = None) -> None: self.markup: str = markup self.examples: Iterable[Example] | None = [] if examples is None else examples def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: yield _markup_and_highlight(self.markup) if self.examples is not None: yield from self.examples @rich.repr.auto class HelpText: """Renderable for help text - the user is shown this when they encounter a style-related error (e.g. setting a style property to an invalid value). Attributes: summary: A succinct summary of the issue. bullets: Bullet points which provide additional context around the issue. These are rendered below the summary. """ def __init__( self, summary: str, *, bullets: Iterable[Bullet] | None = None ) -> None: self.summary: str = summary self.bullets: Iterable[Bullet] | None = bullets or [] def __str__(self) -> str: return self.summary def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: from rich.tree import Tree tree = Tree(_markup_and_highlight(f"[b blue]{self.summary}"), guide_style="dim") if self.bullets is not None: for bullet in self.bullets: tree.add(bullet) yield tree