From 6c0ba383addabbf0ed81b69f31e89af9b46cd86c Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Mon, 19 Feb 2024 16:36:23 +0000 Subject: [PATCH 01/14] Begin to map ansi colours --- src/textual/app.py | 27 ++++++++++++++++++++++++--- src/textual/filter.py | 26 ++++++++++++++++++++++---- src/textual/renderables/tint.py | 1 + 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index cc8f36633f..5f72f79ed8 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -57,6 +57,7 @@ from rich.control import Control from rich.protocol import is_renderable from rich.segment import Segment, Segments +from rich.terminal_theme import TerminalTheme from . import ( Logger, @@ -397,6 +398,12 @@ class MyApp(App[None]): get focus when the terminal widget has focus. """ + ansi_theme_dark = Reactive(terminal_theme.MONOKAI, init=False) + """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in dark mode.""" + + ansi_theme_light = Reactive(terminal_theme.MONOKAI, init=False) + """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in light mode.""" + def __init__( self, driver_class: Type[Driver] | None = None, @@ -421,9 +428,10 @@ def __init__( super().__init__() self.features: frozenset[FeatureFlag] = parse_features(os.getenv("TEXTUAL", "")) - self._filters: list[LineFilter] = [ - ANSIToTruecolor(terminal_theme.DIMMED_MONOKAI) - ] + ansi_theme = self.ansi_theme_dark if self.dark else self.ansi_theme_light + self._truecolor_filter = ANSIToTruecolor(ansi_theme) + self._filters: list[LineFilter] = [self._truecolor_filter] + environ = dict(os.environ) no_color = environ.pop("NO_COLOR", None) if no_color is not None: @@ -870,8 +878,21 @@ def watch_dark(self, dark: bool) -> None: """ self.set_class(dark, "-dark-mode", update=False) self.set_class(not dark, "-light-mode", update=False) + self._truecolor_filter.theme = ( + self.ansi_theme_dark if self.dark else self.ansi_theme_light + ) self.call_later(self.refresh_css) + def watch_ansi_theme_dark(self, theme: TerminalTheme) -> None: + if self.dark: + self._truecolor_filter.theme = theme + self.call_later(self.refresh_css) + + def watch_ansi_theme_light(self, theme: TerminalTheme) -> None: + if not self.dark: + self._truecolor_filter.theme = theme + self.call_later(self.refresh_css) + def get_driver_class(self) -> Type[Driver]: """Get a driver class for this platform. diff --git a/src/textual/filter.py b/src/textual/filter.py index 7494d9a52a..9b3639ee8f 100644 --- a/src/textual/filter.py +++ b/src/textual/filter.py @@ -21,6 +21,8 @@ from rich.style import Style from rich.terminal_theme import TerminalTheme +from textual.cache import LRUCache + from .color import Color @@ -188,9 +190,18 @@ def __init__(self, terminal_theme: TerminalTheme): Args: terminal_theme: A rich terminal theme. """ - self.terminal_theme = terminal_theme + self._terminal_theme = terminal_theme + self._truecolor_cache: LRUCache[Style, Style] = LRUCache(maxsize=1024) + + @property + def theme(self) -> TerminalTheme: + return self._terminal_theme + + @theme.setter + def theme(self, theme: TerminalTheme) -> None: + self._truecolor_cache.clear() + self._terminal_theme = theme - @lru_cache(1024) def truecolor_style(self, style: Style) -> Style: """Replace system colors with truecolor equivalent. @@ -200,7 +211,11 @@ def truecolor_style(self, style: Style) -> Style: Returns: New style. """ - terminal_theme = self.terminal_theme + cache = self._truecolor_cache + if style in cache: + return cache[style] + + terminal_theme = self._terminal_theme color = style.color if color is not None and color.is_system_defined: color = RichColor.from_rgb( @@ -211,7 +226,10 @@ def truecolor_style(self, style: Style) -> Style: bgcolor = RichColor.from_rgb( *bgcolor.get_truecolor(terminal_theme, foreground=False) ) - return style + Style.from_color(color, bgcolor) + + truecolor_style = style + Style.from_color(color, bgcolor) + cache[style] = truecolor_style + return truecolor_style def apply(self, segments: list[Segment], background: Color) -> list[Segment]: """Transform a list of segments. diff --git a/src/textual/renderables/tint.py b/src/textual/renderables/tint.py index 358bbca3fc..592d4ab14c 100644 --- a/src/textual/renderables/tint.py +++ b/src/textual/renderables/tint.py @@ -45,6 +45,7 @@ def process_segments( style_from_color = Style.from_color _Segment = Segment + # TODO - needs to be updated to use the correct terminal theme truecolor_style = ANSIToTruecolor(terminal_theme.DIMMED_MONOKAI).truecolor_style NULL_STYLE = Style() From b70e1c969dc08960afb1a2eb96180d805955473e Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 13:10:50 +0000 Subject: [PATCH 02/14] ANSI theme mapping --- src/textual/_ansi_theme.py | 53 +++++++++++++++++++++++++++++++++ src/textual/_styles_cache.py | 10 ++++++- src/textual/app.py | 13 ++++++-- src/textual/renderables/tint.py | 17 ++++------- tests/renderables/test_tint.py | 33 +++++++++++++++++++- tests/test_app.py | 23 ++++++++++++++ 6 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 src/textual/_ansi_theme.py diff --git a/src/textual/_ansi_theme.py b/src/textual/_ansi_theme.py new file mode 100644 index 0000000000..74ff3beb4f --- /dev/null +++ b/src/textual/_ansi_theme.py @@ -0,0 +1,53 @@ +from rich.terminal_theme import TerminalTheme + +MONOKAI_DARK = TerminalTheme( + (12, 12, 12), + (217, 217, 217), + [ + (26, 26, 26), + (244, 0, 95), + (152, 224, 36), + (253, 151, 31), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (196, 197, 181), + (98, 94, 76), + ], + [ + (244, 0, 95), + (152, 224, 36), + (224, 213, 97), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (246, 246, 239), + ], +) + +MONOKAI_LIGHT = TerminalTheme( + (217, 217, 217), + (12, 12, 12), + [ + (26, 26, 26), + (244, 0, 95), + (152, 224, 36), + (253, 151, 31), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (196, 197, 181), + (98, 94, 76), + ], + [ + (244, 0, 95), + (152, 224, 36), + (224, 213, 97), + (157, 101, 255), + (244, 0, 95), + (88, 209, 235), + (246, 246, 239), + ], +) + +DEFAULT_TERMINAL_THEME = MONOKAI_DARK diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index 6e6366113e..e578c64d8c 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -7,10 +7,12 @@ from rich.console import Console from rich.segment import Segment from rich.style import Style +from rich.terminal_theme import DEFAULT_TERMINAL_THEME from rich.text import Text from . import log from ._border import get_box, render_border_label, render_row +from ._context import active_app from ._opacity import _apply_opacity from ._segment_tools import line_pad, line_trim from .color import Color @@ -318,8 +320,14 @@ def post(segments: Iterable[Segment]) -> Iterable[Segment]: Returns: New list of segments """ + try: + app = active_app.get() + ansi_theme = app.ansi_theme + except LookupError: + ansi_theme = DEFAULT_TERMINAL_THEME + if styles.tint.a: - segments = Tint.process_segments(segments, styles.tint) + segments = Tint.process_segments(segments, styles.tint, ansi_theme) if opacity != 1.0: segments = _apply_opacity(segments, base_background, opacity) return segments diff --git a/src/textual/app.py b/src/textual/app.py index 5f72f79ed8..a455eba578 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -878,9 +878,7 @@ def watch_dark(self, dark: bool) -> None: """ self.set_class(dark, "-dark-mode", update=False) self.set_class(not dark, "-light-mode", update=False) - self._truecolor_filter.theme = ( - self.ansi_theme_dark if self.dark else self.ansi_theme_light - ) + self._truecolor_filter.theme = self.ansi_theme self.call_later(self.refresh_css) def watch_ansi_theme_dark(self, theme: TerminalTheme) -> None: @@ -893,6 +891,15 @@ def watch_ansi_theme_light(self, theme: TerminalTheme) -> None: self._truecolor_filter.theme = theme self.call_later(self.refresh_css) + @property + def ansi_theme(self) -> TerminalTheme: + """The ANSI TerminalTheme currently being used. + + Defines how colors defined as ANSI (e.g. `magenta`) inside Rich renderables + are mapped to hex codes. + """ + return self.ansi_theme_dark if self.dark else self.ansi_theme_light + def get_driver_class(self) -> Type[Driver]: """Get a driver class for this platform. diff --git a/src/textual/renderables/tint.py b/src/textual/renderables/tint.py index 592d4ab14c..a11450e2e3 100644 --- a/src/textual/renderables/tint.py +++ b/src/textual/renderables/tint.py @@ -2,10 +2,10 @@ from typing import Iterable -from rich import terminal_theme -from rich.console import Console, ConsoleOptions, RenderableType, RenderResult +from rich.console import RenderableType from rich.segment import Segment from rich.style import Style +from rich.terminal_theme import TerminalTheme from ..color import Color from ..filter import ANSIToTruecolor @@ -30,13 +30,14 @@ def __init__( @classmethod def process_segments( - cls, segments: Iterable[Segment], color: Color + cls, segments: Iterable[Segment], color: Color, ansi_theme: TerminalTheme ) -> Iterable[Segment]: """Apply tint to segments. Args: segments: Incoming segments. color: Color of tint. + ansi_theme: The TerminalTheme defining how to map ansi colors to hex. Returns: Segments with applied tint. @@ -45,8 +46,7 @@ def process_segments( style_from_color = Style.from_color _Segment = Segment - # TODO - needs to be updated to use the correct terminal theme - truecolor_style = ANSIToTruecolor(terminal_theme.DIMMED_MONOKAI).truecolor_style + truecolor_style = ANSIToTruecolor(ansi_theme).truecolor_style NULL_STYLE = Style() for segment in segments: @@ -74,10 +74,3 @@ def process_segments( ), control, ) - - def __rich_console__( - self, console: Console, options: ConsoleOptions - ) -> RenderResult: - segments = console.render(self.renderable, options) - color = self.color - return self.process_segments(segments, color) diff --git a/tests/renderables/test_tint.py b/tests/renderables/test_tint.py index 52e54aa60c..6c1b7c2525 100644 --- a/tests/renderables/test_tint.py +++ b/tests/renderables/test_tint.py @@ -1,8 +1,11 @@ import io from rich.console import Console +from rich.segment import Segments +from rich.terminal_theme import DIMMED_MONOKAI from rich.text import Text +from textual._ansi_theme import DEFAULT_TERMINAL_THEME from textual.color import Color from textual.renderables.tint import Tint @@ -10,8 +13,36 @@ def test_tint(): console = Console(file=io.StringIO(), force_terminal=True, color_system="truecolor") renderable = Text.from_markup("[#aabbcc on #112233]foo") - console.print(Tint(renderable, Color(0, 100, 0, 0.5))) + segments = list(console.render(renderable)) + console.print( + Segments( + Tint.process_segments( + segments=segments, + color=Color(0, 100, 0, 0.5), + ansi_theme=DEFAULT_TERMINAL_THEME, + ) + ) + ) output = console.file.getvalue() print(repr(output)) expected = "\x1b[38;2;85;143;102;48;2;8;67;25mfoo\x1b[0m\n" assert output == expected + + +def test_tint_ansi_mapping(): + console = Console(file=io.StringIO(), force_terminal=True, color_system="truecolor") + renderable = Text.from_markup("[red on yellow]foo") + segments = list(console.render(renderable)) + console.print( + Segments( + Tint.process_segments( + segments=segments, + color=Color(0, 100, 0, 0.5), + ansi_theme=DIMMED_MONOKAI, + ) + ) + ) + output = console.file.getvalue() + print(repr(output)) + expected = "\x1b[38;2;95;81;36;48;2;98;133;26mfoo\x1b[0m\n" + assert output == expected diff --git a/tests/test_app.py b/tests/test_app.py index e5afed1e2a..3e3927176f 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -1,5 +1,7 @@ import contextlib +from rich.terminal_theme import DIMMED_MONOKAI, MONOKAI, NIGHT_OWLISH + from textual.app import App, ComposeResult from textual.widgets import Button, Input @@ -117,3 +119,24 @@ async def test_no_return_code_while_running(): app = App() async with app.run_test(): assert app.return_code is None + + +async def test_ansi_theme(): + app = App() + async with app.run_test(): + app.ansi_theme_dark = NIGHT_OWLISH + assert app.ansi_theme == NIGHT_OWLISH + + app.dark = False + assert app.ansi_theme != NIGHT_OWLISH + + app.ansi_theme_light = MONOKAI + assert app.ansi_theme == MONOKAI + + # Ensure if we change the dark theme while on light mode, + # then change back to dark mode, the dark theme is updated. + app.ansi_theme_dark = DIMMED_MONOKAI + assert app.ansi_theme == MONOKAI + + app.dark = True + assert app.ansi_theme == DIMMED_MONOKAI From bd41f701f3ef628a5a6f842f63159a5da6791096 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 13:59:12 +0000 Subject: [PATCH 03/14] Snapshot test for ansi theme mapping --- .../__snapshots__/test_snapshots.ambr | 170 ++++++++++++++++++ .../snapshot_apps/ansi_mapping.py | 26 +++ tests/snapshot_tests/test_snapshots.py | 9 +- 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 tests/snapshot_tests/snapshot_apps/ansi_mapping.py diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index f31002578f..95e38f6585 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -161,6 +161,176 @@ ''' # --- +# name: test_ansi_color_mapping + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AnsiMappingApp + + + + + + + + + + Default foreground & background + Hello, red! + Hello, dim red! + Hello, green! + Hello, dim green! + Hello, yellow! + Hello, dim yellow! + Hello, blue! + Hello, dim blue! + Hello, magenta! + Hello, dim magenta! + Hello, cyan! + Hello, dim cyan! + Hello, white! + Hello, dim white! + Hello, black! + Hello, dim black! + + + + + + + + + + + + ''' +# --- # name: test_auto_fr ''' diff --git a/tests/snapshot_tests/snapshot_apps/ansi_mapping.py b/tests/snapshot_tests/snapshot_apps/ansi_mapping.py new file mode 100644 index 0000000000..809403bb54 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/ansi_mapping.py @@ -0,0 +1,26 @@ +from rich.text import Text +from textual.app import App, ComposeResult +from textual.widgets import Label + + +class AnsiMappingApp(App[None]): + def compose(self) -> ComposeResult: + ansi_colors = [ + "red", + "green", + "yellow", + "blue", + "magenta", + "cyan", + "white", + "black", + ] + yield Label("[default on default]Default foreground & background[/]") + for color in ansi_colors: + yield Label(f"[{color}]Hello, {color}![/]") + yield Label(f"[dim {color}]Hello, dim {color}![/]") + + +app = AnsiMappingApp() +if __name__ == "__main__": + app.run() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 8adff1659f..62e4fa8df6 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -762,7 +762,9 @@ async def run_before(pilot) -> None: pilot.app.screen.query_one(Input).cursor_blink = False await pilot.app.screen.workers.wait_for_complete() - assert snap_compare(SNAPSHOT_APPS_DIR / "command_palette_discovery.py", run_before=run_before) + assert snap_compare( + SNAPSHOT_APPS_DIR / "command_palette_discovery.py", run_before=run_before + ) # --- textual-dev library preview tests --- @@ -1052,3 +1054,8 @@ def test_input_percentage_width(snap_compare): """Check percentage widths work correctly.""" # https://github.com/Textualize/textual/issues/3721 assert snap_compare(SNAPSHOT_APPS_DIR / "input_percentage_width.py") + + +def test_ansi_color_mapping(snap_compare): + """Test how ANSI colors in Rich renderables are mapped to hex colors.""" + assert snap_compare(SNAPSHOT_APPS_DIR / "ansi_mapping.py") From ea15a24b0d8df2da5d8167ebb936132227474ab3 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 14:42:03 +0000 Subject: [PATCH 04/14] Add light/dark mode snapshots for ansi theme mapping --- .../__snapshots__/test_snapshots.ambr | 1686 +++++++++-------- .../snapshot_apps/ansi_mapping.py | 7 +- tests/snapshot_tests/test_snapshots.py | 9 +- 3 files changed, 936 insertions(+), 766 deletions(-) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 95e38f6585..deaf57a200 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -161,7 +161,7 @@ ''' # --- -# name: test_ansi_color_mapping +# name: test_ansi_color_mapping[False] ''' @@ -184,146 +184,314 @@ font-weight: 700; } - .terminal-950697367-matrix { + .terminal-306082694-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-950697367-title { + .terminal-306082694-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-950697367-r1 { fill: #d9d9d9 } - .terminal-950697367-r2 { fill: #e1e1e1 } - .terminal-950697367-r3 { fill: #c5c8c6 } - .terminal-950697367-r4 { fill: #f4005f } - .terminal-950697367-r5 { fill: #9e0c45 } - .terminal-950697367-r6 { fill: #98e024 } - .terminal-950697367-r7 { fill: #679221 } - .terminal-950697367-r8 { fill: #fd971f } - .terminal-950697367-r9 { fill: #a3661e } - .terminal-950697367-r10 { fill: #9d65ff } - .terminal-950697367-r11 { fill: #6a48a5 } - .terminal-950697367-r12 { fill: #58d1eb } - .terminal-950697367-r13 { fill: #408999 } - .terminal-950697367-r14 { fill: #c4c5b5 } - .terminal-950697367-r15 { fill: #818278 } - .terminal-950697367-r16 { fill: #1a1a1a } - .terminal-950697367-r17 { fill: #1b1b1b } + .terminal-306082694-r1 { fill: #1f1f1f } + .terminal-306082694-r2 { fill: #c5c8c6 } + .terminal-306082694-r3 { fill: #f4005f } + .terminal-306082694-r4 { fill: #f4629b } + .terminal-306082694-r5 { fill: #98e024 } + .terminal-306082694-r6 { fill: #bde877 } + .terminal-306082694-r7 { fill: #fd971f } + .terminal-306082694-r8 { fill: #f9bc74 } + .terminal-306082694-r9 { fill: #9d65ff } + .terminal-306082694-r10 { fill: #c09efb } + .terminal-306082694-r11 { fill: #58d1eb } + .terminal-306082694-r12 { fill: #96dfef } + .terminal-306082694-r13 { fill: #c4c5b5 } + .terminal-306082694-r14 { fill: #d7d8ce } + .terminal-306082694-r15 { fill: #1a1a1a } + .terminal-306082694-r16 { fill: #717171 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AnsiMappingApp + AnsiMappingApp - - - - Default foreground & background - Hello, red! - Hello, dim red! - Hello, green! - Hello, dim green! - Hello, yellow! - Hello, dim yellow! - Hello, blue! - Hello, dim blue! - Hello, magenta! - Hello, dim magenta! - Hello, cyan! - Hello, dim cyan! - Hello, white! - Hello, dim white! - Hello, black! - Hello, dim black! - - - - - - + + + + Foreground & background + red + dim red + green + dim green + yellow + dim yellow + blue + dim blue + magenta + dim magenta + cyan + dim cyan + white + dim white + black + dim black + + + + + + + + + + + + ''' +# --- +# name: test_ansi_color_mapping[True] + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AnsiMappingApp + + + + + + + + + + Foreground & background + red + dim red + green + dim green + yellow + dim yellow + blue + dim blue + magenta + dim magenta + cyan + dim cyan + white + dim white + black + dim black + + + + + + @@ -2042,144 +2210,144 @@ font-weight: 700; } - .terminal-1403746156-matrix { + .terminal-3087759104-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1403746156-title { + .terminal-3087759104-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1403746156-r1 { fill: #e1e1e1 } - .terminal-1403746156-r2 { fill: #c5c8c6 } - .terminal-1403746156-r3 { fill: #262626 } - .terminal-1403746156-r4 { fill: #e2e2e2 } - .terminal-1403746156-r5 { fill: #4a4a4a } - .terminal-1403746156-r6 { fill: #2e2e2e;font-weight: bold } - .terminal-1403746156-r7 { fill: #e3e3e3 } - .terminal-1403746156-r8 { fill: #e3e3e3;font-weight: bold } - .terminal-1403746156-r9 { fill: #855c8d } - .terminal-1403746156-r10 { fill: #4ebf71;font-weight: bold } - .terminal-1403746156-r11 { fill: #0178d4 } - .terminal-1403746156-r12 { fill: #14191f } - .terminal-1403746156-r13 { fill: #5d5d5d } - .terminal-1403746156-r14 { fill: #e3e3e3;text-decoration: underline; } + .terminal-3087759104-r1 { fill: #e1e1e1 } + .terminal-3087759104-r2 { fill: #c5c8c6 } + .terminal-3087759104-r3 { fill: #262626 } + .terminal-3087759104-r4 { fill: #e2e2e2 } + .terminal-3087759104-r5 { fill: #4a4a4a } + .terminal-3087759104-r6 { fill: #2e2e2e;font-weight: bold } + .terminal-3087759104-r7 { fill: #e3e3e3 } + .terminal-3087759104-r8 { fill: #e3e3e3;font-weight: bold } + .terminal-3087759104-r9 { fill: #f4005f } + .terminal-3087759104-r10 { fill: #4ebf71;font-weight: bold } + .terminal-3087759104-r11 { fill: #0178d4 } + .terminal-3087759104-r12 { fill: #14191f } + .terminal-3087759104-r13 { fill: #5d5d5d } + .terminal-3087759104-r14 { fill: #e3e3e3;text-decoration: underline; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CheckboxApp + CheckboxApp - + - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - X Arrakis 😓 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔ - X Caladan - ▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔ - X Chusuk - ▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - XGiedi Prime - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔ - XGinaz - ▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔ - X Grumman - ▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▃▃ - XKaitain - ▁▁▁▁▁▁▁▁▁▁▁▁▁ - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + X Arrakis 😓 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔ + X Caladan + ▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔ + X Chusuk + ▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + XGiedi Prime + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔ + XGinaz + ▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔ + X Grumman + ▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▃▃ + XKaitain + ▁▁▁▁▁▁▁▁▁▁▁▁▁ + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ @@ -3162,137 +3330,136 @@ font-weight: 700; } - .terminal-174430999-matrix { + .terminal-835230732-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-174430999-title { + .terminal-835230732-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-174430999-r1 { fill: #a2a2a2 } - .terminal-174430999-r2 { fill: #c5c8c6 } - .terminal-174430999-r3 { fill: #004578 } - .terminal-174430999-r4 { fill: #e2e3e3 } - .terminal-174430999-r5 { fill: #00ff00 } - .terminal-174430999-r6 { fill: #24292f } - .terminal-174430999-r7 { fill: #1e1e1e } - .terminal-174430999-r8 { fill: #fea62b;font-weight: bold } + .terminal-835230732-r1 { fill: #a2a2a2 } + .terminal-835230732-r2 { fill: #c5c8c6 } + .terminal-835230732-r3 { fill: #004578 } + .terminal-835230732-r4 { fill: #e2e3e3 } + .terminal-835230732-r5 { fill: #00ff00 } + .terminal-835230732-r6 { fill: #1e1e1e } + .terminal-835230732-r7 { fill: #fea62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎A - - - This is a test of this code 9 - This is a test of this code 8 - This is a test of this code 7 - This is a test of this code 6 - This is a test of this code 5 - This is a test of this code 4 - This is a test of this code 3 - This is a test of this code 2 - This is a test of this code 1 - This is a test of this code 0 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎A + + + This is a test of this code 9 + This is a test of this code 8 + This is a test of this code 7 + This is a test of this code 6 + This is a test of this code 5 + This is a test of this code 4 + This is a test of this code 3 + This is a test of this code 2 + This is a test of this code 1 + This is a test of this code 0 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -3323,137 +3490,136 @@ font-weight: 700; } - .terminal-3083317776-matrix { + .terminal-956019461-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3083317776-title { + .terminal-956019461-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3083317776-r1 { fill: #a2a2a2 } - .terminal-3083317776-r2 { fill: #c5c8c6 } - .terminal-3083317776-r3 { fill: #004578 } - .terminal-3083317776-r4 { fill: #e2e3e3 } - .terminal-3083317776-r5 { fill: #00ff00 } - .terminal-3083317776-r6 { fill: #24292f } - .terminal-3083317776-r7 { fill: #1e1e1e } - .terminal-3083317776-r8 { fill: #777a7e } + .terminal-956019461-r1 { fill: #a2a2a2 } + .terminal-956019461-r2 { fill: #c5c8c6 } + .terminal-956019461-r3 { fill: #004578 } + .terminal-956019461-r4 { fill: #e2e3e3 } + .terminal-956019461-r5 { fill: #00ff00 } + .terminal-956019461-r6 { fill: #1e1e1e } + .terminal-956019461-r7 { fill: #777a7e } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎Command Palette Search... - - - This is a test of this code 0 - This is a test of this code 1 - This is a test of this code 2 - This is a test of this code 3 - This is a test of this code 4 - This is a test of this code 5 - This is a test of this code 6 - This is a test of this code 7 - This is a test of this code 8 - This is a test of this code 9 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎Command Palette Search... + + + This is a test of this code 0 + This is a test of this code 1 + This is a test of this code 2 + This is a test of this code 3 + This is a test of this code 4 + This is a test of this code 5 + This is a test of this code 6 + This is a test of this code 7 + This is a test of this code 8 + This is a test of this code 9 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -5178,141 +5344,141 @@ font-weight: 700; } - .terminal-1056312446-matrix { + .terminal-2586053582-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1056312446-title { + .terminal-2586053582-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1056312446-r1 { fill: #e1e1e1 } - .terminal-1056312446-r2 { fill: #c5c8c6 } - .terminal-1056312446-r3 { fill: #fea62b } - .terminal-1056312446-r4 { fill: #fea62b;font-weight: bold } - .terminal-1056312446-r5 { fill: #fea62b;font-weight: bold;font-style: italic; } - .terminal-1056312446-r6 { fill: #be3f48;font-weight: bold } - .terminal-1056312446-r7 { fill: #1e1e1e } - .terminal-1056312446-r8 { fill: #1e1e1e;text-decoration: underline; } - .terminal-1056312446-r9 { fill: #fea62b;text-decoration: underline; } - .terminal-1056312446-r10 { fill: #3a3d43;text-decoration: underline; } - .terminal-1056312446-r11 { fill: #4ebf71 } - .terminal-1056312446-r12 { fill: #b93c5b } + .terminal-2586053582-r1 { fill: #e1e1e1 } + .terminal-2586053582-r2 { fill: #c5c8c6 } + .terminal-2586053582-r3 { fill: #fea62b } + .terminal-2586053582-r4 { fill: #fea62b;font-weight: bold } + .terminal-2586053582-r5 { fill: #fea62b;font-weight: bold;font-style: italic; } + .terminal-2586053582-r6 { fill: #f4005f;font-weight: bold } + .terminal-2586053582-r7 { fill: #1e1e1e } + .terminal-2586053582-r8 { fill: #1e1e1e;text-decoration: underline; } + .terminal-2586053582-r9 { fill: #fea62b;text-decoration: underline; } + .terminal-2586053582-r10 { fill: #1a1a1a;text-decoration: underline; } + .terminal-2586053582-r11 { fill: #4ebf71 } + .terminal-2586053582-r12 { fill: #b93c5b } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - BorderSubTitleAlignAll + BorderSubTitleAlignAll - - - - - - Border titleLef…▁▁▁▁Left▁▁▁▁ - This is the story ofa Pythondeveloper that - Border subtitleCen…▔▔▔▔@@@▔▔▔▔▔ - - - - - - +--------------+Title───────────────── - |had to fill up|nine labelsand ended up redoing it - +-Left-------+──────────────Subtitle - - - - - Title, but really looo… - Title, but r…Title, but reall… - because the first tryhad some labelsthat were too long. - Subtitle, bu…Subtitle, but re… - Subtitle, but really l… - + + + + + + Border titleLef…▁▁▁▁Left▁▁▁▁ + This is the story ofa Pythondeveloper that + Border subtitleCen…▔▔▔▔@@@▔▔▔▔▔ + + + + + + +--------------+Title───────────────── + |had to fill up|nine labelsand ended up redoing it + +-Left-------+──────────────Subtitle + + + + + Title, but really looo… + Title, but r…Title, but reall… + because the first tryhad some labelsthat were too long. + Subtitle, bu…Subtitle, but re… + Subtitle, but really l… + @@ -16586,137 +16752,137 @@ font-weight: 700; } - .terminal-905695451-matrix { + .terminal-3159150741-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-905695451-title { + .terminal-3159150741-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-905695451-r1 { fill: #e1e1e1 } - .terminal-905695451-r2 { fill: #c5c8c6 } - .terminal-905695451-r3 { fill: #dde6ed;font-weight: bold } - .terminal-905695451-r4 { fill: #dde6ed } - .terminal-905695451-r5 { fill: #fea62b;font-weight: bold;font-style: italic; } - .terminal-905695451-r6 { fill: #e1e2e3 } - .terminal-905695451-r7 { fill: #be3f48 } - .terminal-905695451-r8 { fill: #be3f48;font-weight: bold;font-style: italic; } + .terminal-3159150741-r1 { fill: #e1e1e1 } + .terminal-3159150741-r2 { fill: #c5c8c6 } + .terminal-3159150741-r3 { fill: #dde6ed;font-weight: bold } + .terminal-3159150741-r4 { fill: #dde6ed } + .terminal-3159150741-r5 { fill: #fea62b;font-weight: bold;font-style: italic; } + .terminal-3159150741-r6 { fill: #e1e2e3 } + .terminal-3159150741-r7 { fill: #f4005f } + .terminal-3159150741-r8 { fill: #f4005f;font-weight: bold;font-style: italic; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - DataTableCursorStyles + DataTableCursorStyles - - - - Foreground is 'css', background is 'css': -  Movies      -  Severance   - Foundation - Dark - - Foreground is 'css', background is 'renderable': -  Movies      - Severance - Foundation - Dark - - Foreground is 'renderable', background is 'renderable': -  Movies      - Severance - Foundation - Dark - - Foreground is 'renderable', background is 'css': -  Movies      - Severance - Foundation - Dark + + + + Foreground is 'css', background is 'css': +  Movies      +  Severance   + Foundation + Dark + + Foreground is 'css', background is 'renderable': +  Movies      + Severance + Foundation + Dark + + Foreground is 'renderable', background is 'renderable': +  Movies      + Severance + Foundation + Dark + + Foreground is 'renderable', background is 'css': +  Movies      + Severance + Foundation + Dark @@ -25712,138 +25878,138 @@ font-weight: 700; } - .terminal-2568645244-matrix { + .terminal-43804987-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-2568645244-title { + .terminal-43804987-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-2568645244-r1 { fill: #1e1e1e } - .terminal-2568645244-r2 { fill: #0178d4 } - .terminal-2568645244-r3 { fill: #c5c8c6 } - .terminal-2568645244-r4 { fill: #ddedf9;font-weight: bold } - .terminal-2568645244-r5 { fill: #e2e2e2;font-weight: bold } - .terminal-2568645244-r6 { fill: #e2e2e2 } - .terminal-2568645244-r7 { fill: #434343 } - .terminal-2568645244-r8 { fill: #be3f48 } - .terminal-2568645244-r9 { fill: #e1e1e1 } + .terminal-43804987-r1 { fill: #1e1e1e } + .terminal-43804987-r2 { fill: #0178d4 } + .terminal-43804987-r3 { fill: #c5c8c6 } + .terminal-43804987-r4 { fill: #ddedf9;font-weight: bold } + .terminal-43804987-r5 { fill: #e2e2e2;font-weight: bold } + .terminal-43804987-r6 { fill: #e2e2e2 } + .terminal-43804987-r7 { fill: #434343 } + .terminal-43804987-r8 { fill: #f4005f } + .terminal-43804987-r9 { fill: #e1e1e1 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - OptionListApp + OptionListApp - + - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - OneOneOne - TwoTwoTwo - ──────────────────────────────────────────────────────────────────── - ThreeThreeThree - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - - - - - - - - - - - - + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + OneOneOne + TwoTwoTwo + ──────────────────────────────────────────────────────────────────── + ThreeThreeThree + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + + + + + + + + + + + + @@ -29081,140 +29247,140 @@ font-weight: 700; } - .terminal-386310630-matrix { + .terminal-2351407483-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-386310630-title { + .terminal-2351407483-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-386310630-r1 { fill: #e1e1e1 } - .terminal-386310630-r2 { fill: #c5c8c6 } - .terminal-386310630-r3 { fill: #1e1e1e } - .terminal-386310630-r4 { fill: #0178d4 } - .terminal-386310630-r5 { fill: #575757 } - .terminal-386310630-r6 { fill: #262626;font-weight: bold } - .terminal-386310630-r7 { fill: #e2e2e2 } - .terminal-386310630-r8 { fill: #e2e2e2;text-decoration: underline; } - .terminal-386310630-r9 { fill: #434343 } - .terminal-386310630-r10 { fill: #4ebf71;font-weight: bold } - .terminal-386310630-r11 { fill: #be3f48;font-weight: bold;font-style: italic; } + .terminal-2351407483-r1 { fill: #e1e1e1 } + .terminal-2351407483-r2 { fill: #c5c8c6 } + .terminal-2351407483-r3 { fill: #1e1e1e } + .terminal-2351407483-r4 { fill: #0178d4 } + .terminal-2351407483-r5 { fill: #575757 } + .terminal-2351407483-r6 { fill: #262626;font-weight: bold } + .terminal-2351407483-r7 { fill: #e2e2e2 } + .terminal-2351407483-r8 { fill: #e2e2e2;text-decoration: underline; } + .terminal-2351407483-r9 { fill: #434343 } + .terminal-2351407483-r10 { fill: #4ebf71;font-weight: bold } + .terminal-2351407483-r11 { fill: #f4005f;font-weight: bold;font-style: italic; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - RadioChoicesApp + RadioChoicesApp - + - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - Battlestar Galactica Amanda -  Dune 1984 Connor MacLeod -  Dune 2021 Duncan MacLeod -  Serenity Heather MacLeod -  Star Trek: The Motion Pictur Joe Dawson -  Star Wars: A New Hope Kurgan, The -  The Last Starfighter Methos -  Total Recall 👉 🔴 Rachel Ellenstein -  Wing Commander Ramírez - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - - - + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + Battlestar Galactica Amanda +  Dune 1984 Connor MacLeod +  Dune 2021 Duncan MacLeod +  Serenity Heather MacLeod +  Star Trek: The Motion Pictur Joe Dawson +  Star Wars: A New Hope Kurgan, The +  The Last Starfighter Methos +  Total Recall 👉 🔴 Rachel Ellenstein +  Wing Commander Ramírez + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + + + @@ -30508,137 +30674,137 @@ font-weight: 700; } - .terminal-565918768-matrix { + .terminal-1340160965-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-565918768-title { + .terminal-1340160965-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-565918768-r1 { fill: #e1e1e1 } - .terminal-565918768-r2 { fill: #c5c8c6 } - .terminal-565918768-r3 { fill: #004578 } - .terminal-565918768-r4 { fill: #23568b } - .terminal-565918768-r5 { fill: #fea62b } - .terminal-565918768-r6 { fill: #be3f48 } - .terminal-565918768-r7 { fill: #14191f } + .terminal-1340160965-r1 { fill: #e1e1e1 } + .terminal-1340160965-r2 { fill: #c5c8c6 } + .terminal-1340160965-r3 { fill: #004578 } + .terminal-1340160965-r4 { fill: #23568b } + .terminal-1340160965-r5 { fill: #fea62b } + .terminal-1340160965-r6 { fill: #f4005f } + .terminal-1340160965-r7 { fill: #14191f } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - MyApp + MyApp - + - - SPAM - SPAM - SPAM - ──────────────────────────────────────────────────────────────────────────── - SPAM - SPAM - SPAM - SPAM - SPAM - SPAM▄▄ - SPAM - SPAM - ──────────────────────────────────────────────────────────────────────── - @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>>bullseye<<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - ▇▇ - ▄▄ - - - - - - - - ──────────────────────────────────────────────────────────────────────────── + + SPAM + SPAM + SPAM + ──────────────────────────────────────────────────────────────────────────── + SPAM + SPAM + SPAM + SPAM + SPAM + SPAM▄▄ + SPAM + SPAM + ──────────────────────────────────────────────────────────────────────── + @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@>>bullseye<<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + ▇▇ + ▄▄ + + + + + + + + ──────────────────────────────────────────────────────────────────────────── @@ -32113,141 +32279,141 @@ font-weight: 700; } - .terminal-1048388837-matrix { + .terminal-1590895671-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1048388837-title { + .terminal-1590895671-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1048388837-r1 { fill: #c5c8c6 } - .terminal-1048388837-r2 { fill: #e3e3e3 } - .terminal-1048388837-r3 { fill: #e1e1e1 } - .terminal-1048388837-r4 { fill: #0178d4 } - .terminal-1048388837-r5 { fill: #e1e1e1;font-weight: bold } - .terminal-1048388837-r6 { fill: #575757 } - .terminal-1048388837-r7 { fill: #4ebf71;font-weight: bold } - .terminal-1048388837-r8 { fill: #ddedf9;font-weight: bold } - .terminal-1048388837-r9 { fill: #879a3b } - .terminal-1048388837-r10 { fill: #262626;font-weight: bold } - .terminal-1048388837-r11 { fill: #e2e2e2 } - .terminal-1048388837-r12 { fill: #ddedf9 } + .terminal-1590895671-r1 { fill: #c5c8c6 } + .terminal-1590895671-r2 { fill: #e3e3e3 } + .terminal-1590895671-r3 { fill: #e1e1e1 } + .terminal-1590895671-r4 { fill: #0178d4 } + .terminal-1590895671-r5 { fill: #e1e1e1;font-weight: bold } + .terminal-1590895671-r6 { fill: #575757 } + .terminal-1590895671-r7 { fill: #4ebf71;font-weight: bold } + .terminal-1590895671-r8 { fill: #ddedf9;font-weight: bold } + .terminal-1590895671-r9 { fill: #98e024 } + .terminal-1590895671-r10 { fill: #262626;font-weight: bold } + .terminal-1590895671-r11 { fill: #e2e2e2 } + .terminal-1590895671-r12 { fill: #ddedf9 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - SelectionListApp + SelectionListApp - + - - SelectionListApp - - -  Shall we play some games? ── Selected games ───────────── - [ - XFalken's Maze'secret_back_door', - XBlack Jack'a_nice_game_of_chess', - XGin Rummy'fighter_combat' - XHearts] - XBridge────────────────────────────── - XCheckers - XChess - XPoker - XFighter Combat - - ────────────────────────────── - - - - - - - + + SelectionListApp + + +  Shall we play some games? ── Selected games ───────────── + [ + XFalken's Maze'secret_back_door', + XBlack Jack'a_nice_game_of_chess', + XGin Rummy'fighter_combat' + XHearts] + XBridge────────────────────────────── + XCheckers + XChess + XPoker + XFighter Combat + + ────────────────────────────── + + + + + + + @@ -34198,136 +34364,136 @@ font-weight: 700; } - .terminal-1404658517-matrix { + .terminal-2580112047-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-1404658517-title { + .terminal-2580112047-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-1404658517-r1 { fill: #e1e1e1 } - .terminal-1404658517-r2 { fill: #c5c8c6 } - .terminal-1404658517-r3 { fill: #e1e1e1;font-weight: bold } - .terminal-1404658517-r4 { fill: #879a3b;font-weight: bold;font-style: italic; } - .terminal-1404658517-r5 { fill: #855c8d;font-weight: bold } - .terminal-1404658517-r6 { fill: #e1e1e1;font-style: italic; } - .terminal-1404658517-r7 { fill: #e1e1e1;text-decoration: underline; } + .terminal-2580112047-r1 { fill: #e1e1e1 } + .terminal-2580112047-r2 { fill: #c5c8c6 } + .terminal-2580112047-r3 { fill: #e1e1e1;font-weight: bold } + .terminal-2580112047-r4 { fill: #98e024;font-weight: bold;font-style: italic; } + .terminal-2580112047-r5 { fill: #f4005f;font-weight: bold } + .terminal-2580112047-r6 { fill: #e1e1e1;font-style: italic; } + .terminal-2580112047-r7 { fill: #e1e1e1;text-decoration: underline; } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - TableStaticApp + TableStaticApp - + - - ┏━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┓ - FooBar   baz       - ┡━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━┩ - Hello World!ItalicUnderline - └──────────────┴────────┴───────────┘ - - - - - - - - - - - - - - - - - - + + ┏━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┓ + FooBar   baz       + ┡━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━┩ + Hello World!ItalicUnderline + └──────────────┴────────┴───────────┘ + + + + + + + + + + + + + + + + + + @@ -38999,146 +39165,146 @@ font-weight: 700; } - .terminal-3972235479-matrix { + .terminal-2882699257-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3972235479-title { + .terminal-2882699257-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3972235479-r1 { fill: #c5c8c6 } - .terminal-3972235479-r2 { fill: #e3e3e3 } - .terminal-3972235479-r3 { fill: #e1e1e1 } - .terminal-3972235479-r4 { fill: #e1e1e1;text-decoration: underline; } - .terminal-3972235479-r5 { fill: #e1e1e1;font-weight: bold } - .terminal-3972235479-r6 { fill: #e1e1e1;font-style: italic; } - .terminal-3972235479-r7 { fill: #855c8d;font-weight: bold } - .terminal-3972235479-r8 { fill: #c5a635 } - .terminal-3972235479-r9 { fill: #879a3b } - .terminal-3972235479-r10 { fill: #0f722f;font-style: italic; } - .terminal-3972235479-r11 { fill: #ffcf56 } - .terminal-3972235479-r12 { fill: #e76580 } - .terminal-3972235479-r13 { fill: #fea62b;font-weight: bold } - .terminal-3972235479-r14 { fill: #f5e5e9;font-weight: bold } - .terminal-3972235479-r15 { fill: #b86b00 } - .terminal-3972235479-r16 { fill: #780028 } + .terminal-2882699257-r1 { fill: #c5c8c6 } + .terminal-2882699257-r2 { fill: #e3e3e3 } + .terminal-2882699257-r3 { fill: #e1e1e1 } + .terminal-2882699257-r4 { fill: #e1e1e1;text-decoration: underline; } + .terminal-2882699257-r5 { fill: #e1e1e1;font-weight: bold } + .terminal-2882699257-r6 { fill: #e1e1e1;font-style: italic; } + .terminal-2882699257-r7 { fill: #f4005f;font-weight: bold } + .terminal-2882699257-r8 { fill: #fd971f } + .terminal-2882699257-r9 { fill: #98e024 } + .terminal-2882699257-r10 { fill: #98e024;font-style: italic; } + .terminal-2882699257-r11 { fill: #ffcf56 } + .terminal-2882699257-r12 { fill: #e76580 } + .terminal-2882699257-r13 { fill: #fea62b;font-weight: bold } + .terminal-2882699257-r14 { fill: #f5e5e9;font-weight: bold } + .terminal-2882699257-r15 { fill: #b86b00 } + .terminal-2882699257-r16 { fill: #780028 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - Textual Keys + Textual Keys - + - - Textual Keys - ╭────────────────────────────────────────────────────────────────────────────╮ - Press some keys! - - To quit the app press ctrl+ctwice or press the Quit button below. - ╰────────────────────────────────────────────────────────────────────────────╯ - Key(key='a'character='a'name='a'is_printable=True) - Key(key='b'character='b'name='b'is_printable=True) - - - - - - - - - - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ClearQuit - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + Textual Keys + ╭────────────────────────────────────────────────────────────────────────────╮ + Press some keys! + + To quit the app press ctrl+ctwice or press the Quit button below. + ╰────────────────────────────────────────────────────────────────────────────╯ + Key(key='a'character='a'name='a'is_printable=True) + Key(key='b'character='b'name='b'is_printable=True) + + + + + + + + + + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ClearQuit + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ diff --git a/tests/snapshot_tests/snapshot_apps/ansi_mapping.py b/tests/snapshot_tests/snapshot_apps/ansi_mapping.py index 809403bb54..05e4669cd2 100644 --- a/tests/snapshot_tests/snapshot_apps/ansi_mapping.py +++ b/tests/snapshot_tests/snapshot_apps/ansi_mapping.py @@ -1,4 +1,3 @@ -from rich.text import Text from textual.app import App, ComposeResult from textual.widgets import Label @@ -15,10 +14,10 @@ def compose(self) -> ComposeResult: "white", "black", ] - yield Label("[default on default]Default foreground & background[/]") + yield Label("[fg on bg]Foreground & background[/]") for color in ansi_colors: - yield Label(f"[{color}]Hello, {color}![/]") - yield Label(f"[dim {color}]Hello, dim {color}![/]") + yield Label(f"[{color}]{color}[/]") + yield Label(f"[dim {color}]dim {color}[/]") app = AnsiMappingApp() diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 62e4fa8df6..c7daa4a400 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -1056,6 +1056,11 @@ def test_input_percentage_width(snap_compare): assert snap_compare(SNAPSHOT_APPS_DIR / "input_percentage_width.py") -def test_ansi_color_mapping(snap_compare): +@pytest.mark.parametrize("dark", [True, False]) +def test_ansi_color_mapping(snap_compare, dark): """Test how ANSI colors in Rich renderables are mapped to hex colors.""" - assert snap_compare(SNAPSHOT_APPS_DIR / "ansi_mapping.py") + + def setup(pilot): + pilot.app.dark = dark + + assert snap_compare(SNAPSHOT_APPS_DIR / "ansi_mapping.py", run_before=setup) From 04b9c7115da48325836cd0335d1feeac8a7e4415 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 14:48:11 +0000 Subject: [PATCH 05/14] Update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61689b4643..7f473f541a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased + +### Added + +- Mapping of ANSI colors to hex codes configurable via `App.ansi_theme_dark` and `App.ansi_theme_light` https://github.com/Textualize/textual/pull/4192 + ## [0.52.1] - 2024-02-20 ### Fixed From 33a6d8aa51b8cb64b0c3a4d3c62c7003e86ebc3a Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 14:56:27 +0000 Subject: [PATCH 06/14] Snapshot update failing command palette tests --- .../__snapshots__/test_snapshots.ambr | 238 +++++++++--------- 1 file changed, 120 insertions(+), 118 deletions(-) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index deaf57a200..14f40b9858 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -3330,136 +3330,137 @@ font-weight: 700; } - .terminal-835230732-matrix { + .terminal-174430999-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-835230732-title { + .terminal-174430999-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-835230732-r1 { fill: #a2a2a2 } - .terminal-835230732-r2 { fill: #c5c8c6 } - .terminal-835230732-r3 { fill: #004578 } - .terminal-835230732-r4 { fill: #e2e3e3 } - .terminal-835230732-r5 { fill: #00ff00 } - .terminal-835230732-r6 { fill: #1e1e1e } - .terminal-835230732-r7 { fill: #fea62b;font-weight: bold } + .terminal-174430999-r1 { fill: #a2a2a2 } + .terminal-174430999-r2 { fill: #c5c8c6 } + .terminal-174430999-r3 { fill: #004578 } + .terminal-174430999-r4 { fill: #e2e3e3 } + .terminal-174430999-r5 { fill: #00ff00 } + .terminal-174430999-r6 { fill: #24292f } + .terminal-174430999-r7 { fill: #1e1e1e } + .terminal-174430999-r8 { fill: #fea62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎A - - - This is a test of this code 9 - This is a test of this code 8 - This is a test of this code 7 - This is a test of this code 6 - This is a test of this code 5 - This is a test of this code 4 - This is a test of this code 3 - This is a test of this code 2 - This is a test of this code 1 - This is a test of this code 0 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎A + + + This is a test of this code 9 + This is a test of this code 8 + This is a test of this code 7 + This is a test of this code 6 + This is a test of this code 5 + This is a test of this code 4 + This is a test of this code 3 + This is a test of this code 2 + This is a test of this code 1 + This is a test of this code 0 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -3490,136 +3491,137 @@ font-weight: 700; } - .terminal-956019461-matrix { + .terminal-3083317776-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-956019461-title { + .terminal-3083317776-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-956019461-r1 { fill: #a2a2a2 } - .terminal-956019461-r2 { fill: #c5c8c6 } - .terminal-956019461-r3 { fill: #004578 } - .terminal-956019461-r4 { fill: #e2e3e3 } - .terminal-956019461-r5 { fill: #00ff00 } - .terminal-956019461-r6 { fill: #1e1e1e } - .terminal-956019461-r7 { fill: #777a7e } + .terminal-3083317776-r1 { fill: #a2a2a2 } + .terminal-3083317776-r2 { fill: #c5c8c6 } + .terminal-3083317776-r3 { fill: #004578 } + .terminal-3083317776-r4 { fill: #e2e3e3 } + .terminal-3083317776-r5 { fill: #00ff00 } + .terminal-3083317776-r6 { fill: #24292f } + .terminal-3083317776-r7 { fill: #1e1e1e } + .terminal-3083317776-r8 { fill: #777a7e } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎Command Palette Search... - - - This is a test of this code 0 - This is a test of this code 1 - This is a test of this code 2 - This is a test of this code 3 - This is a test of this code 4 - This is a test of this code 5 - This is a test of this code 6 - This is a test of this code 7 - This is a test of this code 8 - This is a test of this code 9 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎Command Palette Search... + + + This is a test of this code 0 + This is a test of this code 1 + This is a test of this code 2 + This is a test of this code 3 + This is a test of this code 4 + This is a test of this code 5 + This is a test of this code 6 + This is a test of this code 7 + This is a test of this code 8 + This is a test of this code 9 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + From 8e93034a851c2ed21d8698d76a3af9d91257b6ba Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 14:58:57 +0000 Subject: [PATCH 07/14] Import default ansi theme from textual instead of rich --- src/textual/_styles_cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index e578c64d8c..9d4888e292 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -7,10 +7,10 @@ from rich.console import Console from rich.segment import Segment from rich.style import Style -from rich.terminal_theme import DEFAULT_TERMINAL_THEME from rich.text import Text from . import log +from ._ansi_theme import DEFAULT_TERMINAL_THEME from ._border import get_box, render_border_label, render_row from ._context import active_app from ._opacity import _apply_opacity From aaede2d59e170fecebfec67451b161c8421cc614 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 15:39:00 +0000 Subject: [PATCH 08/14] Use a dedicated light theme --- src/textual/_ansi_theme.py | 38 +++++++++++++++++++------------------- src/textual/app.py | 6 +++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/textual/_ansi_theme.py b/src/textual/_ansi_theme.py index 74ff3beb4f..c7c50a2550 100644 --- a/src/textual/_ansi_theme.py +++ b/src/textual/_ansi_theme.py @@ -25,28 +25,28 @@ ], ) -MONOKAI_LIGHT = TerminalTheme( - (217, 217, 217), - (12, 12, 12), +ALABASTER = TerminalTheme( + (247, 247, 247), + (0, 0, 0), [ - (26, 26, 26), - (244, 0, 95), - (152, 224, 36), - (253, 151, 31), - (157, 101, 255), - (244, 0, 95), - (88, 209, 235), - (196, 197, 181), - (98, 94, 76), + (0, 0, 0), + (170, 55, 49), + (68, 140, 39), + (203, 144, 0), + (50, 92, 192), + (122, 62, 157), + (0, 131, 178), + (247, 247, 247), + (119, 119, 119), ], [ - (244, 0, 95), - (152, 224, 36), - (224, 213, 97), - (157, 101, 255), - (244, 0, 95), - (88, 209, 235), - (246, 246, 239), + (240, 80, 80), + (96, 203, 0), + (255, 188, 93), + (0, 122, 204), + (230, 76, 230), + (0, 170, 203), + (247, 247, 247), ], ) diff --git a/src/textual/app.py b/src/textual/app.py index 4eaf8bc955..d1faa70b89 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -52,7 +52,6 @@ import rich import rich.repr -from rich import terminal_theme from rich.console import Console, RenderableType from rich.control import Control from rich.protocol import is_renderable @@ -72,6 +71,7 @@ ) from ._animator import DEFAULT_EASING, Animatable, Animator, EasingFunction from ._ansi_sequences import SYNC_END, SYNC_START +from ._ansi_theme import ALABASTER, MONOKAI_DARK from ._callback import invoke from ._compose import compose from ._compositor import CompositorUpdate @@ -399,10 +399,10 @@ class MyApp(App[None]): get focus when the terminal widget has focus. """ - ansi_theme_dark = Reactive(terminal_theme.MONOKAI, init=False) + ansi_theme_dark = Reactive(MONOKAI_DARK, init=False) """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in dark mode.""" - ansi_theme_light = Reactive(terminal_theme.MONOKAI, init=False) + ansi_theme_light = Reactive(ALABASTER, init=False) """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in light mode.""" def __init__( From c18fff12fb4b7544d67da891c76db24e89171f75 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 15:44:58 +0000 Subject: [PATCH 09/14] Fix snapshot tests --- .../__snapshots__/test_snapshots.ambr | 376 +++++++++--------- 1 file changed, 188 insertions(+), 188 deletions(-) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 14f40b9858..237dea0d44 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -184,145 +184,147 @@ font-weight: 700; } - .terminal-306082694-matrix { + .terminal-1605463770-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-306082694-title { + .terminal-1605463770-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-306082694-r1 { fill: #1f1f1f } - .terminal-306082694-r2 { fill: #c5c8c6 } - .terminal-306082694-r3 { fill: #f4005f } - .terminal-306082694-r4 { fill: #f4629b } - .terminal-306082694-r5 { fill: #98e024 } - .terminal-306082694-r6 { fill: #bde877 } - .terminal-306082694-r7 { fill: #fd971f } - .terminal-306082694-r8 { fill: #f9bc74 } - .terminal-306082694-r9 { fill: #9d65ff } - .terminal-306082694-r10 { fill: #c09efb } - .terminal-306082694-r11 { fill: #58d1eb } - .terminal-306082694-r12 { fill: #96dfef } - .terminal-306082694-r13 { fill: #c4c5b5 } - .terminal-306082694-r14 { fill: #d7d8ce } - .terminal-306082694-r15 { fill: #1a1a1a } - .terminal-306082694-r16 { fill: #717171 } + .terminal-1605463770-r1 { fill: #1f1f1f } + .terminal-1605463770-r2 { fill: #c5c8c6 } + .terminal-1605463770-r3 { fill: #aa3731 } + .terminal-1605463770-r4 { fill: #c8837f } + .terminal-1605463770-r5 { fill: #448c27 } + .terminal-1605463770-r6 { fill: #8ab679 } + .terminal-1605463770-r7 { fill: #cb9000 } + .terminal-1605463770-r8 { fill: #dbb862 } + .terminal-1605463770-r9 { fill: #325cc0 } + .terminal-1605463770-r10 { fill: #8099d5 } + .terminal-1605463770-r11 { fill: #7a3e9d } + .terminal-1605463770-r12 { fill: #ab87c0 } + .terminal-1605463770-r13 { fill: #0083b2 } + .terminal-1605463770-r14 { fill: #62b0cc } + .terminal-1605463770-r15 { fill: #f7f7f7 } + .terminal-1605463770-r16 { fill: #f6f6f6 } + .terminal-1605463770-r17 { fill: #000000 } + .terminal-1605463770-r18 { fill: #626262 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AnsiMappingApp + AnsiMappingApp - + - - Foreground & background - red - dim red - green - dim green - yellow - dim yellow - blue - dim blue - magenta - dim magenta - cyan - dim cyan - white - dim white - black - dim black - - - - - - + + Foreground & background + red + dim red + green + dim green + yellow + dim yellow + blue + dim blue + magenta + dim magenta + cyan + dim cyan + white + dim white + black + dim black + + + + + + @@ -3330,137 +3332,136 @@ font-weight: 700; } - .terminal-174430999-matrix { + .terminal-835230732-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-174430999-title { + .terminal-835230732-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-174430999-r1 { fill: #a2a2a2 } - .terminal-174430999-r2 { fill: #c5c8c6 } - .terminal-174430999-r3 { fill: #004578 } - .terminal-174430999-r4 { fill: #e2e3e3 } - .terminal-174430999-r5 { fill: #00ff00 } - .terminal-174430999-r6 { fill: #24292f } - .terminal-174430999-r7 { fill: #1e1e1e } - .terminal-174430999-r8 { fill: #fea62b;font-weight: bold } + .terminal-835230732-r1 { fill: #a2a2a2 } + .terminal-835230732-r2 { fill: #c5c8c6 } + .terminal-835230732-r3 { fill: #004578 } + .terminal-835230732-r4 { fill: #e2e3e3 } + .terminal-835230732-r5 { fill: #00ff00 } + .terminal-835230732-r6 { fill: #1e1e1e } + .terminal-835230732-r7 { fill: #fea62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎A - - - This is a test of this code 9 - This is a test of this code 8 - This is a test of this code 7 - This is a test of this code 6 - This is a test of this code 5 - This is a test of this code 4 - This is a test of this code 3 - This is a test of this code 2 - This is a test of this code 1 - This is a test of this code 0 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎A + + + This is a test of this code 9 + This is a test of this code 8 + This is a test of this code 7 + This is a test of this code 6 + This is a test of this code 5 + This is a test of this code 4 + This is a test of this code 3 + This is a test of this code 2 + This is a test of this code 1 + This is a test of this code 0 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -3491,137 +3492,136 @@ font-weight: 700; } - .terminal-3083317776-matrix { + .terminal-956019461-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3083317776-title { + .terminal-956019461-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3083317776-r1 { fill: #a2a2a2 } - .terminal-3083317776-r2 { fill: #c5c8c6 } - .terminal-3083317776-r3 { fill: #004578 } - .terminal-3083317776-r4 { fill: #e2e3e3 } - .terminal-3083317776-r5 { fill: #00ff00 } - .terminal-3083317776-r6 { fill: #24292f } - .terminal-3083317776-r7 { fill: #1e1e1e } - .terminal-3083317776-r8 { fill: #777a7e } + .terminal-956019461-r1 { fill: #a2a2a2 } + .terminal-956019461-r2 { fill: #c5c8c6 } + .terminal-956019461-r3 { fill: #004578 } + .terminal-956019461-r4 { fill: #e2e3e3 } + .terminal-956019461-r5 { fill: #00ff00 } + .terminal-956019461-r6 { fill: #1e1e1e } + .terminal-956019461-r7 { fill: #777a7e } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎Command Palette Search... - - - This is a test of this code 0 - This is a test of this code 1 - This is a test of this code 2 - This is a test of this code 3 - This is a test of this code 4 - This is a test of this code 5 - This is a test of this code 6 - This is a test of this code 7 - This is a test of this code 8 - This is a test of this code 9 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎Command Palette Search... + + + This is a test of this code 0 + This is a test of this code 1 + This is a test of this code 2 + This is a test of this code 3 + This is a test of this code 4 + This is a test of this code 5 + This is a test of this code 6 + This is a test of this code 7 + This is a test of this code 8 + This is a test of this code 9 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + From f9a14aa7c2c3745af4d8e2dc1c863a065a11ea51 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 20 Feb 2024 17:42:17 +0000 Subject: [PATCH 10/14] Regenerate all snapshots in a single run --- src/textual/_ansi_theme.py | 4 +- src/textual/app.py | 4 +- .../__snapshots__/test_snapshots.ambr | 376 +++++++++--------- 3 files changed, 192 insertions(+), 192 deletions(-) diff --git a/src/textual/_ansi_theme.py b/src/textual/_ansi_theme.py index c7c50a2550..f53f40ca78 100644 --- a/src/textual/_ansi_theme.py +++ b/src/textual/_ansi_theme.py @@ -1,6 +1,6 @@ from rich.terminal_theme import TerminalTheme -MONOKAI_DARK = TerminalTheme( +MONOKAI = TerminalTheme( (12, 12, 12), (217, 217, 217), [ @@ -50,4 +50,4 @@ ], ) -DEFAULT_TERMINAL_THEME = MONOKAI_DARK +DEFAULT_TERMINAL_THEME = MONOKAI diff --git a/src/textual/app.py b/src/textual/app.py index d1faa70b89..42d3aa8ed3 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -71,7 +71,7 @@ ) from ._animator import DEFAULT_EASING, Animatable, Animator, EasingFunction from ._ansi_sequences import SYNC_END, SYNC_START -from ._ansi_theme import ALABASTER, MONOKAI_DARK +from ._ansi_theme import ALABASTER, MONOKAI from ._callback import invoke from ._compose import compose from ._compositor import CompositorUpdate @@ -399,7 +399,7 @@ class MyApp(App[None]): get focus when the terminal widget has focus. """ - ansi_theme_dark = Reactive(MONOKAI_DARK, init=False) + ansi_theme_dark = Reactive(MONOKAI, init=False) """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in dark mode.""" ansi_theme_light = Reactive(ALABASTER, init=False) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 14f40b9858..237dea0d44 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -184,145 +184,147 @@ font-weight: 700; } - .terminal-306082694-matrix { + .terminal-1605463770-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-306082694-title { + .terminal-1605463770-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-306082694-r1 { fill: #1f1f1f } - .terminal-306082694-r2 { fill: #c5c8c6 } - .terminal-306082694-r3 { fill: #f4005f } - .terminal-306082694-r4 { fill: #f4629b } - .terminal-306082694-r5 { fill: #98e024 } - .terminal-306082694-r6 { fill: #bde877 } - .terminal-306082694-r7 { fill: #fd971f } - .terminal-306082694-r8 { fill: #f9bc74 } - .terminal-306082694-r9 { fill: #9d65ff } - .terminal-306082694-r10 { fill: #c09efb } - .terminal-306082694-r11 { fill: #58d1eb } - .terminal-306082694-r12 { fill: #96dfef } - .terminal-306082694-r13 { fill: #c4c5b5 } - .terminal-306082694-r14 { fill: #d7d8ce } - .terminal-306082694-r15 { fill: #1a1a1a } - .terminal-306082694-r16 { fill: #717171 } + .terminal-1605463770-r1 { fill: #1f1f1f } + .terminal-1605463770-r2 { fill: #c5c8c6 } + .terminal-1605463770-r3 { fill: #aa3731 } + .terminal-1605463770-r4 { fill: #c8837f } + .terminal-1605463770-r5 { fill: #448c27 } + .terminal-1605463770-r6 { fill: #8ab679 } + .terminal-1605463770-r7 { fill: #cb9000 } + .terminal-1605463770-r8 { fill: #dbb862 } + .terminal-1605463770-r9 { fill: #325cc0 } + .terminal-1605463770-r10 { fill: #8099d5 } + .terminal-1605463770-r11 { fill: #7a3e9d } + .terminal-1605463770-r12 { fill: #ab87c0 } + .terminal-1605463770-r13 { fill: #0083b2 } + .terminal-1605463770-r14 { fill: #62b0cc } + .terminal-1605463770-r15 { fill: #f7f7f7 } + .terminal-1605463770-r16 { fill: #f6f6f6 } + .terminal-1605463770-r17 { fill: #000000 } + .terminal-1605463770-r18 { fill: #626262 } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - AnsiMappingApp + AnsiMappingApp - + - - Foreground & background - red - dim red - green - dim green - yellow - dim yellow - blue - dim blue - magenta - dim magenta - cyan - dim cyan - white - dim white - black - dim black - - - - - - + + Foreground & background + red + dim red + green + dim green + yellow + dim yellow + blue + dim blue + magenta + dim magenta + cyan + dim cyan + white + dim white + black + dim black + + + + + + @@ -3330,137 +3332,136 @@ font-weight: 700; } - .terminal-174430999-matrix { + .terminal-835230732-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-174430999-title { + .terminal-835230732-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-174430999-r1 { fill: #a2a2a2 } - .terminal-174430999-r2 { fill: #c5c8c6 } - .terminal-174430999-r3 { fill: #004578 } - .terminal-174430999-r4 { fill: #e2e3e3 } - .terminal-174430999-r5 { fill: #00ff00 } - .terminal-174430999-r6 { fill: #24292f } - .terminal-174430999-r7 { fill: #1e1e1e } - .terminal-174430999-r8 { fill: #fea62b;font-weight: bold } + .terminal-835230732-r1 { fill: #a2a2a2 } + .terminal-835230732-r2 { fill: #c5c8c6 } + .terminal-835230732-r3 { fill: #004578 } + .terminal-835230732-r4 { fill: #e2e3e3 } + .terminal-835230732-r5 { fill: #00ff00 } + .terminal-835230732-r6 { fill: #1e1e1e } + .terminal-835230732-r7 { fill: #fea62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎A - - - This is a test of this code 9 - This is a test of this code 8 - This is a test of this code 7 - This is a test of this code 6 - This is a test of this code 5 - This is a test of this code 4 - This is a test of this code 3 - This is a test of this code 2 - This is a test of this code 1 - This is a test of this code 0 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎A + + + This is a test of this code 9 + This is a test of this code 8 + This is a test of this code 7 + This is a test of this code 6 + This is a test of this code 5 + This is a test of this code 4 + This is a test of this code 3 + This is a test of this code 2 + This is a test of this code 1 + This is a test of this code 0 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -3491,137 +3492,136 @@ font-weight: 700; } - .terminal-3083317776-matrix { + .terminal-956019461-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3083317776-title { + .terminal-956019461-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-3083317776-r1 { fill: #a2a2a2 } - .terminal-3083317776-r2 { fill: #c5c8c6 } - .terminal-3083317776-r3 { fill: #004578 } - .terminal-3083317776-r4 { fill: #e2e3e3 } - .terminal-3083317776-r5 { fill: #00ff00 } - .terminal-3083317776-r6 { fill: #24292f } - .terminal-3083317776-r7 { fill: #1e1e1e } - .terminal-3083317776-r8 { fill: #777a7e } + .terminal-956019461-r1 { fill: #a2a2a2 } + .terminal-956019461-r2 { fill: #c5c8c6 } + .terminal-956019461-r3 { fill: #004578 } + .terminal-956019461-r4 { fill: #e2e3e3 } + .terminal-956019461-r5 { fill: #00ff00 } + .terminal-956019461-r6 { fill: #1e1e1e } + .terminal-956019461-r7 { fill: #777a7e } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎Command Palette Search... - - - This is a test of this code 0 - This is a test of this code 1 - This is a test of this code 2 - This is a test of this code 3 - This is a test of this code 4 - This is a test of this code 5 - This is a test of this code 6 - This is a test of this code 7 - This is a test of this code 8 - This is a test of this code 9 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎Command Palette Search... + + + This is a test of this code 0 + This is a test of this code 1 + This is a test of this code 2 + This is a test of this code 3 + This is a test of this code 4 + This is a test of this code 5 + This is a test of this code 6 + This is a test of this code 7 + This is a test of this code 8 + This is a test of this code 9 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + From 2db17278543deb76e193f11b3fba23ced0e4a09f Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Thu, 22 Feb 2024 12:36:39 +0000 Subject: [PATCH 11/14] Hardcode a color on the search icon emoji to work around test issues --- src/textual/command.py | 4 +- .../__snapshots__/test_snapshots.ambr | 238 +++++++++--------- 2 files changed, 122 insertions(+), 120 deletions(-) diff --git a/src/textual/command.py b/src/textual/command.py index 94d3aa07dc..c7c240fcaa 100644 --- a/src/textual/command.py +++ b/src/textual/command.py @@ -25,7 +25,6 @@ import rich.repr from rich.align import Align from rich.console import Group, RenderableType -from rich.emoji import Emoji from rich.style import Style from rich.text import Text from typing_extensions import Final, TypeAlias @@ -384,13 +383,14 @@ class SearchIcon(Static, inherit_css=False): DEFAULT_CSS = """ SearchIcon { + color: #000; /* required for snapshot tests */ margin-left: 1; margin-top: 1; width: 2; } """ - icon: var[str] = var(Emoji.replace(":magnifying_glass_tilted_right:")) + icon: var[str] = var("🔎") """The icon to display.""" def render(self) -> RenderableType: diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 237dea0d44..7d8cdbab98 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -3332,136 +3332,137 @@ font-weight: 700; } - .terminal-835230732-matrix { + .terminal-454793765-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-835230732-title { + .terminal-454793765-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-835230732-r1 { fill: #a2a2a2 } - .terminal-835230732-r2 { fill: #c5c8c6 } - .terminal-835230732-r3 { fill: #004578 } - .terminal-835230732-r4 { fill: #e2e3e3 } - .terminal-835230732-r5 { fill: #00ff00 } - .terminal-835230732-r6 { fill: #1e1e1e } - .terminal-835230732-r7 { fill: #fea62b;font-weight: bold } + .terminal-454793765-r1 { fill: #a2a2a2 } + .terminal-454793765-r2 { fill: #c5c8c6 } + .terminal-454793765-r3 { fill: #004578 } + .terminal-454793765-r4 { fill: #e2e3e3 } + .terminal-454793765-r5 { fill: #00ff00 } + .terminal-454793765-r6 { fill: #000000 } + .terminal-454793765-r7 { fill: #1e1e1e } + .terminal-454793765-r8 { fill: #fea62b;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎A - - - This is a test of this code 9 - This is a test of this code 8 - This is a test of this code 7 - This is a test of this code 6 - This is a test of this code 5 - This is a test of this code 4 - This is a test of this code 3 - This is a test of this code 2 - This is a test of this code 1 - This is a test of this code 0 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎A + + + This is a test of this code 9 + This is a test of this code 8 + This is a test of this code 7 + This is a test of this code 6 + This is a test of this code 5 + This is a test of this code 4 + This is a test of this code 3 + This is a test of this code 2 + This is a test of this code 1 + This is a test of this code 0 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + @@ -3492,136 +3493,137 @@ font-weight: 700; } - .terminal-956019461-matrix { + .terminal-929804574-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-956019461-title { + .terminal-929804574-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-956019461-r1 { fill: #a2a2a2 } - .terminal-956019461-r2 { fill: #c5c8c6 } - .terminal-956019461-r3 { fill: #004578 } - .terminal-956019461-r4 { fill: #e2e3e3 } - .terminal-956019461-r5 { fill: #00ff00 } - .terminal-956019461-r6 { fill: #1e1e1e } - .terminal-956019461-r7 { fill: #777a7e } + .terminal-929804574-r1 { fill: #a2a2a2 } + .terminal-929804574-r2 { fill: #c5c8c6 } + .terminal-929804574-r3 { fill: #004578 } + .terminal-929804574-r4 { fill: #e2e3e3 } + .terminal-929804574-r5 { fill: #00ff00 } + .terminal-929804574-r6 { fill: #000000 } + .terminal-929804574-r7 { fill: #1e1e1e } + .terminal-929804574-r8 { fill: #777a7e } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - CommandPaletteApp + CommandPaletteApp - + - - - - - ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - - 🔎Command Palette Search... - - - This is a test of this code 0 - This is a test of this code 1 - This is a test of this code 2 - This is a test of this code 3 - This is a test of this code 4 - This is a test of this code 5 - This is a test of this code 6 - This is a test of this code 7 - This is a test of this code 8 - This is a test of this code 9 - ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ - - - - + + + + + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + + 🔎Command Palette Search... + + + This is a test of this code 0 + This is a test of this code 1 + This is a test of this code 2 + This is a test of this code 3 + This is a test of this code 4 + This is a test of this code 5 + This is a test of this code 6 + This is a test of this code 7 + This is a test of this code 8 + This is a test of this code 9 + ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ + + + + From a416cf974483ef7b46679136ba12b3ef7c1a9bb1 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Mon, 26 Feb 2024 18:38:06 +0000 Subject: [PATCH 12/14] Alternative approach --- src/textual/app.py | 27 ++++++++++++++++++++++----- src/textual/filter.py | 21 ++------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index 42d3aa8ed3..6edbe23278 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -430,8 +430,7 @@ def __init__( self.features: frozenset[FeatureFlag] = parse_features(os.getenv("TEXTUAL", "")) ansi_theme = self.ansi_theme_dark if self.dark else self.ansi_theme_light - self._truecolor_filter = ANSIToTruecolor(ansi_theme) - self._filters: list[LineFilter] = [self._truecolor_filter] + self._filters: list[LineFilter] = [ANSIToTruecolor(ansi_theme)] environ = dict(os.environ) no_color = environ.pop("NO_COLOR", None) @@ -888,17 +887,17 @@ def watch_dark(self, dark: bool) -> None: """ self.set_class(dark, "-dark-mode", update=False) self.set_class(not dark, "-light-mode", update=False) - self._truecolor_filter.theme = self.ansi_theme + self._refresh_truecolor_filter(self.ansi_theme) self.call_later(self.refresh_css) def watch_ansi_theme_dark(self, theme: TerminalTheme) -> None: if self.dark: - self._truecolor_filter.theme = theme + self._refresh_truecolor_filter(theme) self.call_later(self.refresh_css) def watch_ansi_theme_light(self, theme: TerminalTheme) -> None: if not self.dark: - self._truecolor_filter.theme = theme + self._refresh_truecolor_filter(theme) self.call_later(self.refresh_css) @property @@ -910,6 +909,24 @@ def ansi_theme(self) -> TerminalTheme: """ return self.ansi_theme_dark if self.dark else self.ansi_theme_light + def _refresh_truecolor_filter(self, theme: TerminalTheme) -> None: + """Update the ANSI to Truecolor filter, if available, with a new theme mapping. + + Args: + theme: The new terminal theme to use for mapping ANSI to truecolor. + """ + filters = self._filters + target_index = -1 + for index, filter in enumerate(filters): + if isinstance(filter, ANSIToTruecolor): + target_index = index + break + + if target_index == -1: + return + + filters[target_index] = ANSIToTruecolor(theme) + def get_driver_class(self) -> Type[Driver]: """Get a driver class for this platform. diff --git a/src/textual/filter.py b/src/textual/filter.py index 9b3639ee8f..2963689ebd 100644 --- a/src/textual/filter.py +++ b/src/textual/filter.py @@ -21,8 +21,6 @@ from rich.style import Style from rich.terminal_theme import TerminalTheme -from textual.cache import LRUCache - from .color import Color @@ -191,17 +189,8 @@ def __init__(self, terminal_theme: TerminalTheme): terminal_theme: A rich terminal theme. """ self._terminal_theme = terminal_theme - self._truecolor_cache: LRUCache[Style, Style] = LRUCache(maxsize=1024) - - @property - def theme(self) -> TerminalTheme: - return self._terminal_theme - - @theme.setter - def theme(self, theme: TerminalTheme) -> None: - self._truecolor_cache.clear() - self._terminal_theme = theme + @lru_cache(1024) def truecolor_style(self, style: Style) -> Style: """Replace system colors with truecolor equivalent. @@ -211,10 +200,6 @@ def truecolor_style(self, style: Style) -> Style: Returns: New style. """ - cache = self._truecolor_cache - if style in cache: - return cache[style] - terminal_theme = self._terminal_theme color = style.color if color is not None and color.is_system_defined: @@ -227,9 +212,7 @@ def truecolor_style(self, style: Style) -> Style: *bgcolor.get_truecolor(terminal_theme, foreground=False) ) - truecolor_style = style + Style.from_color(color, bgcolor) - cache[style] = truecolor_style - return truecolor_style + return style + Style.from_color(color, bgcolor) def apply(self, segments: list[Segment], background: Color) -> list[Segment]: """Transform a list of segments. From 642c42f3beead7b08ba16bbec41cdcfb2855f2ca Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Mon, 26 Feb 2024 19:59:56 +0000 Subject: [PATCH 13/14] snapshot update --- .../__snapshots__/test_snapshots.ambr | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index 92a332734d..efefa50e4a 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -27759,67 +27759,67 @@ font-weight: 700; } - .terminal-4031343223-matrix { + .terminal-2341104189-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-4031343223-title { + .terminal-2341104189-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-4031343223-r1 { fill: #ffdddd;font-weight: bold } - .terminal-4031343223-r2 { fill: #879a3b } - .terminal-4031343223-r3 { fill: #ddeedd } - .terminal-4031343223-r4 { fill: #c5c8c6 } - .terminal-4031343223-r5 { fill: #ddddff } - .terminal-4031343223-r6 { fill: #e1e1e1 } + .terminal-2341104189-r1 { fill: #ffdddd;font-weight: bold } + .terminal-2341104189-r2 { fill: #98e024 } + .terminal-2341104189-r3 { fill: #ddeedd } + .terminal-2341104189-r4 { fill: #c5c8c6 } + .terminal-2341104189-r5 { fill: #ddddff } + .terminal-2341104189-r6 { fill: #e1e1e1 } - + - + - + - + - + - + - + - MyApp + MyApp - + - - ['This is a string that has some chars'] - - This should be 1 cell away from ^ - - - + + ['This is a string that has some chars'] + + This should be 1 cell away from ^ + + + From cc3e8329cc2fd7a8ad6e80f52bc691d94581d345 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Tue, 27 Feb 2024 10:14:20 +0000 Subject: [PATCH 14/14] Simplify a loop in app.py --- src/textual/app.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/textual/app.py b/src/textual/app.py index 6edbe23278..8e19385315 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -916,16 +916,10 @@ def _refresh_truecolor_filter(self, theme: TerminalTheme) -> None: theme: The new terminal theme to use for mapping ANSI to truecolor. """ filters = self._filters - target_index = -1 for index, filter in enumerate(filters): if isinstance(filter, ANSIToTruecolor): - target_index = index - break - - if target_index == -1: - return - - filters[target_index] = ANSIToTruecolor(theme) + filters[index] = ANSIToTruecolor(theme) + return def get_driver_class(self) -> Type[Driver]: """Get a driver class for this platform.