]> jfr.im git - dlqueue.git/blame - venv/lib/python3.11/site-packages/pip/_vendor/rich/box.py
init: venv aand flask
[dlqueue.git] / venv / lib / python3.11 / site-packages / pip / _vendor / rich / box.py
CommitLineData
e0df8241
JR
1import sys
2from typing import TYPE_CHECKING, Iterable, List
3
4if sys.version_info >= (3, 8):
5 from typing import Literal
6else:
7 from pip._vendor.typing_extensions import Literal # pragma: no cover
8
9
10from ._loop import loop_last
11
12if TYPE_CHECKING:
13 from pip._vendor.rich.console import ConsoleOptions
14
15
16class Box:
17 """Defines characters to render boxes.
18
19 ┌─┬┐ top
20 │ ││ head
21 ├─┼┤ head_row
22 │ ││ mid
23 ├─┼┤ row
24 ├─┼┤ foot_row
25 │ ││ foot
26 └─┴┘ bottom
27
28 Args:
29 box (str): Characters making up box.
30 ascii (bool, optional): True if this box uses ascii characters only. Default is False.
31 """
32
33 def __init__(self, box: str, *, ascii: bool = False) -> None:
34 self._box = box
35 self.ascii = ascii
36 line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines()
37 # top
38 self.top_left, self.top, self.top_divider, self.top_right = iter(line1)
39 # head
40 self.head_left, _, self.head_vertical, self.head_right = iter(line2)
41 # head_row
42 (
43 self.head_row_left,
44 self.head_row_horizontal,
45 self.head_row_cross,
46 self.head_row_right,
47 ) = iter(line3)
48
49 # mid
50 self.mid_left, _, self.mid_vertical, self.mid_right = iter(line4)
51 # row
52 self.row_left, self.row_horizontal, self.row_cross, self.row_right = iter(line5)
53 # foot_row
54 (
55 self.foot_row_left,
56 self.foot_row_horizontal,
57 self.foot_row_cross,
58 self.foot_row_right,
59 ) = iter(line6)
60 # foot
61 self.foot_left, _, self.foot_vertical, self.foot_right = iter(line7)
62 # bottom
63 self.bottom_left, self.bottom, self.bottom_divider, self.bottom_right = iter(
64 line8
65 )
66
67 def __repr__(self) -> str:
68 return "Box(...)"
69
70 def __str__(self) -> str:
71 return self._box
72
73 def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box":
74 """Substitute this box for another if it won't render due to platform issues.
75
76 Args:
77 options (ConsoleOptions): Console options used in rendering.
78 safe (bool, optional): Substitute this for another Box if there are known problems
79 displaying on the platform (currently only relevant on Windows). Default is True.
80
81 Returns:
82 Box: A different Box or the same Box.
83 """
84 box = self
85 if options.legacy_windows and safe:
86 box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box)
87 if options.ascii_only and not box.ascii:
88 box = ASCII
89 return box
90
91 def get_plain_headed_box(self) -> "Box":
92 """If this box uses special characters for the borders of the header, then
93 return the equivalent box that does not.
94
95 Returns:
96 Box: The most similar Box that doesn't use header-specific box characters.
97 If the current Box already satisfies this criterion, then it's returned.
98 """
99 return PLAIN_HEADED_SUBSTITUTIONS.get(self, self)
100
101 def get_top(self, widths: Iterable[int]) -> str:
102 """Get the top of a simple box.
103
104 Args:
105 widths (List[int]): Widths of columns.
106
107 Returns:
108 str: A string of box characters.
109 """
110
111 parts: List[str] = []
112 append = parts.append
113 append(self.top_left)
114 for last, width in loop_last(widths):
115 append(self.top * width)
116 if not last:
117 append(self.top_divider)
118 append(self.top_right)
119 return "".join(parts)
120
121 def get_row(
122 self,
123 widths: Iterable[int],
124 level: Literal["head", "row", "foot", "mid"] = "row",
125 edge: bool = True,
126 ) -> str:
127 """Get the top of a simple box.
128
129 Args:
130 width (List[int]): Widths of columns.
131
132 Returns:
133 str: A string of box characters.
134 """
135 if level == "head":
136 left = self.head_row_left
137 horizontal = self.head_row_horizontal
138 cross = self.head_row_cross
139 right = self.head_row_right
140 elif level == "row":
141 left = self.row_left
142 horizontal = self.row_horizontal
143 cross = self.row_cross
144 right = self.row_right
145 elif level == "mid":
146 left = self.mid_left
147 horizontal = " "
148 cross = self.mid_vertical
149 right = self.mid_right
150 elif level == "foot":
151 left = self.foot_row_left
152 horizontal = self.foot_row_horizontal
153 cross = self.foot_row_cross
154 right = self.foot_row_right
155 else:
156 raise ValueError("level must be 'head', 'row' or 'foot'")
157
158 parts: List[str] = []
159 append = parts.append
160 if edge:
161 append(left)
162 for last, width in loop_last(widths):
163 append(horizontal * width)
164 if not last:
165 append(cross)
166 if edge:
167 append(right)
168 return "".join(parts)
169
170 def get_bottom(self, widths: Iterable[int]) -> str:
171 """Get the bottom of a simple box.
172
173 Args:
174 widths (List[int]): Widths of columns.
175
176 Returns:
177 str: A string of box characters.
178 """
179
180 parts: List[str] = []
181 append = parts.append
182 append(self.bottom_left)
183 for last, width in loop_last(widths):
184 append(self.bottom * width)
185 if not last:
186 append(self.bottom_divider)
187 append(self.bottom_right)
188 return "".join(parts)
189
190
191ASCII: Box = Box(
192 """\
193+--+
194| ||
195|-+|
196| ||
197|-+|
198|-+|
199| ||
200+--+
201""",
202 ascii=True,
203)
204
205ASCII2: Box = Box(
206 """\
207+-++
208| ||
209+-++
210| ||
211+-++
212+-++
213| ||
214+-++
215""",
216 ascii=True,
217)
218
219ASCII_DOUBLE_HEAD: Box = Box(
220 """\
221+-++
222| ||
223+=++
224| ||
225+-++
226+-++
227| ||
228+-++
229""",
230 ascii=True,
231)
232
233SQUARE: Box = Box(
234 """\
235┌─┬┐
236│ ││
237├─┼┤
238│ ││
239├─┼┤
240├─┼┤
241│ ││
242└─┴┘
243"""
244)
245
246SQUARE_DOUBLE_HEAD: Box = Box(
247 """\
248┌─┬┐
249│ ││
250╞═╪╡
251│ ││
252├─┼┤
253├─┼┤
254│ ││
255└─┴┘
256"""
257)
258
259MINIMAL: Box = Box(
260 """\
261
262
263╶─┼╴
264
265╶─┼╴
266╶─┼╴
267
268
269"""
270)
271
272
273MINIMAL_HEAVY_HEAD: Box = Box(
274 """\
275
276
277╺━┿╸
278
279╶─┼╴
280╶─┼╴
281
282
283"""
284)
285
286MINIMAL_DOUBLE_HEAD: Box = Box(
287 """\
288
289
290 ═╪
291
292 ─┼
293 ─┼
294
295
296"""
297)
298
299
300SIMPLE: Box = Box(
301 """\
302
303
304 ──
305
306
307 ──
308
309
310"""
311)
312
313SIMPLE_HEAD: Box = Box(
314 """\
315
316
317 ──
318
319
320
321
322
323"""
324)
325
326
327SIMPLE_HEAVY: Box = Box(
328 """\
329
330
331 ━━
332
333
334 ━━
335
336
337"""
338)
339
340
341HORIZONTALS: Box = Box(
342 """\
343 ──
344
345 ──
346
347 ──
348 ──
349
350 ──
351"""
352)
353
354ROUNDED: Box = Box(
355 """\
356╭─┬╮
357│ ││
358├─┼┤
359│ ││
360├─┼┤
361├─┼┤
362│ ││
363╰─┴╯
364"""
365)
366
367HEAVY: Box = Box(
368 """\
369┏━┳┓
370┃ ┃┃
371┣━╋┫
372┃ ┃┃
373┣━╋┫
374┣━╋┫
375┃ ┃┃
376┗━┻┛
377"""
378)
379
380HEAVY_EDGE: Box = Box(
381 """\
382┏━┯┓
383┃ │┃
384┠─┼┨
385┃ │┃
386┠─┼┨
387┠─┼┨
388┃ │┃
389┗━┷┛
390"""
391)
392
393HEAVY_HEAD: Box = Box(
394 """\
395┏━┳┓
396┃ ┃┃
397┡━╇┩
398│ ││
399├─┼┤
400├─┼┤
401│ ││
402└─┴┘
403"""
404)
405
406DOUBLE: Box = Box(
407 """\
408╔═╦╗
409║ ║║
410╠═╬╣
411║ ║║
412╠═╬╣
413╠═╬╣
414║ ║║
415╚═╩╝
416"""
417)
418
419DOUBLE_EDGE: Box = Box(
420 """\
421╔═╤╗
422║ │║
423╟─┼╢
424║ │║
425╟─┼╢
426╟─┼╢
427║ │║
428╚═╧╝
429"""
430)
431
432MARKDOWN: Box = Box(
433 """\
434
435| ||
436|-||
437| ||
438|-||
439|-||
440| ||
441
442""",
443 ascii=True,
444)
445
446# Map Boxes that don't render with raster fonts on to equivalent that do
447LEGACY_WINDOWS_SUBSTITUTIONS = {
448 ROUNDED: SQUARE,
449 MINIMAL_HEAVY_HEAD: MINIMAL,
450 SIMPLE_HEAVY: SIMPLE,
451 HEAVY: SQUARE,
452 HEAVY_EDGE: SQUARE,
453 HEAVY_HEAD: SQUARE,
454}
455
456# Map headed boxes to their headerless equivalents
457PLAIN_HEADED_SUBSTITUTIONS = {
458 HEAVY_HEAD: SQUARE,
459 SQUARE_DOUBLE_HEAD: SQUARE,
460 MINIMAL_DOUBLE_HEAD: MINIMAL,
461 MINIMAL_HEAVY_HEAD: MINIMAL,
462 ASCII_DOUBLE_HEAD: ASCII2,
463}
464
465
466if __name__ == "__main__": # pragma: no cover
467
468 from pip._vendor.rich.columns import Columns
469 from pip._vendor.rich.panel import Panel
470
471 from . import box as box
472 from .console import Console
473 from .table import Table
474 from .text import Text
475
476 console = Console(record=True)
477
478 BOXES = [
479 "ASCII",
480 "ASCII2",
481 "ASCII_DOUBLE_HEAD",
482 "SQUARE",
483 "SQUARE_DOUBLE_HEAD",
484 "MINIMAL",
485 "MINIMAL_HEAVY_HEAD",
486 "MINIMAL_DOUBLE_HEAD",
487 "SIMPLE",
488 "SIMPLE_HEAD",
489 "SIMPLE_HEAVY",
490 "HORIZONTALS",
491 "ROUNDED",
492 "HEAVY",
493 "HEAVY_EDGE",
494 "HEAVY_HEAD",
495 "DOUBLE",
496 "DOUBLE_EDGE",
497 "MARKDOWN",
498 ]
499
500 console.print(Panel("[bold green]Box Constants", style="green"), justify="center")
501 console.print()
502
503 columns = Columns(expand=True, padding=2)
504 for box_name in sorted(BOXES):
505 table = Table(
506 show_footer=True, style="dim", border_style="not dim", expand=True
507 )
508 table.add_column("Header 1", "Footer 1")
509 table.add_column("Header 2", "Footer 2")
510 table.add_row("Cell", "Cell")
511 table.add_row("Cell", "Cell")
512 table.box = getattr(box, box_name)
513 table.title = Text(f"box.{box_name}", style="magenta")
514 columns.add_renderable(table)
515 console.print(columns)
516
517 # console.save_svg("box.svg")