Optimized style rendering

This commit is contained in:
Will McGugan 2020-03-11 00:14:16 +00:00
parent 7674ebae51
commit 8d266a7a5e
7 changed files with 543 additions and 45 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added width option to Panel
- Change special method `__render_width__` to `__measure__`
- Dropped the "markdown style" syntax in console markup
- Optimized style rendering
### Added

18
rich/_make_style_table.py Normal file
View File

@ -0,0 +1,18 @@
"""Generate a ANSI style table."""
def make_table():
table = []
for attributes in range(0, 512):
ansi_codes = []
for bit_no in range(0, 9):
bit = 1 << bit_no
if attributes & bit:
ansi_codes.append(str(1 + bit_no))
table.append(";".join(ansi_codes))
return table
table = make_table()
print(repr(table))

517
rich/_style_table.py Normal file
View File

@ -0,0 +1,517 @@
# Generated by _make_style_table
# Maps a bit-field of attributes on to ANSI codes
STYLE_TABLE = [
"",
"1",
"2",
"1;2",
"3",
"1;3",
"2;3",
"1;2;3",
"4",
"1;4",
"2;4",
"1;2;4",
"3;4",
"1;3;4",
"2;3;4",
"1;2;3;4",
"5",
"1;5",
"2;5",
"1;2;5",
"3;5",
"1;3;5",
"2;3;5",
"1;2;3;5",
"4;5",
"1;4;5",
"2;4;5",
"1;2;4;5",
"3;4;5",
"1;3;4;5",
"2;3;4;5",
"1;2;3;4;5",
"6",
"1;6",
"2;6",
"1;2;6",
"3;6",
"1;3;6",
"2;3;6",
"1;2;3;6",
"4;6",
"1;4;6",
"2;4;6",
"1;2;4;6",
"3;4;6",
"1;3;4;6",
"2;3;4;6",
"1;2;3;4;6",
"5;6",
"1;5;6",
"2;5;6",
"1;2;5;6",
"3;5;6",
"1;3;5;6",
"2;3;5;6",
"1;2;3;5;6",
"4;5;6",
"1;4;5;6",
"2;4;5;6",
"1;2;4;5;6",
"3;4;5;6",
"1;3;4;5;6",
"2;3;4;5;6",
"1;2;3;4;5;6",
"7",
"1;7",
"2;7",
"1;2;7",
"3;7",
"1;3;7",
"2;3;7",
"1;2;3;7",
"4;7",
"1;4;7",
"2;4;7",
"1;2;4;7",
"3;4;7",
"1;3;4;7",
"2;3;4;7",
"1;2;3;4;7",
"5;7",
"1;5;7",
"2;5;7",
"1;2;5;7",
"3;5;7",
"1;3;5;7",
"2;3;5;7",
"1;2;3;5;7",
"4;5;7",
"1;4;5;7",
"2;4;5;7",
"1;2;4;5;7",
"3;4;5;7",
"1;3;4;5;7",
"2;3;4;5;7",
"1;2;3;4;5;7",
"6;7",
"1;6;7",
"2;6;7",
"1;2;6;7",
"3;6;7",
"1;3;6;7",
"2;3;6;7",
"1;2;3;6;7",
"4;6;7",
"1;4;6;7",
"2;4;6;7",
"1;2;4;6;7",
"3;4;6;7",
"1;3;4;6;7",
"2;3;4;6;7",
"1;2;3;4;6;7",
"5;6;7",
"1;5;6;7",
"2;5;6;7",
"1;2;5;6;7",
"3;5;6;7",
"1;3;5;6;7",
"2;3;5;6;7",
"1;2;3;5;6;7",
"4;5;6;7",
"1;4;5;6;7",
"2;4;5;6;7",
"1;2;4;5;6;7",
"3;4;5;6;7",
"1;3;4;5;6;7",
"2;3;4;5;6;7",
"1;2;3;4;5;6;7",
"8",
"1;8",
"2;8",
"1;2;8",
"3;8",
"1;3;8",
"2;3;8",
"1;2;3;8",
"4;8",
"1;4;8",
"2;4;8",
"1;2;4;8",
"3;4;8",
"1;3;4;8",
"2;3;4;8",
"1;2;3;4;8",
"5;8",
"1;5;8",
"2;5;8",
"1;2;5;8",
"3;5;8",
"1;3;5;8",
"2;3;5;8",
"1;2;3;5;8",
"4;5;8",
"1;4;5;8",
"2;4;5;8",
"1;2;4;5;8",
"3;4;5;8",
"1;3;4;5;8",
"2;3;4;5;8",
"1;2;3;4;5;8",
"6;8",
"1;6;8",
"2;6;8",
"1;2;6;8",
"3;6;8",
"1;3;6;8",
"2;3;6;8",
"1;2;3;6;8",
"4;6;8",
"1;4;6;8",
"2;4;6;8",
"1;2;4;6;8",
"3;4;6;8",
"1;3;4;6;8",
"2;3;4;6;8",
"1;2;3;4;6;8",
"5;6;8",
"1;5;6;8",
"2;5;6;8",
"1;2;5;6;8",
"3;5;6;8",
"1;3;5;6;8",
"2;3;5;6;8",
"1;2;3;5;6;8",
"4;5;6;8",
"1;4;5;6;8",
"2;4;5;6;8",
"1;2;4;5;6;8",
"3;4;5;6;8",
"1;3;4;5;6;8",
"2;3;4;5;6;8",
"1;2;3;4;5;6;8",
"7;8",
"1;7;8",
"2;7;8",
"1;2;7;8",
"3;7;8",
"1;3;7;8",
"2;3;7;8",
"1;2;3;7;8",
"4;7;8",
"1;4;7;8",
"2;4;7;8",
"1;2;4;7;8",
"3;4;7;8",
"1;3;4;7;8",
"2;3;4;7;8",
"1;2;3;4;7;8",
"5;7;8",
"1;5;7;8",
"2;5;7;8",
"1;2;5;7;8",
"3;5;7;8",
"1;3;5;7;8",
"2;3;5;7;8",
"1;2;3;5;7;8",
"4;5;7;8",
"1;4;5;7;8",
"2;4;5;7;8",
"1;2;4;5;7;8",
"3;4;5;7;8",
"1;3;4;5;7;8",
"2;3;4;5;7;8",
"1;2;3;4;5;7;8",
"6;7;8",
"1;6;7;8",
"2;6;7;8",
"1;2;6;7;8",
"3;6;7;8",
"1;3;6;7;8",
"2;3;6;7;8",
"1;2;3;6;7;8",
"4;6;7;8",
"1;4;6;7;8",
"2;4;6;7;8",
"1;2;4;6;7;8",
"3;4;6;7;8",
"1;3;4;6;7;8",
"2;3;4;6;7;8",
"1;2;3;4;6;7;8",
"5;6;7;8",
"1;5;6;7;8",
"2;5;6;7;8",
"1;2;5;6;7;8",
"3;5;6;7;8",
"1;3;5;6;7;8",
"2;3;5;6;7;8",
"1;2;3;5;6;7;8",
"4;5;6;7;8",
"1;4;5;6;7;8",
"2;4;5;6;7;8",
"1;2;4;5;6;7;8",
"3;4;5;6;7;8",
"1;3;4;5;6;7;8",
"2;3;4;5;6;7;8",
"1;2;3;4;5;6;7;8",
"9",
"1;9",
"2;9",
"1;2;9",
"3;9",
"1;3;9",
"2;3;9",
"1;2;3;9",
"4;9",
"1;4;9",
"2;4;9",
"1;2;4;9",
"3;4;9",
"1;3;4;9",
"2;3;4;9",
"1;2;3;4;9",
"5;9",
"1;5;9",
"2;5;9",
"1;2;5;9",
"3;5;9",
"1;3;5;9",
"2;3;5;9",
"1;2;3;5;9",
"4;5;9",
"1;4;5;9",
"2;4;5;9",
"1;2;4;5;9",
"3;4;5;9",
"1;3;4;5;9",
"2;3;4;5;9",
"1;2;3;4;5;9",
"6;9",
"1;6;9",
"2;6;9",
"1;2;6;9",
"3;6;9",
"1;3;6;9",
"2;3;6;9",
"1;2;3;6;9",
"4;6;9",
"1;4;6;9",
"2;4;6;9",
"1;2;4;6;9",
"3;4;6;9",
"1;3;4;6;9",
"2;3;4;6;9",
"1;2;3;4;6;9",
"5;6;9",
"1;5;6;9",
"2;5;6;9",
"1;2;5;6;9",
"3;5;6;9",
"1;3;5;6;9",
"2;3;5;6;9",
"1;2;3;5;6;9",
"4;5;6;9",
"1;4;5;6;9",
"2;4;5;6;9",
"1;2;4;5;6;9",
"3;4;5;6;9",
"1;3;4;5;6;9",
"2;3;4;5;6;9",
"1;2;3;4;5;6;9",
"7;9",
"1;7;9",
"2;7;9",
"1;2;7;9",
"3;7;9",
"1;3;7;9",
"2;3;7;9",
"1;2;3;7;9",
"4;7;9",
"1;4;7;9",
"2;4;7;9",
"1;2;4;7;9",
"3;4;7;9",
"1;3;4;7;9",
"2;3;4;7;9",
"1;2;3;4;7;9",
"5;7;9",
"1;5;7;9",
"2;5;7;9",
"1;2;5;7;9",
"3;5;7;9",
"1;3;5;7;9",
"2;3;5;7;9",
"1;2;3;5;7;9",
"4;5;7;9",
"1;4;5;7;9",
"2;4;5;7;9",
"1;2;4;5;7;9",
"3;4;5;7;9",
"1;3;4;5;7;9",
"2;3;4;5;7;9",
"1;2;3;4;5;7;9",
"6;7;9",
"1;6;7;9",
"2;6;7;9",
"1;2;6;7;9",
"3;6;7;9",
"1;3;6;7;9",
"2;3;6;7;9",
"1;2;3;6;7;9",
"4;6;7;9",
"1;4;6;7;9",
"2;4;6;7;9",
"1;2;4;6;7;9",
"3;4;6;7;9",
"1;3;4;6;7;9",
"2;3;4;6;7;9",
"1;2;3;4;6;7;9",
"5;6;7;9",
"1;5;6;7;9",
"2;5;6;7;9",
"1;2;5;6;7;9",
"3;5;6;7;9",
"1;3;5;6;7;9",
"2;3;5;6;7;9",
"1;2;3;5;6;7;9",
"4;5;6;7;9",
"1;4;5;6;7;9",
"2;4;5;6;7;9",
"1;2;4;5;6;7;9",
"3;4;5;6;7;9",
"1;3;4;5;6;7;9",
"2;3;4;5;6;7;9",
"1;2;3;4;5;6;7;9",
"8;9",
"1;8;9",
"2;8;9",
"1;2;8;9",
"3;8;9",
"1;3;8;9",
"2;3;8;9",
"1;2;3;8;9",
"4;8;9",
"1;4;8;9",
"2;4;8;9",
"1;2;4;8;9",
"3;4;8;9",
"1;3;4;8;9",
"2;3;4;8;9",
"1;2;3;4;8;9",
"5;8;9",
"1;5;8;9",
"2;5;8;9",
"1;2;5;8;9",
"3;5;8;9",
"1;3;5;8;9",
"2;3;5;8;9",
"1;2;3;5;8;9",
"4;5;8;9",
"1;4;5;8;9",
"2;4;5;8;9",
"1;2;4;5;8;9",
"3;4;5;8;9",
"1;3;4;5;8;9",
"2;3;4;5;8;9",
"1;2;3;4;5;8;9",
"6;8;9",
"1;6;8;9",
"2;6;8;9",
"1;2;6;8;9",
"3;6;8;9",
"1;3;6;8;9",
"2;3;6;8;9",
"1;2;3;6;8;9",
"4;6;8;9",
"1;4;6;8;9",
"2;4;6;8;9",
"1;2;4;6;8;9",
"3;4;6;8;9",
"1;3;4;6;8;9",
"2;3;4;6;8;9",
"1;2;3;4;6;8;9",
"5;6;8;9",
"1;5;6;8;9",
"2;5;6;8;9",
"1;2;5;6;8;9",
"3;5;6;8;9",
"1;3;5;6;8;9",
"2;3;5;6;8;9",
"1;2;3;5;6;8;9",
"4;5;6;8;9",
"1;4;5;6;8;9",
"2;4;5;6;8;9",
"1;2;4;5;6;8;9",
"3;4;5;6;8;9",
"1;3;4;5;6;8;9",
"2;3;4;5;6;8;9",
"1;2;3;4;5;6;8;9",
"7;8;9",
"1;7;8;9",
"2;7;8;9",
"1;2;7;8;9",
"3;7;8;9",
"1;3;7;8;9",
"2;3;7;8;9",
"1;2;3;7;8;9",
"4;7;8;9",
"1;4;7;8;9",
"2;4;7;8;9",
"1;2;4;7;8;9",
"3;4;7;8;9",
"1;3;4;7;8;9",
"2;3;4;7;8;9",
"1;2;3;4;7;8;9",
"5;7;8;9",
"1;5;7;8;9",
"2;5;7;8;9",
"1;2;5;7;8;9",
"3;5;7;8;9",
"1;3;5;7;8;9",
"2;3;5;7;8;9",
"1;2;3;5;7;8;9",
"4;5;7;8;9",
"1;4;5;7;8;9",
"2;4;5;7;8;9",
"1;2;4;5;7;8;9",
"3;4;5;7;8;9",
"1;3;4;5;7;8;9",
"2;3;4;5;7;8;9",
"1;2;3;4;5;7;8;9",
"6;7;8;9",
"1;6;7;8;9",
"2;6;7;8;9",
"1;2;6;7;8;9",
"3;6;7;8;9",
"1;3;6;7;8;9",
"2;3;6;7;8;9",
"1;2;3;6;7;8;9",
"4;6;7;8;9",
"1;4;6;7;8;9",
"2;4;6;7;8;9",
"1;2;4;6;7;8;9",
"3;4;6;7;8;9",
"1;3;4;6;7;8;9",
"2;3;4;6;7;8;9",
"1;2;3;4;6;7;8;9",
"5;6;7;8;9",
"1;5;6;7;8;9",
"2;5;6;7;8;9",
"1;2;5;6;7;8;9",
"3;5;6;7;8;9",
"1;3;5;6;7;8;9",
"2;3;5;6;7;8;9",
"1;2;3;5;6;7;8;9",
"4;5;6;7;8;9",
"1;4;5;6;7;8;9",
"2;4;5;6;7;8;9",
"1;2;4;5;6;7;8;9",
"3;4;5;6;7;8;9",
"1;3;4;5;6;7;8;9",
"2;3;4;5;6;7;8;9",
"1;2;3;4;5;6;7;8;9",
]

