From 53dca5dbba8ee162fa3588ab0503df6f3fbf4efb Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 10 Jan 2025 12:05:40 +0000 Subject: [PATCH 1/2] fix markup false --- src/textual/visual.py | 6 +- src/textual/widgets/_static.py | 4 +- .../test_snapshots/test_static_markup.svg | 151 ++++++++++++++++++ tests/snapshot_tests/test_snapshots.py | 15 ++ 4 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg diff --git a/src/textual/visual.py b/src/textual/visual.py index 4b457f173d..c6de6d680c 100644 --- a/src/textual/visual.py +++ b/src/textual/visual.py @@ -60,14 +60,16 @@ class VisualError(Exception): VisualType: TypeAlias = "RenderableType | SupportsVisual | Visual" -def visualize(widget: Widget, obj: object) -> Visual: +def visualize(widget: Widget, obj: object, markup: bool = True) -> Visual: """Get a visual instance from an object. If the object does not support the Visual protocol and is a Rich renderable, it will be wrapped in a [RichVisual][textual.visual.RichVisual]. Args: + widget: The parent widget. obj: An object. + markup: Enable markup. Returns: A Visual instance to render the object, or `None` if there is no associated visual. @@ -84,7 +86,7 @@ def visualize(widget: Widget, obj: object) -> Visual: if is_renderable(obj): # If it is a string, render it to Text if isinstance(obj, str): - obj = widget.render_str(obj) + obj = widget.render_str(obj) if markup else Text(obj) if isinstance(obj, Text) and widget.allow_select: return Content.from_rich_text( diff --git a/src/textual/widgets/_static.py b/src/textual/widgets/_static.py index 1872f6623f..607c57c499 100644 --- a/src/textual/widgets/_static.py +++ b/src/textual/widgets/_static.py @@ -74,7 +74,7 @@ def __init__( @property def visual(self) -> Visual: if self._visual is None: - self._visual = visualize(self, self._content) + self._visual = visualize(self, self._content, markup=self.markup) return self._visual @property @@ -109,5 +109,5 @@ def update(self, content: RenderableType | SupportsVisual = "") -> None: """ self._content = content - self._visual = visualize(self, content) + self._visual = visualize(self, content, markup=self.markup) self.refresh(layout=True) diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg new file mode 100644 index 0000000000..729491bf18 --- /dev/null +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LabelApp + + + + + + + + + + This allows markup +This does not allow [bold]markup[/bold] + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 878da6a45d..91ffb80a79 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -3311,3 +3311,18 @@ def compose(self) -> ComposeResult: yield Static("\n".join(f"This is some text {n}" for n in range(100))) assert snap_compare(ScrollbarOpacityApp()) + + +def test_static_markup(snap_compare): + """Check that markup may be disabled. + + You should see two labels, the first uses markup. + The second has markup disabled, and tags should be visible. + """ + + class LabelApp(App): + def compose(self) -> ComposeResult: + yield Label("This allows [bold]markup[/bold]") + yield Label("This does not allow [bold]markup[/bold]", markup=False) + + snap_compare(LabelApp()) From d3fedb9bffef6101980fa2bf54878b420969804d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Fri, 10 Jan 2025 12:20:16 +0000 Subject: [PATCH 2/2] invalid tag case --- src/textual/content.py | 10 +- .../test_snapshots/test_static_markup.svg | 112 +++++++++--------- tests/snapshot_tests/test_snapshots.py | 8 +- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/src/textual/content.py b/src/textual/content.py index c6da265f8c..1aa943ed98 100644 --- a/src/textual/content.py +++ b/src/textual/content.py @@ -19,6 +19,7 @@ from rich._wrap import divide_line from rich.cells import set_cell_size from rich.console import OverflowMethod +from rich.errors import MissingStyle from rich.segment import Segment, Segments from rich.terminal_theme import TerminalTheme from rich.text import Text @@ -744,9 +745,12 @@ def render( @lru_cache(maxsize=1024) def get_style(style: str, /) -> Style: - visual_style = Style.from_rich_style( - app.console.get_style(style), app.ansi_theme - ) + try: + visual_style = Style.from_rich_style( + app.console.get_style(style), app.ansi_theme + ) + except MissingStyle: + visual_style = Style() return visual_style else: diff --git a/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg b/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg index 729491bf18..0ca9a31e19 100644 --- a/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg +++ b/tests/snapshot_tests/__snapshots__/test_snapshots/test_static_markup.svg @@ -19,132 +19,132 @@ font-weight: 700; } - .terminal-193165944-matrix { + .terminal-1106774111-matrix { font-family: Fira Code, monospace; font-size: 20px; line-height: 24.4px; font-variant-east-asian: full-width; } - .terminal-193165944-title { + .terminal-1106774111-title { font-size: 18px; font-weight: bold; font-family: arial; } - .terminal-193165944-r1 { fill: #e0e0e0 } -.terminal-193165944-r2 { fill: #e0e0e0;font-weight: bold } -.terminal-193165944-r3 { fill: #c5c8c6 } + .terminal-1106774111-r1 { fill: #e0e0e0 } +.terminal-1106774111-r2 { fill: #c5c8c6 } +.terminal-1106774111-r3 { fill: #e0e0e0;font-weight: bold } - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - LabelApp + LabelApp - - - - This allows markup -This does not allow [bold]markup[/bold] - - - - - - - - - - - - - - - - - - - - - + + + + There should be no tags or style +This allows markup +This does not allow [bold]markup[/bold] + + + + + + + + + + + + + + + + + + + + diff --git a/tests/snapshot_tests/test_snapshots.py b/tests/snapshot_tests/test_snapshots.py index 91ffb80a79..43b565b3f6 100644 --- a/tests/snapshot_tests/test_snapshots.py +++ b/tests/snapshot_tests/test_snapshots.py @@ -3316,12 +3316,16 @@ def compose(self) -> ComposeResult: def test_static_markup(snap_compare): """Check that markup may be disabled. - You should see two labels, the first uses markup. - The second has markup disabled, and tags should be visible. + You should see 3 labels. + + This first label contains an invalid style, and should have tags removed. + The second label should have the word "markup" boldened. + The third label has markup disabled, and should show tags without styles. """ class LabelApp(App): def compose(self) -> ComposeResult: + yield Label("There should be no [foo]tags or style[/foo]") yield Label("This allows [bold]markup[/bold]") yield Label("This does not allow [bold]markup[/bold]", markup=False)