File size: 4,970 Bytes
870ab6b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
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"))
|