Загрузить файлы в «venv/Lib/site-packages/pip/_vendor/rich»
This commit is contained in:
151
venv/Lib/site-packages/pip/_vendor/rich/measure.py
Normal file
151
venv/Lib/site-packages/pip/_vendor/rich/measure.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
from operator import itemgetter
|
||||||
|
from typing import TYPE_CHECKING, Callable, NamedTuple, Optional, Sequence
|
||||||
|
|
||||||
|
from . import errors
|
||||||
|
from .protocol import is_renderable, rich_cast
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .console import Console, ConsoleOptions, RenderableType
|
||||||
|
|
||||||
|
|
||||||
|
class Measurement(NamedTuple):
|
||||||
|
"""Stores the minimum and maximum widths (in characters) required to render an object."""
|
||||||
|
|
||||||
|
minimum: int
|
||||||
|
"""Minimum number of cells required to render."""
|
||||||
|
maximum: int
|
||||||
|
"""Maximum number of cells required to render."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def span(self) -> int:
|
||||||
|
"""Get difference between maximum and minimum."""
|
||||||
|
return self.maximum - self.minimum
|
||||||
|
|
||||||
|
def normalize(self) -> "Measurement":
|
||||||
|
"""Get measurement that ensures that minimum <= maximum and minimum >= 0
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: A normalized measurement.
|
||||||
|
"""
|
||||||
|
minimum, maximum = self
|
||||||
|
minimum = min(max(0, minimum), maximum)
|
||||||
|
return Measurement(max(0, minimum), max(0, max(minimum, maximum)))
|
||||||
|
|
||||||
|
def with_maximum(self, width: int) -> "Measurement":
|
||||||
|
"""Get a RenderableWith where the widths are <= width.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
width (int): Maximum desired width.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: New Measurement object.
|
||||||
|
"""
|
||||||
|
minimum, maximum = self
|
||||||
|
return Measurement(min(minimum, width), min(maximum, width))
|
||||||
|
|
||||||
|
def with_minimum(self, width: int) -> "Measurement":
|
||||||
|
"""Get a RenderableWith where the widths are >= width.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
width (int): Minimum desired width.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: New Measurement object.
|
||||||
|
"""
|
||||||
|
minimum, maximum = self
|
||||||
|
width = max(0, width)
|
||||||
|
return Measurement(max(minimum, width), max(maximum, width))
|
||||||
|
|
||||||
|
def clamp(
|
||||||
|
self, min_width: Optional[int] = None, max_width: Optional[int] = None
|
||||||
|
) -> "Measurement":
|
||||||
|
"""Clamp a measurement within the specified range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
min_width (int): Minimum desired width, or ``None`` for no minimum. Defaults to None.
|
||||||
|
max_width (int): Maximum desired width, or ``None`` for no maximum. Defaults to None.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: New Measurement object.
|
||||||
|
"""
|
||||||
|
measurement = self
|
||||||
|
if min_width is not None:
|
||||||
|
measurement = measurement.with_minimum(min_width)
|
||||||
|
if max_width is not None:
|
||||||
|
measurement = measurement.with_maximum(max_width)
|
||||||
|
return measurement
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(
|
||||||
|
cls, console: "Console", options: "ConsoleOptions", renderable: "RenderableType"
|
||||||
|
) -> "Measurement":
|
||||||
|
"""Get a measurement for a renderable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
console (~rich.console.Console): Console instance.
|
||||||
|
options (~rich.console.ConsoleOptions): Console options.
|
||||||
|
renderable (RenderableType): An object that may be rendered with Rich.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
errors.NotRenderableError: If the object is not renderable.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: Measurement object containing range of character widths required to render the object.
|
||||||
|
"""
|
||||||
|
_max_width = options.max_width
|
||||||
|
if _max_width < 1:
|
||||||
|
return Measurement(0, 0)
|
||||||
|
if isinstance(renderable, str):
|
||||||
|
renderable = console.render_str(
|
||||||
|
renderable, markup=options.markup, highlight=False
|
||||||
|
)
|
||||||
|
renderable = rich_cast(renderable)
|
||||||
|
if is_renderable(renderable):
|
||||||
|
get_console_width: Optional[
|
||||||
|
Callable[["Console", "ConsoleOptions"], "Measurement"]
|
||||||
|
] = getattr(renderable, "__rich_measure__", None)
|
||||||
|
if get_console_width is not None:
|
||||||
|
render_width = (
|
||||||
|
get_console_width(console, options)
|
||||||
|
.normalize()
|
||||||
|
.with_maximum(_max_width)
|
||||||
|
)
|
||||||
|
if render_width.maximum < 1:
|
||||||
|
return Measurement(0, 0)
|
||||||
|
return render_width.normalize()
|
||||||
|
else:
|
||||||
|
return Measurement(0, _max_width)
|
||||||
|
else:
|
||||||
|
raise errors.NotRenderableError(
|
||||||
|
f"Unable to get render width for {renderable!r}; "
|
||||||
|
"a str, Segment, or object with __rich_console__ method is required"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def measure_renderables(
|
||||||
|
console: "Console",
|
||||||
|
options: "ConsoleOptions",
|
||||||
|
renderables: Sequence["RenderableType"],
|
||||||
|
) -> "Measurement":
|
||||||
|
"""Get a measurement that would fit a number of renderables.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
console (~rich.console.Console): Console instance.
|
||||||
|
options (~rich.console.ConsoleOptions): Console options.
|
||||||
|
renderables (Iterable[RenderableType]): One or more renderable objects.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Measurement: Measurement object containing range of character widths required to
|
||||||
|
contain all given renderables.
|
||||||
|
"""
|
||||||
|
if not renderables:
|
||||||
|
return Measurement(0, 0)
|
||||||
|
get_measurement = Measurement.get
|
||||||
|
measurements = [
|
||||||
|
get_measurement(console, options, renderable) for renderable in renderables
|
||||||
|
]
|
||||||
|
measured_width = Measurement(
|
||||||
|
max(measurements, key=itemgetter(0)).minimum,
|
||||||
|
max(measurements, key=itemgetter(1)).maximum,
|
||||||
|
)
|
||||||
|
return measured_width
|
||||||
141
venv/Lib/site-packages/pip/_vendor/rich/padding.py
Normal file
141
venv/Lib/site-packages/pip/_vendor/rich/padding.py
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
from typing import TYPE_CHECKING, List, Optional, Tuple, Union
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .console import (
|
||||||
|
Console,
|
||||||
|
ConsoleOptions,
|
||||||
|
RenderableType,
|
||||||
|
RenderResult,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .jupyter import JupyterMixin
|
||||||
|
from .measure import Measurement
|
||||||
|
from .segment import Segment
|
||||||
|
from .style import Style
|
||||||
|
|
||||||
|
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 = pad
|
||||||
|
return (pad_top, pad_right, pad_top, pad_right)
|
||||||
|
if len(pad) == 4:
|
||||||
|
top, right, bottom, left = 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"))
|
||||||
34
venv/Lib/site-packages/pip/_vendor/rich/pager.py
Normal file
34
venv/Lib/site-packages/pip/_vendor/rich/pager.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class Pager(ABC):
|
||||||
|
"""Base class for a pager."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def show(self, content: str) -> None:
|
||||||
|
"""Show content in pager.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
content (str): Content to be displayed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class SystemPager(Pager):
|
||||||
|
"""Uses the pager installed on the system."""
|
||||||
|
|
||||||
|
def _pager(self, content: str) -> Any: # pragma: no cover
|
||||||
|
return __import__("pydoc").pager(content)
|
||||||
|
|
||||||
|
def show(self, content: str) -> None:
|
||||||
|
"""Use the same pager used by pydoc."""
|
||||||
|
self._pager(content)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
from .__main__ import make_test_card
|
||||||
|
from .console import Console
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
with console.pager(styles=True):
|
||||||
|
console.print(make_test_card())
|
||||||
100
venv/Lib/site-packages/pip/_vendor/rich/palette.py
Normal file
100
venv/Lib/site-packages/pip/_vendor/rich/palette.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
from math import sqrt
|
||||||
|
from functools import lru_cache
|
||||||
|
from typing import Sequence, Tuple, TYPE_CHECKING
|
||||||
|
|
||||||
|
from .color_triplet import ColorTriplet
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pip._vendor.rich.table import Table
|
||||||
|
|
||||||
|
|
||||||
|
class Palette:
|
||||||
|
"""A palette of available colors."""
|
||||||
|
|
||||||
|
def __init__(self, colors: Sequence[Tuple[int, int, int]]):
|
||||||
|
self._colors = colors
|
||||||
|
|
||||||
|
def __getitem__(self, number: int) -> ColorTriplet:
|
||||||
|
return ColorTriplet(*self._colors[number])
|
||||||
|
|
||||||
|
def __rich__(self) -> "Table":
|
||||||
|
from pip._vendor.rich.color import Color
|
||||||
|
from pip._vendor.rich.style import Style
|
||||||
|
from pip._vendor.rich.text import Text
|
||||||
|
from pip._vendor.rich.table import Table
|
||||||
|
|
||||||
|
table = Table(
|
||||||
|
"index",
|
||||||
|
"RGB",
|
||||||
|
"Color",
|
||||||
|
title="Palette",
|
||||||
|
caption=f"{len(self._colors)} colors",
|
||||||
|
highlight=True,
|
||||||
|
caption_justify="right",
|
||||||
|
)
|
||||||
|
for index, color in enumerate(self._colors):
|
||||||
|
table.add_row(
|
||||||
|
str(index),
|
||||||
|
repr(color),
|
||||||
|
Text(" " * 16, style=Style(bgcolor=Color.from_rgb(*color))),
|
||||||
|
)
|
||||||
|
return table
|
||||||
|
|
||||||
|
# This is somewhat inefficient and needs caching
|
||||||
|
@lru_cache(maxsize=1024)
|
||||||
|
def match(self, color: Tuple[int, int, int]) -> int:
|
||||||
|
"""Find a color from a palette that most closely matches a given color.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
color (Tuple[int, int, int]): RGB components in range 0 > 255.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Index of closes matching color.
|
||||||
|
"""
|
||||||
|
red1, green1, blue1 = color
|
||||||
|
_sqrt = sqrt
|
||||||
|
get_color = self._colors.__getitem__
|
||||||
|
|
||||||
|
def get_color_distance(index: int) -> float:
|
||||||
|
"""Get the distance to a color."""
|
||||||
|
red2, green2, blue2 = get_color(index)
|
||||||
|
red_mean = (red1 + red2) // 2
|
||||||
|
red = red1 - red2
|
||||||
|
green = green1 - green2
|
||||||
|
blue = blue1 - blue2
|
||||||
|
return _sqrt(
|
||||||
|
(((512 + red_mean) * red * red) >> 8)
|
||||||
|
+ 4 * green * green
|
||||||
|
+ (((767 - red_mean) * blue * blue) >> 8)
|
||||||
|
)
|
||||||
|
|
||||||
|
min_index = min(range(len(self._colors)), key=get_color_distance)
|
||||||
|
return min_index
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
import colorsys
|
||||||
|
from typing import Iterable
|
||||||
|
from pip._vendor.rich.color import Color
|
||||||
|
from pip._vendor.rich.console import Console, ConsoleOptions
|
||||||
|
from pip._vendor.rich.segment import Segment
|
||||||
|
from pip._vendor.rich.style import Style
|
||||||
|
|
||||||
|
class ColorBox:
|
||||||
|
def __rich_console__(
|
||||||
|
self, console: Console, options: ConsoleOptions
|
||||||
|
) -> Iterable[Segment]:
|
||||||
|
height = console.size.height - 3
|
||||||
|
for y in range(0, height):
|
||||||
|
for x in range(options.max_width):
|
||||||
|
h = x / options.max_width
|
||||||
|
l = y / (height + 1)
|
||||||
|
r1, g1, b1 = colorsys.hls_to_rgb(h, l, 1.0)
|
||||||
|
r2, g2, b2 = colorsys.hls_to_rgb(h, l + (1 / height / 2), 1.0)
|
||||||
|
bgcolor = Color.from_rgb(r1 * 255, g1 * 255, b1 * 255)
|
||||||
|
color = Color.from_rgb(r2 * 255, g2 * 255, b2 * 255)
|
||||||
|
yield Segment("▄", Style(color=color, bgcolor=bgcolor))
|
||||||
|
yield Segment.line()
|
||||||
|
|
||||||
|
console = Console()
|
||||||
|
console.print(ColorBox())
|
||||||
317
venv/Lib/site-packages/pip/_vendor/rich/panel.py
Normal file
317
venv/Lib/site-packages/pip/_vendor/rich/panel.py
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from .align import AlignMethod
|
||||||
|
from .box import ROUNDED, Box
|
||||||
|
from .cells import cell_len
|
||||||
|
from .jupyter import JupyterMixin
|
||||||
|
from .measure import Measurement, measure_renderables
|
||||||
|
from .padding import Padding, PaddingDimensions
|
||||||
|
from .segment import Segment
|
||||||
|
from .style import Style, StyleType
|
||||||
|
from .text import Text, TextType
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .console import Console, ConsoleOptions, RenderableType, RenderResult
|
||||||
|
|
||||||
|
|
||||||
|
class Panel(JupyterMixin):
|
||||||
|
"""A console renderable that draws a border around its contents.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> console.print(Panel("Hello, World!"))
|
||||||
|
|
||||||
|
Args:
|
||||||
|
renderable (RenderableType): A console renderable object.
|
||||||
|
box (Box): A Box instance that defines the look of the border (see :ref:`appendix_box`. Defaults to box.ROUNDED.
|
||||||
|
title (Optional[TextType], optional): Optional title displayed in panel header. Defaults to None.
|
||||||
|
title_align (AlignMethod, optional): Alignment of title. Defaults to "center".
|
||||||
|
subtitle (Optional[TextType], optional): Optional subtitle displayed in panel footer. Defaults to None.
|
||||||
|
subtitle_align (AlignMethod, optional): Alignment of subtitle. Defaults to "center".
|
||||||
|
safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.
|
||||||
|
expand (bool, optional): If True the panel will stretch to fill the console width, otherwise it will be sized to fit the contents. Defaults to True.
|
||||||
|
style (str, optional): The style of the panel (border and contents). Defaults to "none".
|
||||||
|
border_style (str, optional): The style of the border. Defaults to "none".
|
||||||
|
width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.
|
||||||
|
height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect.
|
||||||
|
padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0.
|
||||||
|
highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
renderable: "RenderableType",
|
||||||
|
box: Box = ROUNDED,
|
||||||
|
*,
|
||||||
|
title: Optional[TextType] = None,
|
||||||
|
title_align: AlignMethod = "center",
|
||||||
|
subtitle: Optional[TextType] = None,
|
||||||
|
subtitle_align: AlignMethod = "center",
|
||||||
|
safe_box: Optional[bool] = None,
|
||||||
|
expand: bool = True,
|
||||||
|
style: StyleType = "none",
|
||||||
|
border_style: StyleType = "none",
|
||||||
|
width: Optional[int] = None,
|
||||||
|
height: Optional[int] = None,
|
||||||
|
padding: PaddingDimensions = (0, 1),
|
||||||
|
highlight: bool = False,
|
||||||
|
) -> None:
|
||||||
|
self.renderable = renderable
|
||||||
|
self.box = box
|
||||||
|
self.title = title
|
||||||
|
self.title_align: AlignMethod = title_align
|
||||||
|
self.subtitle = subtitle
|
||||||
|
self.subtitle_align = subtitle_align
|
||||||
|
self.safe_box = safe_box
|
||||||
|
self.expand = expand
|
||||||
|
self.style = style
|
||||||
|
self.border_style = border_style
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.padding = padding
|
||||||
|
self.highlight = highlight
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fit(
|
||||||
|
cls,
|
||||||
|
renderable: "RenderableType",
|
||||||
|
box: Box = ROUNDED,
|
||||||
|
*,
|
||||||
|
title: Optional[TextType] = None,
|
||||||
|
title_align: AlignMethod = "center",
|
||||||
|
subtitle: Optional[TextType] = None,
|
||||||
|
subtitle_align: AlignMethod = "center",
|
||||||
|
safe_box: Optional[bool] = None,
|
||||||
|
style: StyleType = "none",
|
||||||
|
border_style: StyleType = "none",
|
||||||
|
width: Optional[int] = None,
|
||||||
|
height: Optional[int] = None,
|
||||||
|
padding: PaddingDimensions = (0, 1),
|
||||||
|
highlight: bool = False,
|
||||||
|
) -> "Panel":
|
||||||
|
"""An alternative constructor that sets expand=False."""
|
||||||
|
return cls(
|
||||||
|
renderable,
|
||||||
|
box,
|
||||||
|
title=title,
|
||||||
|
title_align=title_align,
|
||||||
|
subtitle=subtitle,
|
||||||
|
subtitle_align=subtitle_align,
|
||||||
|
safe_box=safe_box,
|
||||||
|
style=style,
|
||||||
|
border_style=border_style,
|
||||||
|
width=width,
|
||||||
|
height=height,
|
||||||
|
padding=padding,
|
||||||
|
highlight=highlight,
|
||||||
|
expand=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _title(self) -> Optional[Text]:
|
||||||
|
if self.title:
|
||||||
|
title_text = (
|
||||||
|
Text.from_markup(self.title)
|
||||||
|
if isinstance(self.title, str)
|
||||||
|
else self.title.copy()
|
||||||
|
)
|
||||||
|
title_text.end = ""
|
||||||
|
title_text.plain = title_text.plain.replace("\n", " ")
|
||||||
|
title_text.no_wrap = True
|
||||||
|
title_text.expand_tabs()
|
||||||
|
title_text.pad(1)
|
||||||
|
return title_text
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _subtitle(self) -> Optional[Text]:
|
||||||
|
if self.subtitle:
|
||||||
|
subtitle_text = (
|
||||||
|
Text.from_markup(self.subtitle)
|
||||||
|
if isinstance(self.subtitle, str)
|
||||||
|
else self.subtitle.copy()
|
||||||
|
)
|
||||||
|
subtitle_text.end = ""
|
||||||
|
subtitle_text.plain = subtitle_text.plain.replace("\n", " ")
|
||||||
|
subtitle_text.no_wrap = True
|
||||||
|
subtitle_text.expand_tabs()
|
||||||
|
subtitle_text.pad(1)
|
||||||
|
return subtitle_text
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __rich_console__(
|
||||||
|
self, console: "Console", options: "ConsoleOptions"
|
||||||
|
) -> "RenderResult":
|
||||||
|
_padding = Padding.unpack(self.padding)
|
||||||
|
renderable = (
|
||||||
|
Padding(self.renderable, _padding) if any(_padding) else self.renderable
|
||||||
|
)
|
||||||
|
style = console.get_style(self.style)
|
||||||
|
border_style = style + console.get_style(self.border_style)
|
||||||
|
width = (
|
||||||
|
options.max_width
|
||||||
|
if self.width is None
|
||||||
|
else min(options.max_width, self.width)
|
||||||
|
)
|
||||||
|
|
||||||
|
safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box
|
||||||
|
box = self.box.substitute(options, safe=safe_box)
|
||||||
|
|
||||||
|
def align_text(
|
||||||
|
text: Text, width: int, align: str, character: str, style: Style
|
||||||
|
) -> Text:
|
||||||
|
"""Gets new aligned text.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (Text): Title or subtitle text.
|
||||||
|
width (int): Desired width.
|
||||||
|
align (str): Alignment.
|
||||||
|
character (str): Character for alignment.
|
||||||
|
style (Style): Border style
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Text: New text instance
|
||||||
|
"""
|
||||||
|
text = text.copy()
|
||||||
|
text.truncate(width)
|
||||||
|
excess_space = width - cell_len(text.plain)
|
||||||
|
if text.style:
|
||||||
|
text.stylize(console.get_style(text.style))
|
||||||
|
|
||||||
|
if excess_space:
|
||||||
|
if align == "left":
|
||||||
|
return Text.assemble(
|
||||||
|
text,
|
||||||
|
(character * excess_space, style),
|
||||||
|
no_wrap=True,
|
||||||
|
end="",
|
||||||
|
)
|
||||||
|
elif align == "center":
|
||||||
|
left = excess_space // 2
|
||||||
|
return Text.assemble(
|
||||||
|
(character * left, style),
|
||||||
|
text,
|
||||||
|
(character * (excess_space - left), style),
|
||||||
|
no_wrap=True,
|
||||||
|
end="",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return Text.assemble(
|
||||||
|
(character * excess_space, style),
|
||||||
|
text,
|
||||||
|
no_wrap=True,
|
||||||
|
end="",
|
||||||
|
)
|
||||||
|
return text
|
||||||
|
|
||||||
|
title_text = self._title
|
||||||
|
if title_text is not None:
|
||||||
|
title_text.stylize_before(border_style)
|
||||||
|
|
||||||
|
child_width = (
|
||||||
|
width - 2
|
||||||
|
if self.expand
|
||||||
|
else console.measure(
|
||||||
|
renderable, options=options.update_width(width - 2)
|
||||||
|
).maximum
|
||||||
|
)
|
||||||
|
child_height = self.height or options.height or None
|
||||||
|
if child_height:
|
||||||
|
child_height -= 2
|
||||||
|
if title_text is not None:
|
||||||
|
child_width = min(
|
||||||
|
options.max_width - 2, max(child_width, title_text.cell_len + 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
width = child_width + 2
|
||||||
|
child_options = options.update(
|
||||||
|
width=child_width, height=child_height, highlight=self.highlight
|
||||||
|
)
|
||||||
|
lines = console.render_lines(renderable, child_options, style=style)
|
||||||
|
|
||||||
|
line_start = Segment(box.mid_left, border_style)
|
||||||
|
line_end = Segment(f"{box.mid_right}", border_style)
|
||||||
|
new_line = Segment.line()
|
||||||
|
if title_text is None or width <= 4:
|
||||||
|
yield Segment(box.get_top([width - 2]), border_style)
|
||||||
|
else:
|
||||||
|
title_text = align_text(
|
||||||
|
title_text,
|
||||||
|
width - 4,
|
||||||
|
self.title_align,
|
||||||
|
box.top,
|
||||||
|
border_style,
|
||||||
|
)
|
||||||
|
yield Segment(box.top_left + box.top, border_style)
|
||||||
|
yield from console.render(title_text, child_options.update_width(width - 4))
|
||||||
|
yield Segment(box.top + box.top_right, border_style)
|
||||||
|
|
||||||
|
yield new_line
|
||||||
|
for line in lines:
|
||||||
|
yield line_start
|
||||||
|
yield from line
|
||||||
|
yield line_end
|
||||||
|
yield new_line
|
||||||
|
|
||||||
|
subtitle_text = self._subtitle
|
||||||
|
if subtitle_text is not None:
|
||||||
|
subtitle_text.stylize_before(border_style)
|
||||||
|
|
||||||
|
if subtitle_text is None or width <= 4:
|
||||||
|
yield Segment(box.get_bottom([width - 2]), border_style)
|
||||||
|
else:
|
||||||
|
subtitle_text = align_text(
|
||||||
|
subtitle_text,
|
||||||
|
width - 4,
|
||||||
|
self.subtitle_align,
|
||||||
|
box.bottom,
|
||||||
|
border_style,
|
||||||
|
)
|
||||||
|
yield Segment(box.bottom_left + box.bottom, border_style)
|
||||||
|
yield from console.render(
|
||||||
|
subtitle_text, child_options.update_width(width - 4)
|
||||||
|
)
|
||||||
|
yield Segment(box.bottom + box.bottom_right, border_style)
|
||||||
|
|
||||||
|
yield new_line
|
||||||
|
|
||||||
|
def __rich_measure__(
|
||||||
|
self, console: "Console", options: "ConsoleOptions"
|
||||||
|
) -> "Measurement":
|
||||||
|
_title = self._title
|
||||||
|
_, right, _, left = Padding.unpack(self.padding)
|
||||||
|
padding = left + right
|
||||||
|
renderables = [self.renderable, _title] if _title else [self.renderable]
|
||||||
|
|
||||||
|
if self.width is None:
|
||||||
|
width = (
|
||||||
|
measure_renderables(
|
||||||
|
console,
|
||||||
|
options.update_width(options.max_width - padding - 2),
|
||||||
|
renderables,
|
||||||
|
).maximum
|
||||||
|
+ padding
|
||||||
|
+ 2
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
width = self.width
|
||||||
|
return Measurement(width, width)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
from .console import Console
|
||||||
|
|
||||||
|
c = Console()
|
||||||
|
|
||||||
|
from .box import DOUBLE, ROUNDED
|
||||||
|
from .padding import Padding
|
||||||
|
|
||||||
|
p = Panel(
|
||||||
|
"Hello, World!",
|
||||||
|
title="rich.Panel",
|
||||||
|
style="white on blue",
|
||||||
|
box=DOUBLE,
|
||||||
|
padding=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
c.print()
|
||||||
|
c.print(p)
|
||||||
Reference in New Issue
Block a user