mirror of
https://github.com/Textualize/rich.git
synced 2025-08-04 18:18:22 +00:00
background style, table width calculation
This commit is contained in:
parent
c98bf070e4
commit
05ce5105b4
14 changed files with 68 additions and 49 deletions
|
@ -16,15 +16,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Support for Python 3.9
|
||||
- Added legacy_windows to ConsoleOptions
|
||||
- Added ascii_only to ConsoleOptions
|
||||
- Addded box.SQUARE_DOUBLE_HEAD
|
||||
- Added box.SQUARE_DOUBLE_HEAD
|
||||
- Added highlighting of EUI-48 and EUI-64 (MAC addresses)
|
||||
- Added Console.pager
|
||||
- Added Console.out
|
||||
- Added Progress.reset
|
||||
- Added Style.background_style property
|
||||
|
||||
### Changed
|
||||
|
||||
- Dropped box.get_safe_box function in favor of Box.substitute
|
||||
- Changed default padding in Panel from 0 to (0, 1) https://github.com/willmcgugan/rich/issues/385
|
||||
- Table with row_styles will extend background color between cells if the box has no vertical dividerhttps://github.com/willmcgugan/rich/issues/383
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ class Box:
|
|||
box = self
|
||||
if options.legacy_windows and safe:
|
||||
box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box)
|
||||
if options.ascii_only:
|
||||
if options.ascii_only and not box.ascii:
|
||||
box = ASCII
|
||||
return box
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ class Panel(JupyterMixin):
|
|||
style: StyleType = "none",
|
||||
border_style: StyleType = "none",
|
||||
width: Optional[int] = None,
|
||||
padding: PaddingDimensions = 0,
|
||||
padding: PaddingDimensions = (0, 1),
|
||||
) -> None:
|
||||
self.renderable = renderable
|
||||
self.box = box
|
||||
|
@ -70,7 +70,7 @@ class Panel(JupyterMixin):
|
|||
style: StyleType = "none",
|
||||
border_style: StyleType = "none",
|
||||
width: Optional[int] = None,
|
||||
padding: PaddingDimensions = 0,
|
||||
padding: PaddingDimensions = (0, 1),
|
||||
):
|
||||
"""An alternative constructor that sets expand=False."""
|
||||
return cls(
|
||||
|
|
|
@ -349,6 +349,11 @@ class Style:
|
|||
"""Check if the style specified a transparent background."""
|
||||
return self.bgcolor is None or self.bgcolor.is_default
|
||||
|
||||
@property
|
||||
def background_style(self) -> "Style":
|
||||
"""A Style with background only."""
|
||||
return Style(bgcolor=self.bgcolor)
|
||||
|
||||
@classmethod
|
||||
@lru_cache(maxsize=1024)
|
||||
def parse(cls, style_definition: str) -> "Style":
|
||||
|
|
|
@ -300,7 +300,7 @@ class Table(JupyterMixin):
|
|||
footer_style (Union[str, Style], optional): Style for the header. Defaults to "none".
|
||||
style (Union[str, Style], optional): Style for the column cells. Defaults to "none".
|
||||
justify (JustifyMethod, optional): Alignment for cells. Defaults to "left".
|
||||
width (int, optional): A minimum width in characters. Defaults to None.
|
||||
width (int, optional): Desired width of column in characters, or None to fit to contents. Defaults to None.
|
||||
ratio (int, optional): Flexible ratio for the column (requires ``Table.expand`` or ``Table.width``). Defaults to None.
|
||||
no_wrap (bool, optional): Set to ``True`` to disable wrapping of this column.
|
||||
"""
|
||||
|
@ -376,12 +376,10 @@ class Table(JupyterMixin):
|
|||
max_width = options.max_width
|
||||
if self.width is not None:
|
||||
max_width = self.width
|
||||
if self.box:
|
||||
max_width -= len(self.columns) - 1
|
||||
if self.show_edge:
|
||||
max_width -= 2
|
||||
widths = self._calculate_column_widths(console, max_width)
|
||||
table_width = sum(widths) + self._extra_width
|
||||
|
||||
extra_width = self._extra_width
|
||||
widths = self._calculate_column_widths(console, max_width - extra_width)
|
||||
table_width = sum(widths) + extra_width
|
||||
|
||||
render_options = options.update(width=table_width)
|
||||
|
||||
|
@ -437,10 +435,11 @@ class Table(JupyterMixin):
|
|||
if column.flexible:
|
||||
widths[index] = fixed_widths[index] + next(iter_flex_widths)
|
||||
table_width = sum(widths)
|
||||
|
||||
if table_width > max_width:
|
||||
widths = self._collapse_widths(
|
||||
widths, [not column.no_wrap for column in columns], max_width
|
||||
widths,
|
||||
[(column.width is None and not column.no_wrap) for column in columns],
|
||||
max_width,
|
||||
)
|
||||
table_width = sum(widths)
|
||||
|
||||
|
@ -570,7 +569,7 @@ class Table(JupyterMixin):
|
|||
# Fixed width column
|
||||
return Measurement(
|
||||
column.width + padding_width, column.width + padding_width
|
||||
)
|
||||
).with_maximum(max_width)
|
||||
# Flexible column, we need to measure contents
|
||||
min_widths: List[int] = []
|
||||
max_widths: List[int] = []
|
||||
|
@ -582,10 +581,11 @@ class Table(JupyterMixin):
|
|||
append_min(_min)
|
||||
append_max(_max)
|
||||
|
||||
return Measurement(
|
||||
measurement = Measurement(
|
||||
max(min_widths) if min_widths else 1,
|
||||
max(max_widths) if max_widths else max_width,
|
||||
)
|
||||
).with_maximum(max_width)
|
||||
return measurement
|
||||
|
||||
def _render(
|
||||
self, console: "Console", options: "ConsoleOptions", widths: List[int]
|
||||
|
@ -683,13 +683,16 @@ class Table(JupyterMixin):
|
|||
_box.get_row(widths, "foot", edge=show_edge), border_style
|
||||
)
|
||||
yield new_line
|
||||
if first:
|
||||
left, right, divider = box_segments[0]
|
||||
elif last:
|
||||
left, right, divider = box_segments[2]
|
||||
else:
|
||||
left, right, divider = box_segments[1]
|
||||
left, right, _divider = box_segments[0 if first else (2 if last else 1)]
|
||||
|
||||
# If the column divider is whitespace also style it with the row background
|
||||
divider = (
|
||||
_divider
|
||||
if _divider.text.strip()
|
||||
else _Segment(
|
||||
_divider.text, row_style.background_style + _divider.style
|
||||
)
|
||||
)
|
||||
for line_no in range(max_height):
|
||||
if show_edge:
|
||||
yield left
|
||||
|
@ -706,7 +709,7 @@ class Table(JupyterMixin):
|
|||
yield from rendered_cell[line_no]
|
||||
yield new_line
|
||||
if _box and first and show_header:
|
||||
yield Segment(
|
||||
yield _Segment(
|
||||
_box.get_row(widths, "head", edge=show_edge), border_style
|
||||
)
|
||||
yield new_line
|
||||
|
@ -735,24 +738,24 @@ class Table(JupyterMixin):
|
|||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
from .console import Console
|
||||
from . import box
|
||||
|
||||
c = Console()
|
||||
table = Table(
|
||||
show_lines=False,
|
||||
row_styles=["red", "green"],
|
||||
row_styles=["on blue", "on red"],
|
||||
expand=False,
|
||||
show_header=True,
|
||||
show_footer=False,
|
||||
show_edge=True,
|
||||
box=box.SIMPLE,
|
||||
)
|
||||
table.add_column("foo", no_wrap=True, footer="BAR")
|
||||
table.add_column("bar")
|
||||
table.add_column("baz")
|
||||
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
|
||||
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
|
||||
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
|
||||
table.add_row("Magnet", "foo" * 20, "bar" * 10, "egg" * 15)
|
||||
|
||||
for width in range(170, 1, -1):
|
||||
print(" " * width + "<|")
|
||||
c = Console(width=width)
|
||||
c.print(table)
|
||||
|
||||
c.print("Some more words", width=4, overflow="ellipsis")
|
||||
c.print(table)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@ from rich.panel import Panel
|
|||
|
||||
def render():
|
||||
console = Console(file=io.StringIO(), width=100, legacy_windows=False)
|
||||
panel = Panel.fit("foo", box=box.SQUARE)
|
||||
panel = Panel.fit("foo", box=box.SQUARE, padding=0)
|
||||
columns = Columns([panel] * 4)
|
||||
columns.expand = True
|
||||
console.rule("no align")
|
||||
|
|
|
@ -232,7 +232,7 @@ def test_justify_renderable_none():
|
|||
console = Console(
|
||||
file=io.StringIO(), force_terminal=True, width=20, legacy_windows=False
|
||||
)
|
||||
console.print(Panel("FOO", expand=False), justify=None)
|
||||
console.print(Panel("FOO", expand=False, padding=0), justify=None)
|
||||
assert console.file.getvalue() == "╭───╮\n│FOO│\n╰───╯\n"
|
||||
|
||||
|
||||
|
@ -240,7 +240,7 @@ def test_justify_renderable_left():
|
|||
console = Console(
|
||||
file=io.StringIO(), force_terminal=True, width=10, legacy_windows=False
|
||||
)
|
||||
console.print(Panel("FOO", expand=False), justify="left")
|
||||
console.print(Panel("FOO", expand=False, padding=0), justify="left")
|
||||
assert console.file.getvalue() == "╭───╮ \n│FOO│ \n╰───╯ \n"
|
||||
|
||||
|
||||
|
@ -248,7 +248,7 @@ def test_justify_renderable_center():
|
|||
console = Console(
|
||||
file=io.StringIO(), force_terminal=True, width=10, legacy_windows=False
|
||||
)
|
||||
console.print(Panel("FOO", expand=False), justify="center")
|
||||
console.print(Panel("FOO", expand=False, padding=0), justify="center")
|
||||
assert console.file.getvalue() == " ╭───╮ \n │FOO│ \n ╰───╯ \n"
|
||||
|
||||
|
||||
|
@ -256,7 +256,7 @@ def test_justify_renderable_right():
|
|||
console = Console(
|
||||
file=io.StringIO(), force_terminal=True, width=20, legacy_windows=False
|
||||
)
|
||||
console.print(Panel("FOO", expand=False), justify="right")
|
||||
console.print(Panel("FOO", expand=False, padding=0), justify="right")
|
||||
assert (
|
||||
console.file.getvalue()
|
||||
== " ╭───╮\n │FOO│\n ╰───╯\n"
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,12 +5,12 @@ from rich.panel import Panel
|
|||
import pytest
|
||||
|
||||
tests = [
|
||||
Panel("Hello, World"),
|
||||
Panel("Hello, World", expand=False),
|
||||
Panel.fit("Hello, World"),
|
||||
Panel("Hello, World", width=8),
|
||||
Panel(Panel("Hello, World")),
|
||||
Panel("Hello, World", title="FOO"),
|
||||
Panel("Hello, World", padding=0),
|
||||
Panel("Hello, World", expand=False, padding=0),
|
||||
Panel.fit("Hello, World", padding=0),
|
||||
Panel("Hello, World", width=8, padding=0),
|
||||
Panel(Panel("Hello, World", padding=0), padding=0),
|
||||
Panel("Hello, World", title="FOO", padding=0),
|
||||
]
|
||||
|
||||
expected = [
|
||||
|
@ -38,8 +38,8 @@ def test_console_width():
|
|||
console = Console(file=io.StringIO(), width=50, legacy_windows=False)
|
||||
panel = Panel("Hello, World", expand=False)
|
||||
min_width, max_width = panel.__rich_measure__(console, 50)
|
||||
assert min_width == 14
|
||||
assert max_width == 14
|
||||
assert min_width == 16
|
||||
assert max_width == 16
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -20,5 +20,5 @@ def test_rich_cast():
|
|||
def test_rich_cast_container():
|
||||
foo = Foo()
|
||||
console = Console(file=io.StringIO(), legacy_windows=False)
|
||||
console.print(Panel.fit(foo))
|
||||
console.print(Panel.fit(foo, padding=0))
|
||||
assert console.file.getvalue() == "╭───╮\n│Foo│\n╰───╯\n"
|
||||
|
|
|
@ -190,3 +190,9 @@ def test_style_stack():
|
|||
def test_pick_first():
|
||||
with pytest.raises(ValueError):
|
||||
Style.pick_first()
|
||||
|
||||
|
||||
def test_background_style():
|
||||
assert Style(bold=True, color="yellow", bgcolor="red").background_style == Style(
|
||||
bgcolor="red"
|
||||
)
|
||||
|
|
|
@ -45,7 +45,8 @@ def test_python_render():
|
|||
theme="foo",
|
||||
code_width=60,
|
||||
word_wrap=True,
|
||||
)
|
||||
),
|
||||
padding=0,
|
||||
)
|
||||
rendered_syntax = render(syntax)
|
||||
print(repr(rendered_syntax))
|
||||
|
@ -192,7 +193,8 @@ if __name__ == "__main__":
|
|||
theme="foo",
|
||||
code_width=60,
|
||||
word_wrap=True,
|
||||
)
|
||||
),
|
||||
padding=0,
|
||||
)
|
||||
rendered = render(markdown)
|
||||
print(rendered)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue