| from typing import cast, List, Optional, Tuple, TYPE_CHECKING, Union |
| |
| if TYPE_CHECKING: |
| from .console import ( |
| Console, |
| ConsoleOptions, |
| RenderableType, |
| RenderResult, |
| ) |
| from .jupyter import JupyterMixin |
| from .measure import Measurement |
| from .style import Style |
| from .segment import Segment |
| |
| |
| PaddingDimensions = Union[int, Tuple[int], Tuple[int, int], Tuple[int, int, int, int]] |
| |
| |
| class Padding(JupyterMixin): |
| """Draw space around content. |
| |
| Example: |
| >>> print(Padding("Hello", (2, 4), style="on blue")) |
| |
| Args: |
| renderable (RenderableType): String or other renderable. |
| pad (Union[int, Tuple[int]]): Padding for top, right, bottom, and left borders. |
| May be specified with 1, 2, or 4 integers (CSS style). |
| style (Union[str, Style], optional): Style for padding characters. Defaults to "none". |
| expand (bool, optional): Expand padding to fit available width. Defaults to True. |
| """ |
| |
| def __init__( |
| self, |
| renderable: "RenderableType", |
| pad: "PaddingDimensions" = (0, 0, 0, 0), |
| *, |
| style: Union[str, Style] = "none", |
| expand: bool = True, |
| ): |
| self.renderable = renderable |
| self.top, self.right, self.bottom, self.left = self.unpack(pad) |
| self.style = style |
| self.expand = expand |
| |
| @classmethod |
| def indent(cls, renderable: "RenderableType", level: int) -> "Padding": |
| """Make padding instance to render an indent. |
| |
| Args: |
| renderable (RenderableType): String or other renderable. |
| level (int): Number of characters to indent. |
| |
| Returns: |
| Padding: A Padding instance. |
| """ |
| |
| return Padding(renderable, pad=(0, 0, 0, level), expand=False) |
| |
| @staticmethod |
| def unpack(pad: "PaddingDimensions") -> Tuple[int, int, int, int]: |
| """Unpack padding specified in CSS style.""" |
| if isinstance(pad, int): |
| return (pad, pad, pad, pad) |
| if len(pad) == 1: |
| _pad = pad[0] |
| return (_pad, _pad, _pad, _pad) |
| if len(pad) == 2: |
| pad_top, pad_right = cast(Tuple[int, int], pad) |
| return (pad_top, pad_right, pad_top, pad_right) |
| if len(pad) == 4: |
| top, right, bottom, left = cast(Tuple[int, int, int, int], pad) |
| return (top, right, bottom, left) |
| raise ValueError(f"1, 2 or 4 integers required for padding; {len(pad)} given") |
| |
| def __repr__(self) -> str: |
| return f"Padding({self.renderable!r}, ({self.top},{self.right},{self.bottom},{self.left}))" |
| |
| def __rich_console__( |
| self, console: "Console", options: "ConsoleOptions" |
| ) -> "RenderResult": |
| style = console.get_style(self.style) |
| if self.expand: |
| width = options.max_width |
| else: |
| width = min( |
| Measurement.get(console, options, self.renderable).maximum |
| + self.left |
| + self.right, |
| options.max_width, |
| ) |
| render_options = options.update_width(width - self.left - self.right) |
| if render_options.height is not None: |
| render_options = render_options.update_height( |
| height=render_options.height - self.top - self.bottom |
| ) |
| lines = console.render_lines( |
| self.renderable, render_options, style=style, pad=True |
| ) |
| _Segment = Segment |
| |
| left = _Segment(" " * self.left, style) if self.left else None |
| right = ( |
| [_Segment(f'{" " * self.right}', style), _Segment.line()] |
| if self.right |
| else [_Segment.line()] |
| ) |
| blank_line: Optional[List[Segment]] = None |
| if self.top: |
| blank_line = [_Segment(f'{" " * width}\n', style)] |
| yield from blank_line * self.top |
| if left: |
| for line in lines: |
| yield left |
| yield from line |
| yield from right |
| else: |
| for line in lines: |
| yield from line |
| yield from right |
| if self.bottom: |
| blank_line = blank_line or [_Segment(f'{" " * width}\n', style)] |
| yield from blank_line * self.bottom |
| |
| def __rich_measure__( |
| self, console: "Console", options: "ConsoleOptions" |
| ) -> "Measurement": |
| max_width = options.max_width |
| extra_width = self.left + self.right |
| if max_width - extra_width < 1: |
| return Measurement(max_width, max_width) |
| measure_min, measure_max = Measurement.get(console, options, self.renderable) |
| measurement = Measurement(measure_min + extra_width, measure_max + extra_width) |
| measurement = measurement.with_maximum(max_width) |
| return measurement |
| |
| |
| if __name__ == "__main__": # pragma: no cover |
| from pip._vendor.rich import print |
| |
| print(Padding("Hello, World", (2, 4), style="on blue")) |