diff --git a/CHANGELOG.md b/CHANGELOG.md index 3acf68510d..30dc481d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ 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 + ### Fixed - Fixed `TextArea.code_editor` missing recently added attributes https://github.com/Textualize/textual/pull/4172 diff --git a/src/textual/_ansi_theme.py b/src/textual/_ansi_theme.py new file mode 100644 index 0000000000..f53f40ca78 --- /dev/null +++ b/src/textual/_ansi_theme.py @@ -0,0 +1,53 @@ +from rich.terminal_theme import TerminalTheme + +MONOKAI = 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), + ], +) + +ALABASTER = TerminalTheme( + (247, 247, 247), + (0, 0, 0), + [ + (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), + ], + [ + (240, 80, 80), + (96, 203, 0), + (255, 188, 93), + (0, 122, 204), + (230, 76, 230), + (0, 170, 203), + (247, 247, 247), + ], +) + +DEFAULT_TERMINAL_THEME = MONOKAI diff --git a/src/textual/_styles_cache.py b/src/textual/_styles_cache.py index 6e6366113e..9d4888e292 100644 --- a/src/textual/_styles_cache.py +++ b/src/textual/_styles_cache.py @@ -10,7 +10,9 @@ 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 ._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 08c4392fbe..8e19385315 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -52,11 +52,11 @@ 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 from rich.segment import Segment, Segments +from rich.terminal_theme import TerminalTheme from . import ( Logger, @@ -71,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 from ._callback import invoke from ._compose import compose from ._compositor import CompositorUpdate @@ -398,6 +399,12 @@ class MyApp(App[None]): get focus when the terminal widget has focus. """ + 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) + """Maps ANSI colors to hex colors using a Rich TerminalTheme object while in light mode.""" + def __init__( self, driver_class: Type[Driver] | None = None, @@ -422,9 +429,9 @@ 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._filters: list[LineFilter] = [ANSIToTruecolor(ansi_theme)] + environ = dict(os.environ) no_color = environ.pop("NO_COLOR", None) if no_color is not None: @@ -880,8 +887,40 @@ 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._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._refresh_truecolor_filter(theme) + self.call_later(self.refresh_css) + + def watch_ansi_theme_light(self, theme: TerminalTheme) -> None: + if not self.dark: + self._refresh_truecolor_filter(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 _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 + for index, filter in enumerate(filters): + if isinstance(filter, ANSIToTruecolor): + filters[index] = ANSIToTruecolor(theme) + return + def get_driver_class(self) -> Type[Driver]: """Get a driver class for this platform. 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/src/textual/filter.py b/src/textual/filter.py index 7494d9a52a..2963689ebd 100644 --- a/src/textual/filter.py +++ b/src/textual/filter.py @@ -188,7 +188,7 @@ def __init__(self, terminal_theme: TerminalTheme): Args: terminal_theme: A rich terminal theme. """ - self.terminal_theme = terminal_theme + self._terminal_theme = terminal_theme @lru_cache(1024) def truecolor_style(self, style: Style) -> Style: @@ -200,7 +200,7 @@ def truecolor_style(self, style: Style) -> Style: Returns: New style. """ - terminal_theme = self.terminal_theme + terminal_theme = self._terminal_theme color = style.color if color is not None and color.is_system_defined: color = RichColor.from_rgb( @@ -211,6 +211,7 @@ 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) def apply(self, segments: list[Segment], background: Color) -> list[Segment]: diff --git a/src/textual/renderables/tint.py b/src/textual/renderables/tint.py index 358bbca3fc..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,7 +46,7 @@ def process_segments( style_from_color = Style.from_color _Segment = Segment - truecolor_style = ANSIToTruecolor(terminal_theme.DIMMED_MONOKAI).truecolor_style + truecolor_style = ANSIToTruecolor(ansi_theme).truecolor_style NULL_STYLE = Style() for segment in segments: @@ -73,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/snapshot_tests/__snapshots__/test_snapshots.ambr b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr index b6f4122b2f..efefa50e4a 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots.ambr +++ b/tests/snapshot_tests/__snapshots__/test_snapshots.ambr @@ -161,6 +161,346 @@ ''' # --- +# name: test_ansi_color_mapping[False] + ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + + ''' +# --- +# 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 + + + + + + + + + + + + ''' +# --- # name: test_auto_fr ''' @@ -1872,144 +2212,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โ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž - โ–Šโ–Xโ–ŒGiedi Primeโ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž - โ–Šโ–Xโ–ŒGinazโ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž - โ–Šโ–Xโ–Œ Grummanโ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–ƒโ–ƒ - โ–Šโ–Xโ–ŒKaitainโ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + + + + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–Œ Arrakis ๐Ÿ˜“โ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–Œ Caladanโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–Œ Chusukโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–ŒGiedi Primeโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–ŒGinazโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–Šโ–Xโ–Œ Grummanโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–ƒโ–ƒ + โ–Šโ–Xโ–ŒKaitainโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž @@ -2992,137 +3332,137 @@ font-weight: 700; } - .terminal-174430999-matrix { + .terminal-454793765-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-174430999-title { + .terminal-454793765-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-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 + โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ– + + + + @@ -3153,137 +3493,137 @@ font-weight: 700; } - .terminal-3083317776-matrix { + .terminal-929804574-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-3083317776-title { + .terminal-929804574-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-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 + โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ– + + + + @@ -5008,141 +5348,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 titleโ–•โ•ญโ”€Lefโ€ฆโ”€โ•ฎโ–โ–โ–โ–โ–Leftโ–โ–โ–โ–โ– - โ–This is the story ofโ–•โ”‚a Pythonโ”‚โ–Ždeveloper thatโ–Š - โ–Border subtitleโ–•โ•ฐโ”€Cenโ€ฆโ”€โ•ฏโ–”โ–”โ–”โ–”โ–”@@@โ–”โ–”โ–”โ–”โ–”โ–” - - - - - - +--------------+โ”€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 titleโ–•โ•ญโ”€Lefโ€ฆโ”€โ•ฎโ–โ–โ–โ–โ–Leftโ–โ–โ–โ–โ– + โ–This is the story ofโ–•โ”‚a Pythonโ”‚โ–Ždeveloper thatโ–Š + โ–Border subtitleโ–•โ•ฐโ”€Cenโ€ฆโ”€โ•ฏโ–”โ–”โ–”โ–”โ–”@@@โ–”โ–”โ–”โ–”โ–”โ–” + + + + + + +--------------+โ”€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โ€ฆโ”€ + @@ -16416,137 +16756,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 @@ -25542,138 +25882,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 - + - - โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž - โ–ŠOneโ–Žโ–ŠOneโ–Žโ–ŠOneโ–Ž - โ–ŠTwoโ–Žโ–ŠTwoโ–Žโ–ŠTwoโ–Ž - โ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Žโ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Žโ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Ž - โ–ŠThreeโ–Žโ–ŠThreeโ–Žโ–ŠThreeโ–Ž - โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Žโ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Žโ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž - - - - - - - - - - - - - - - - - + + โ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Žโ–Šโ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–”โ–Ž + โ–ŠOneโ–Žโ–ŠOneโ–Žโ–ŠOneโ–Ž + โ–ŠTwoโ–Žโ–ŠTwoโ–Žโ–ŠTwoโ–Ž + โ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Žโ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Žโ–Šโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–Ž + โ–ŠThreeโ–Žโ–ŠThreeโ–Žโ–ŠThreeโ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Žโ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Žโ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + + + + + + + + + + + + + + + + + @@ -27419,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 ^ + + + @@ -29101,140 +29441,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โ–Ž + โ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Žโ–Šโ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–โ–Ž + + + + + + @@ -30528,137 +30868,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<<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚โ–‡โ–‡ + โ”‚โ”‚โ”‚โ–„โ–„โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚โ”‚ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ @@ -32133,141 +32473,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 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” - โ”‚โ”‚โ”‚[โ”‚ - โ”‚โ–Xโ–ŒFalken's Mazeโ”‚โ”‚'secret_back_door',โ”‚ - โ”‚โ–Xโ–ŒBlack Jackโ”‚โ”‚'a_nice_game_of_chess',โ”‚ - โ”‚โ–Xโ–ŒGin Rummyโ”‚โ”‚'fighter_combat'โ”‚ - โ”‚โ–Xโ–ŒHeartsโ”‚โ”‚]โ”‚ - โ”‚โ–Xโ–ŒBridgeโ”‚โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - โ”‚โ–Xโ–ŒCheckersโ”‚ - โ”‚โ–Xโ–ŒChessโ”‚ - โ”‚โ–Xโ–ŒPokerโ”‚ - โ”‚โ–Xโ–ŒFighter Combatโ”‚ - โ”‚โ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - - - - - + + โญ˜SelectionListApp + + + โ”Œโ”€ Shall we play some games? โ”€โ”€โ”โ”Œโ”€ Selected games โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚โ”‚โ”‚[โ”‚ + โ”‚โ–Xโ–ŒFalken's Mazeโ”‚โ”‚'secret_back_door',โ”‚ + โ”‚โ–Xโ–ŒBlack Jackโ”‚โ”‚'a_nice_game_of_chess',โ”‚ + โ”‚โ–Xโ–ŒGin Rummyโ”‚โ”‚'fighter_combat'โ”‚ + โ”‚โ–Xโ–ŒHeartsโ”‚โ”‚]โ”‚ + โ”‚โ–Xโ–ŒBridgeโ”‚โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚โ–Xโ–ŒCheckersโ”‚ + โ”‚โ–Xโ–ŒChessโ”‚ + โ”‚โ–Xโ–ŒPokerโ”‚ + โ”‚โ–Xโ–ŒFighter Combatโ”‚ + โ”‚โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + + + + + @@ -34218,136 +34558,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 - + - - โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ - โ”ƒFooโ”ƒBar   โ”ƒbaz      โ”ƒ - โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ - โ”‚Hello World!โ”‚Italicโ”‚Underlineโ”‚ - โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - - - - - - - - - - - - - - - - - + + โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ + โ”ƒFooโ”ƒBar   โ”ƒbaz      โ”ƒ + โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ + โ”‚Hello World!โ”‚Italicโ”‚Underlineโ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + + + + + + + + + + + + + + + + + + @@ -39019,146 +39359,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 new file mode 100644 index 0000000000..05e4669cd2 --- /dev/null +++ b/tests/snapshot_tests/snapshot_apps/ansi_mapping.py @@ -0,0 +1,25 @@ +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("[fg on bg]Foreground & background[/]") + for color in ansi_colors: + yield Label(f"[{color}]{color}[/]") + yield Label(f"[dim {color}]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 00fedf3e0b..ece28e9cb2 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -1068,6 +1068,16 @@ def test_input_percentage_width(snap_compare): assert snap_compare(SNAPSHOT_APPS_DIR / "input_percentage_width.py") +@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.""" + + def setup(pilot): + pilot.app.dark = dark + + assert snap_compare(SNAPSHOT_APPS_DIR / "ansi_mapping.py", run_before=setup) + + def test_pretty_grid_gutter_interaction(snap_compare): """Regression test for https://github.com/Textualize/textual/pull/4219.""" assert snap_compare( 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