From ab178c2accc232f3b23cdf5286c7fe91c2059ec3 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 27 Jun 2020 22:16:00 +0100 Subject: [PATCH] box docs --- docs/source/appendix/box.rst | 168 ++++++++++++----------------------- rich/box.py | 33 +++++-- rich/columns.py | 14 ++- rich/table.py | 10 ++- tests/test_columns.py | 2 +- 5 files changed, 100 insertions(+), 127 deletions(-) diff --git a/docs/source/appendix/box.rst b/docs/source/appendix/box.rst index e19f0afa..24415fc8 100644 --- a/docs/source/appendix/box.rst +++ b/docs/source/appendix/box.rst @@ -8,120 +8,62 @@ Rich defines a number of ways of drawing boxes and lines such as those used in t from rich import box table = Table(box=box.SQUARE) -The constants are as follows: + + +.. note:: + Some of the box drawing characters will not display correctly on Windows legacy terminal (cmd.exe) with *raster* fonts, and are disabled by default. If you want the full range of box options on Windows legacy terminal, use a *truetype* font and set the ``safe_box`` parameter on the Table class to ``False``. + + +The following table is generated with the following command:: + + python -m rich.box .. raw:: html -
         box.ASCII          
-    +-------------------------+
-    |            |            |
-    |------------+------------|
-    |            |            |
-    |------------+------------|
-    |            |            |
-    +-------------------------+
-             box.SQUARE         
-    ┌────────────┬────────────┐
-    │                        │
-    ├────────────┼────────────┤
-    │                        │
-    ├────────────┼────────────┤
-    │                        │
-    └────────────┴────────────┘
-            box.MINIMAL         
-                            
-                             
-    ────────────┼──────────── 
-                             
-    ────────────┼──────────── 
-                             
-                            
-       box.MINIMAL_HEAVY_HEAD   
-                            
-                             
-    ━━━━━━━━━━━━┿━━━━━━━━━━━━ 
-                             
-    ────────────┼──────────── 
-                             
-                            
-      box.MINIMAL_DOUBLE_HEAD   
-                            
-                             
-    ════════════╪════════════ 
-                             
-    ────────────┼──────────── 
-                             
-                            
-             box.SIMPLE         
-                            
-                              
-    ───────────────────────────
-                              
-    ───────────────────────────
-                              
-                            
-          box.SIMPLE_HEAVY      
-                            
-                              
-    ╺━━━━━━━━━━━━━━━━━━━━━━━━━╸
-                              
-    ╺━━━━━━━━━━━━━━━━━━━━━━━━━╸
-                              
-                            
-          box.HORIZONTALS       
-    ───────────────────────────
-                              
-    ───────────────────────────
-                              
-    ───────────────────────────
-                              
-    ───────────────────────────
-            box.ROUNDED         
-    ╭────────────┬────────────╮
-    │                        │
-    ├────────────┼────────────┤
-    │                        │
-    ├────────────┼────────────┤
-    │                        │
-    ╰────────────┴────────────╯
-             box.HEAVY          
-    ┏━━━━━━━━━━━━┳━━━━━━━━━━━━┓
-    ┃                        ┃
-    ┣━━━━━━━━━━━━╋━━━━━━━━━━━━┫
-    ┃                        ┃
-    ┣━━━━━━━━━━━━╋━━━━━━━━━━━━┫
-    ┃                        ┃
-    ┗━━━━━━━━━━━━┻━━━━━━━━━━━━┛
-           box.HEAVY_EDGE       
-    ┏━━━━━━━━━━━━┯━━━━━━━━━━━━┓
-    ┃                        ┃
-    ┠────────────┼────────────┨
-    ┃                        ┃
-    ┠────────────┼────────────┨
-    ┃                        ┃
-    ┗━━━━━━━━━━━━┷━━━━━━━━━━━━┛
-           box.HEAVY_HEAD       
-    ┏━━━━━━━━━━━━┳━━━━━━━━━━━━┓
-    ┃                        ┃
-    ┡━━━━━━━━━━━━╇━━━━━━━━━━━━┩
-    │                        │
-    ├────────────┼────────────┤
-    │                        │
-    └────────────┴────────────┘
-             box.DOUBLE         
-    ╔════════════╦════════════╗
-    ║                        ║
-    ╠════════════╬════════════╣
-    ║                        ║
-    ╠════════════╬════════════╣
-    ║                        ║
-    ╚════════════╩════════════╝
-          box.DOUBLE_EDGE       
-    ╔════════════╤════════════╗
-    ║                        ║
-    ╟────────────┼────────────╢
-    ║                        ║
-    ╟────────────┼────────────╢
-    ║                        ║
-    ╚════════════╧════════════╝
+    
╭────────────────────────────────────────────────────────────────────────────────────────────────╮
+                                             Box Constants                                          │
+    ╰────────────────────────────────────────────────────────────────────────────────────────────────╯
+
+           box.ASCII               box.SQUARE               box.MINIMAL        box.MINIMAL_HEAVY_HEAD 
+    +---------------------+  ┌──────────┬──────────┐                                                  
+    | Header 1 | Header 2 |  │ Header 1  Header 2  Header 1  Header 2      Header 1  Header 2  
+    |----------+----------|  ├──────────┼──────────┤   ──────────┼──────────    ━━━━━━━━━━┿━━━━━━━━━━ 
+    | Cell     | Cell     |  │ Cell      Cell      Cell      Cell          Cell      Cell      
+    | Cell     | Cell     |  │ Cell      Cell      Cell      Cell          Cell      Cell      
+    |----------+----------|  ├──────────┼──────────┤   ──────────┼──────────    ──────────┼────────── 
+    | Footer 1 | Footer 2 |  │ Footer 1  Footer 2  Footer 1  Footer 2      Footer 1  Footer 2  
+    +---------------------+  └──────────┴──────────┘                                                  
+                                                                                                  
+                                                                                                  
+    box.MINIMAL_DOUBLE_HEAD        box.SIMPLE            box.SIMPLE_HEAVY          box.HORIZONTALS    
+                                                                              ───────────────────────
+     Header 1  Header 2      Header 1   Header 2      Header 1   Header 2      Header 1   Header 2  
+    ══════════╪══════════   ───────────────────────  ╺━━━━━━━━━━━━━━━━━━━━━╸  ───────────────────────
+     Cell      Cell          Cell       Cell          Cell       Cell          Cell       Cell      
+     Cell      Cell          Cell       Cell          Cell       Cell          Cell       Cell      
+    ──────────┼──────────   ───────────────────────  ╺━━━━━━━━━━━━━━━━━━━━━╸  ───────────────────────
+     Footer 1  Footer 2      Footer 1   Footer 2      Footer 1   Footer 2      Footer 1   Footer 2  
+                                                                              ───────────────────────
+                                                                                                    
+                                                                                                  
+          box.ROUNDED               box.HEAVY             box.HEAVY_EDGE           box.HEAVY_HEAD     
+    ╭──────────┬──────────╮  ┏━━━━━━━━━━┳━━━━━━━━━━┓  ┏━━━━━━━━━━┯━━━━━━━━━━┓  ┏━━━━━━━━━━┳━━━━━━━━━━┓
+    │ Header 1  Header 2 │  ┃ Header 1  Header 2 ┃  ┃ Header 1  Header 2 ┃  ┃ Header 1  Header 2 ┃
+    ├──────────┼──────────┤  ┣━━━━━━━━━━╋━━━━━━━━━━┫  ┠──────────┼──────────┨  ┡━━━━━━━━━━╇━━━━━━━━━━┩
+    │ Cell      Cell     │  ┃ Cell      Cell     ┃  ┃ Cell      Cell     ┃  │ Cell      Cell     │
+    │ Cell      Cell     │  ┃ Cell      Cell     ┃  ┃ Cell      Cell     ┃  │ Cell      Cell     │
+    ├──────────┼──────────┤  ┣━━━━━━━━━━╋━━━━━━━━━━┫  ┠──────────┼──────────┨  ├──────────┼──────────┤
+    │ Footer 1  Footer 2 │  ┃ Footer 1  Footer 2 ┃  ┃ Footer 1  Footer 2 ┃  │ Footer 1  Footer 2 │
+    ╰──────────┴──────────╯  ┗━━━━━━━━━━┻━━━━━━━━━━┛  ┗━━━━━━━━━━┷━━━━━━━━━━┛  └──────────┴──────────┘
+                                                                                                    
+                                                                                                    
+          box.DOUBLE             box.DOUBLE_EDGE                                                      
+    ╔══════════╦══════════╗  ╔══════════╤══════════╗                                                  
+    ║ Header 1  Header 2 ║  ║ Header 1  Header 2 ║                                                  
+    ╠══════════╬══════════╣  ╟──────────┼──────────╢                                                  
+    ║ Cell      Cell     ║  ║ Cell      Cell     ║                                                  
+    ║ Cell      Cell     ║  ║ Cell      Cell     ║                                                  
+    ╠══════════╬══════════╣  ╟──────────┼──────────╢                                                  
+    ║ Footer 1  Footer 2 ║  ║ Footer 1  Footer 2 ║                                                  
+    ╚══════════╩══════════╝  ╚══════════╧══════════╝                                                  
     
