|
import sys |
|
from typing import TYPE_CHECKING, Iterable, List |
|
|
|
if sys.version_info >= (3, 8): |
|
from typing import Literal |
|
else: |
|
from pip._vendor.typing_extensions import Literal |
|
|
|
|
|
from ._loop import loop_last |
|
|
|
if TYPE_CHECKING: |
|
from pip._vendor.rich.console import ConsoleOptions |
|
|
|
|
|
class Box: |
|
"""Defines characters to render boxes. |
|
|
|
โโโฌโ top |
|
โ โโ head |
|
โโโผโค head_row |
|
โ โโ mid |
|
โโโผโค row |
|
โโโผโค foot_row |
|
โ โโ foot |
|
โโโดโ bottom |
|
|
|
Args: |
|
box (str): Characters making up box. |
|
ascii (bool, optional): True if this box uses ascii characters only. Default is False. |
|
""" |
|
|
|
def __init__(self, box: str, *, ascii: bool = False) -> None: |
|
self._box = box |
|
self.ascii = ascii |
|
line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines() |
|
|
|
self.top_left, self.top, self.top_divider, self.top_right = iter(line1) |
|
|
|
self.head_left, _, self.head_vertical, self.head_right = iter(line2) |
|
|
|
( |
|
self.head_row_left, |
|
self.head_row_horizontal, |
|
self.head_row_cross, |
|
self.head_row_right, |
|
) = iter(line3) |
|
|
|
|
|
self.mid_left, _, self.mid_vertical, self.mid_right = iter(line4) |
|
|
|
self.row_left, self.row_horizontal, self.row_cross, self.row_right = iter(line5) |
|
|
|
( |
|
self.foot_row_left, |
|
self.foot_row_horizontal, |
|
self.foot_row_cross, |
|
self.foot_row_right, |
|
) = iter(line6) |
|
|
|
self.foot_left, _, self.foot_vertical, self.foot_right = iter(line7) |
|
|
|
self.bottom_left, self.bottom, self.bottom_divider, self.bottom_right = iter( |
|
line8 |
|
) |
|
|
|
def __repr__(self) -> str: |
|
return "Box(...)" |
|
|
|
def __str__(self) -> str: |
|
return self._box |
|
|
|
def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box": |
|
"""Substitute this box for another if it won't render due to platform issues. |
|
|
|
Args: |
|
options (ConsoleOptions): Console options used in rendering. |
|
safe (bool, optional): Substitute this for another Box if there are known problems |
|
displaying on the platform (currently only relevant on Windows). Default is True. |
|
|
|
Returns: |
|
Box: A different Box or the same Box. |
|
""" |
|
box = self |
|
if options.legacy_windows and safe: |
|
box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box) |
|
if options.ascii_only and not box.ascii: |
|
box = ASCII |
|
return box |
|
|
|
def get_plain_headed_box(self) -> "Box": |
|
"""If this box uses special characters for the borders of the header, then |
|
return the equivalent box that does not. |
|
|
|
Returns: |
|
Box: The most similar Box that doesn't use header-specific box characters. |
|
If the current Box already satisfies this criterion, then it's returned. |
|
""" |
|
return PLAIN_HEADED_SUBSTITUTIONS.get(self, self) |
|
|
|
def get_top(self, widths: Iterable[int]) -> str: |
|
"""Get the top of a simple box. |
|
|
|
Args: |
|
widths (List[int]): Widths of columns. |
|
|
|
Returns: |
|
str: A string of box characters. |
|
""" |
|
|
|
parts: List[str] = [] |
|
append = parts.append |
|
append(self.top_left) |
|
for last, width in loop_last(widths): |
|
append(self.top * width) |
|
if not last: |
|
append(self.top_divider) |
|
append(self.top_right) |
|
return "".join(parts) |
|
|
|
def get_row( |
|
self, |
|
widths: Iterable[int], |
|
level: Literal["head", "row", "foot", "mid"] = "row", |
|
edge: bool = True, |
|
) -> str: |
|
"""Get the top of a simple box. |
|
|
|
Args: |
|
width (List[int]): Widths of columns. |
|
|
|
Returns: |
|
str: A string of box characters. |
|
""" |
|
if level == "head": |
|
left = self.head_row_left |
|
horizontal = self.head_row_horizontal |
|
cross = self.head_row_cross |
|
right = self.head_row_right |
|
elif level == "row": |
|
left = self.row_left |
|
horizontal = self.row_horizontal |
|
cross = self.row_cross |
|
right = self.row_right |
|
elif level == "mid": |
|
left = self.mid_left |
|
horizontal = " " |
|
cross = self.mid_vertical |
|
right = self.mid_right |
|
elif level == "foot": |
|
left = self.foot_row_left |
|
horizontal = self.foot_row_horizontal |
|
cross = self.foot_row_cross |
|
right = self.foot_row_right |
|
else: |
|
raise ValueError("level must be 'head', 'row' or 'foot'") |
|
|
|
parts: List[str] = [] |
|
append = parts.append |
|
if edge: |
|
append(left) |
|
for last, width in loop_last(widths): |
|
append(horizontal * width) |
|
if not last: |
|
append(cross) |
|
if edge: |
|
append(right) |
|
return "".join(parts) |
|
|
|
def get_bottom(self, widths: Iterable[int]) -> str: |
|
"""Get the bottom of a simple box. |
|
|
|
Args: |
|
widths (List[int]): Widths of columns. |
|
|
|
Returns: |
|
str: A string of box characters. |
|
""" |
|
|
|
parts: List[str] = [] |
|
append = parts.append |
|
append(self.bottom_left) |
|
for last, width in loop_last(widths): |
|
append(self.bottom * width) |
|
if not last: |
|
append(self.bottom_divider) |
|
append(self.bottom_right) |
|
return "".join(parts) |
|
|
|
|
|
ASCII: Box = Box( |
|
"""\ |
|
+--+ |
|
| || |
|
|-+| |
|
| || |
|
|-+| |
|
|-+| |
|
| || |
|
+--+ |
|
""", |
|
ascii=True, |
|
) |
|
|
|
ASCII2: Box = Box( |
|
"""\ |
|
+-++ |
|
| || |
|
+-++ |
|
| || |
|
+-++ |
|
+-++ |
|
| || |
|
+-++ |
|
""", |
|
ascii=True, |
|
) |
|
|
|
ASCII_DOUBLE_HEAD: Box = Box( |
|
"""\ |
|
+-++ |
|
| || |
|
+=++ |
|
| || |
|
+-++ |
|
+-++ |
|
| || |
|
+-++ |
|
""", |
|
ascii=True, |
|
) |
|
|
|
SQUARE: Box = Box( |
|
"""\ |
|
โโโฌโ |
|
โ โโ |
|
โโโผโค |
|
โ โโ |
|
โโโผโค |
|
โโโผโค |
|
โ โโ |
|
โโโดโ |
|
""" |
|
) |
|
|
|
SQUARE_DOUBLE_HEAD: Box = Box( |
|
"""\ |
|
โโโฌโ |
|
โ โโ |
|
โโโชโก |
|
โ โโ |
|
โโโผโค |
|
โโโผโค |
|
โ โโ |
|
โโโดโ |
|
""" |
|
) |
|
|
|
MINIMAL: Box = Box( |
|
"""\ |
|
โท |
|
โ |
|
โถโโผโด |
|
โ |
|
โถโโผโด |
|
โถโโผโด |
|
โ |
|
โต |
|
""" |
|
) |
|
|
|
|
|
MINIMAL_HEAVY_HEAD: Box = Box( |
|
"""\ |
|
โท |
|
โ |
|
โบโโฟโธ |
|
โ |
|
โถโโผโด |
|
โถโโผโด |
|
โ |
|
โต |
|
""" |
|
) |
|
|
|
MINIMAL_DOUBLE_HEAD: Box = Box( |
|
"""\ |
|
โท |
|
โ |
|
โโช |
|
โ |
|
โโผ |
|
โโผ |
|
โ |
|
โต |
|
""" |
|
) |
|
|
|
|
|
SIMPLE: Box = Box( |
|
"""\ |
|
|
|
|
|
โโ |
|
|
|
|
|
โโ |
|
|
|
|
|
""" |
|
) |
|
|
|
SIMPLE_HEAD: Box = Box( |
|
"""\ |
|
|
|
|
|
โโ |
|
|
|
|
|
|
|
|
|
|
|
""" |
|
) |
|
|
|
|
|
SIMPLE_HEAVY: Box = Box( |
|
"""\ |
|
|
|
|
|
โโ |
|
|
|
|
|
โโ |
|
|
|
|
|
""" |
|
) |
|
|
|
|
|
HORIZONTALS: Box = Box( |
|
"""\ |
|
โโ |
|
|
|
โโ |
|
|
|
โโ |
|
โโ |
|
|
|
โโ |
|
""" |
|
) |
|
|
|
ROUNDED: Box = Box( |
|
"""\ |
|
โญโโฌโฎ |
|
โ โโ |
|
โโโผโค |
|
โ โโ |
|
โโโผโค |
|
โโโผโค |
|
โ โโ |
|
โฐโโดโฏ |
|
""" |
|
) |
|
|
|
HEAVY: Box = Box( |
|
"""\ |
|
โโโณโ |
|
โ โโ |
|
โฃโโโซ |
|
โ โโ |
|
โฃโโโซ |
|
โฃโโโซ |
|
โ โโ |
|
โโโปโ |
|
""" |
|
) |
|
|
|
HEAVY_EDGE: Box = Box( |
|
"""\ |
|
โโโฏโ |
|
โ โโ |
|
โ โโผโจ |
|
โ โโ |
|
โ โโผโจ |
|
โ โโผโจ |
|
โ โโ |
|
โโโทโ |
|
""" |
|
) |
|
|
|
HEAVY_HEAD: Box = Box( |
|
"""\ |
|
โโโณโ |
|
โ โโ |
|
โกโโโฉ |
|
โ โโ |
|
โโโผโค |
|
โโโผโค |
|
โ โโ |
|
โโโดโ |
|
""" |
|
) |
|
|
|
DOUBLE: Box = Box( |
|
"""\ |
|
โโโฆโ |
|
โ โโ |
|
โ โโฌโฃ |
|
โ โโ |
|
โ โโฌโฃ |
|
โ โโฌโฃ |
|
โ โโ |
|
โโโฉโ |
|
""" |
|
) |
|
|
|
DOUBLE_EDGE: Box = Box( |
|
"""\ |
|
โโโคโ |
|
โ โโ |
|
โโโผโข |
|
โ โโ |
|
โโโผโข |
|
โโโผโข |
|
โ โโ |
|
โโโงโ |
|
""" |
|
) |
|
|
|
MARKDOWN: Box = Box( |
|
"""\ |
|
|
|
| || |
|
|-|| |
|
| || |
|
|-|| |
|
|-|| |
|
| || |
|
|
|
""", |
|
ascii=True, |
|
) |
|
|
|
|
|
LEGACY_WINDOWS_SUBSTITUTIONS = { |
|
ROUNDED: SQUARE, |
|
MINIMAL_HEAVY_HEAD: MINIMAL, |
|
SIMPLE_HEAVY: SIMPLE, |
|
HEAVY: SQUARE, |
|
HEAVY_EDGE: SQUARE, |
|
HEAVY_HEAD: SQUARE, |
|
} |
|
|
|
|
|
PLAIN_HEADED_SUBSTITUTIONS = { |
|
HEAVY_HEAD: SQUARE, |
|
SQUARE_DOUBLE_HEAD: SQUARE, |
|
MINIMAL_DOUBLE_HEAD: MINIMAL, |
|
MINIMAL_HEAVY_HEAD: MINIMAL, |
|
ASCII_DOUBLE_HEAD: ASCII2, |
|
} |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
from pip._vendor.rich.columns import Columns |
|
from pip._vendor.rich.panel import Panel |
|
|
|
from . import box as box |
|
from .console import Console |
|
from .table import Table |
|
from .text import Text |
|
|
|
console = Console(record=True) |
|
|
|
BOXES = [ |
|
"ASCII", |
|
"ASCII2", |
|
"ASCII_DOUBLE_HEAD", |
|
"SQUARE", |
|
"SQUARE_DOUBLE_HEAD", |
|
"MINIMAL", |
|
"MINIMAL_HEAVY_HEAD", |
|
"MINIMAL_DOUBLE_HEAD", |
|
"SIMPLE", |
|
"SIMPLE_HEAD", |
|
"SIMPLE_HEAVY", |
|
"HORIZONTALS", |
|
"ROUNDED", |
|
"HEAVY", |
|
"HEAVY_EDGE", |
|
"HEAVY_HEAD", |
|
"DOUBLE", |
|
"DOUBLE_EDGE", |
|
"MARKDOWN", |
|
] |
|
|
|
console.print(Panel("[bold green]Box Constants", style="green"), justify="center") |
|
console.print() |
|
|
|
columns = Columns(expand=True, padding=2) |
|
for box_name in sorted(BOXES): |
|
table = Table( |
|
show_footer=True, style="dim", border_style="not dim", expand=True |
|
) |
|
table.add_column("Header 1", "Footer 1") |
|
table.add_column("Header 2", "Footer 2") |
|
table.add_row("Cell", "Cell") |
|
table.add_row("Cell", "Cell") |
|
table.box = getattr(box, box_name) |
|
table.title = Text(f"box.{box_name}", style="magenta") |
|
columns.add_renderable(table) |
|
console.print(columns) |
|
|
|
|
|
|