View File

@ -476,27 +476,13 @@ An h2 header
import commonmark
# print(commonmark.commonmark(markup))
from .console import Console
console = Console(record=True)
# print(console.size)
# markup = "<foo>"
md = Markdown(markup)
from time import time
console.print(md)
print(console)
# print(console.render_spans())
# from .color import Color
# from .style import Style
# print(Color.downgrade.cache_info())
# print(Color.parse.cache_info())
# print(Color.get_ansi_codes.cache_info())
# Style.parse("on red")
# print(Style.parse.cache_info())

View File

@ -4,6 +4,7 @@ from typing import Any, Dict, Iterable, List, Mapping, Optional, Type, Union
from . import errors
from .color import blend_rgb, Color, ColorParseError, ColorSystem
from ._style_table import STYLE_TABLE
from .terminal_theme import TerminalTheme, DEFAULT_TERMINAL_THEME
# Style instances and style definitions are often interchangable
@ -340,40 +341,14 @@ class Style:
"""
if color_system is None or not text:
return text
attrs: List[str] = []
_attributes = self._attributes & self._set_attributes
attrs: List[str] = [STYLE_TABLE[_attributes]] if _attributes else []
if self._color is not None:
attrs.extend(self._color.downgrade(color_system).get_ansi_codes())
if self._bgcolor is not None:
attrs.extend(
self._bgcolor.downgrade(color_system).get_ansi_codes(foreground=False)
)
set_bits = self._set_attributes
if set_bits:
append = attrs.append
bits = self._attributes
if set_bits & 1:
append("1" if bits & 1 else "21")
if set_bits & 2:
append("2" if bits & 2 else "22")
if set_bits & 4:
append("3" if bits & 4 else "23")
if set_bits & 8:
append("4" if bits & 8 else "24")
# Early out for less common attributes
if set_bits & 0b111110000:
if set_bits & 16:
append("5" if bits & 16 else "25")
if set_bits & 32:
append("6" if bits & 32 else "26")
if set_bits & 64:
append("7" if bits & 64 else "27")
if set_bits & 128:
append("8" if bits & 128 else "28")
if set_bits & 256:
append("9" if bits & 256 else "29")
if attrs:
return f"\x1b[{';'.join(attrs)}m{text or ''}\x1b[0m"
else:

View File

@ -100,7 +100,7 @@ def test_render():
assert Style(color="red").render("foo", color_system=None) == "foo"
assert (
Style(color="red", bgcolor="black", bold=True).render("foo")
== "\x1b[31;40;1mfoo\x1b[0m"
== "\x1b[1;31;40mfoo\x1b[0m"
)
assert Style().render("foo") == "foo"

View File

@ -282,6 +282,7 @@ def test_render():
)
console.print(test)
output = console.export_text(styles=True)
print(repr(output))
expected = "\x1b[1;4mWhere\x1b[0m\x1b[4m there is \x1b[0m\n\x1b[4ma \x1b[0m\x1b[3;4mWill\x1b[0m\x1b[4m, there \x1b[0m\n\x1b[4mis a Way.\x1b[0m\n"
assert output == expected