\ No newline at end of file diff --git a/rich/box.py b/rich/box.py index f100d8b1..a7b14b54 100644 --- a/rich/box.py +++ b/rich/box.py @@ -348,9 +348,20 @@ DOUBLE_EDGE: Box = Box( """ ) +LEGACY_WINDOWS_SUBSTITUTIONS = { + ROUNDED: SQUARE, + MINIMAL_HEAVY_HEAD: MINIMAL, + SIMPLE_HEAVY: SIMPLE, + HEAVY: SQUARE, + HEAVY_EDGE: SQUARE, + HEAVY_HEAD: SQUARE, +} + if __name__ == "__main__": # pragma: no cover + from rich.columns import Columns + from rich.panel import Panel from .console import Console from .table import Table from .text import Text @@ -358,12 +369,6 @@ if __name__ == "__main__": # pragma: no cover console = Console(record=True) - table = Table(width=80, show_footer=True, style="dim", border_style="not dim") - spaces = " " * 10 - table.add_column(spaces, spaces) - table.add_column(spaces, spaces) - table.add_row(spaces, spaces) - BOXES = [ "ASCII", "SQUARE", @@ -381,9 +386,21 @@ if __name__ == "__main__": # pragma: no cover "DOUBLE_EDGE", ] + console.print(Panel("[bold green]Box Constants", style="green"), justify="center") + console.print() + + columns = Columns(expand=False, padding=2) for box_name in BOXES: + table = Table(width=80, show_footer=True, style="dim", border_style="not dim") + spaces = " " * 10 + 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") - console.print(table) + columns.add_renderable(table) + console.print(columns) + + # console.save_html("box.html", inline_styles=True) - console.save_html("box.html", inline_styles=True) diff --git a/rich/columns.py b/rich/columns.py index 6d530c08..be05c090 100644 --- a/rich/columns.py +++ b/rich/columns.py @@ -15,7 +15,7 @@ class Columns(JupyterMixin): """Display renderables in neat columns. Args: - renderables (Iterable[RenderableType]): Any number of Rich renderables (including str), + renderables (Iterable[RenderableType]): Any number of Rich renderables (including str). width (int, optional): The desired width of the columns, or None to auto detect. Defaults to None. padding (PaddingDimensions, optional): Optional padding around cells. Defaults to (0, 1). expand (bool, optional): Expand columns to full width. Defaults to False. @@ -26,7 +26,7 @@ class Columns(JupyterMixin): def __init__( self, - renderables: Iterable[RenderableType], + renderables: Iterable[RenderableType] = None, padding: PaddingDimensions = (0, 1), width: int = None, expand: bool = False, @@ -34,7 +34,7 @@ class Columns(JupyterMixin): column_first: bool = False, right_to_left: bool = False, ) -> None: - self.renderables = list(renderables) + self.renderables = list(renderables or []) self.width = width self.padding = padding self.expand = expand @@ -42,6 +42,14 @@ class Columns(JupyterMixin): self.column_first = column_first self.right_to_left = right_to_left + def add_renderable(self, renderable: RenderableType) -> None: + """Add a renderable to the columns. + + Args: + renderable (RenderableType): Any renderable object. + """ + self.renderables.append(renderable) + def __rich_console__( self, console: Console, options: ConsoleOptions ) -> RenderResult: diff --git a/rich/table.py b/rich/table.py index 6204e0a7..6d28f828 100644 --- a/rich/table.py +++ b/rich/table.py @@ -112,6 +112,7 @@ class Table(JupyterMixin): border_style (Union[str, Style], optional): Style of the border. Defaults to None. title_style (Union[str, Style], optional): Style of the title. Defaults to None. caption_style (Union[str, Style], optional): Style of the caption. Defaults to None. + safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True. """ columns: List[Column] @@ -138,6 +139,7 @@ class Table(JupyterMixin): border_style: StyleType = None, title_style: StyleType = None, caption_style: StyleType = None, + safe_box: bool = True, ) -> None: self.columns = [ @@ -162,6 +164,7 @@ class Table(JupyterMixin): self.border_style = border_style self.title_style = title_style self.caption_style = title_style + self.safe_box = safe_box self._row_count = 0 self.row_styles = list(row_styles or []) @@ -481,11 +484,11 @@ class Table(JupyterMixin): for first, last, (style, renderable) in loop_first_last(raw_cells): yield _Cell(style, add_padding(renderable, first, last)) - def _get_padding_width(self, column_index) -> int: + def _get_padding_width(self, column_index: int) -> int: """Get extra width from padding.""" _, pad_right, _, pad_left = self.padding if self.collapse_padding: - if column_index != 0: + if column_index > 0: pad_left = max(0, pad_right - pad_left) return pad_left + pad_right @@ -537,6 +540,9 @@ class Table(JupyterMixin): if isinstance(self.box, box.PlatformDefaultBox) else self.box ) + if self.safe_box and _box is not None and console.legacy_windows: + _box = box.LEGACY_WINDOWS_SUBSTITUTIONS.get(_box, _box) + # _box = self.box new_line = Segment.line() diff --git a/tests/test_columns.py b/tests/test_columns.py index b418aa4d..b07af7cb 100644 --- a/tests/test_columns.py +++ b/tests/test_columns.py @@ -25,7 +25,6 @@ COLUMN_DATA = [ "Anteater, australian spiny", "Tachyglossus aculeatus", "Anteater, giant", - "Myrmecophaga tridactyla", ] @@ -36,6 +35,7 @@ def render(): empty_columns = Columns([]) console.print(empty_columns) columns = Columns(COLUMN_DATA) + columns.add_renderable("Myrmecophaga tridactyla") console.rule("optimal") console.print(columns) console.rule("optimal, expand")