From e5be2f033215aebc7a086772a9eefe203cc28849 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 31 May 2025 16:19:20 +0100 Subject: [PATCH 1/3] fix markup, added features to markup playground --- src/textual/_markup_playground.py | 60 ++++++++++++++++++++++--------- src/textual/markup.py | 11 +++--- tests/test_markup.py | 7 ++++ 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/textual/_markup_playground.py b/src/textual/_markup_playground.py index 720e2d68d4..88a6522655 100644 --- a/src/textual/_markup_playground.py +++ b/src/textual/_markup_playground.py @@ -4,21 +4,17 @@ from textual.app import App, ComposeResult from textual.content import Content from textual.reactive import reactive -from textual.widgets import Static, TextArea +from textual.widgets import Footer, Pretty, Static, TextArea class MarkupPlayground(App): TITLE = "Markup Playground" CSS = """ - Screen { - & > * { - margin: 0 1; - height: 1fr; - } + Screen { layout: vertical; #editor { - width: 2fr; + width: 1fr; height: 1fr; border: tab $foreground 50%; padding: 1; @@ -33,7 +29,7 @@ class MarkupPlayground(App): height: 1fr; border: tab $foreground 50%; padding: 1; - margin: 1 0 0 1; + margin: 1 1 0 1; &:focus { border: tab $primary; } @@ -48,16 +44,35 @@ class MarkupPlayground(App): } overflow-y: auto; } - #results { - + #results { padding: 1 1; + width: 1fr; + } + #spans-container { + border: tab $success; + overflow-y: auto; + margin: 0 1; + } + #spans { + padding: 1 1; + width: 1fr; + } + HorizontalGroup { + height: 1fr; } } """ AUTO_FOCUS = "#editor" + BINDINGS = [ + ("f1", "toggle('show_variables')", "Variables"), + ("f2", "toggle('show_spans')", "Spans"), + ] variables: reactive[dict[str, object]] = reactive({}) + show_variables = reactive(False) + show_spans = reactive(False) + def compose(self) -> ComposeResult: with containers.HorizontalGroup(): yield (editor := TextArea(id="editor")) @@ -65,11 +80,21 @@ def compose(self) -> ComposeResult: editor.border_title = "Markup" variables.border_title = "Variables (JSON)" - with containers.VerticalScroll( - id="results-container", can_focus=False - ) as container: - yield Static(id="results") - container.border_title = "Output" + with containers.HorizontalGroup(): + with containers.VerticalScroll(id="results-container") as container: + yield Static(id="results") + container.border_title = "Output" + with containers.VerticalScroll(id="spans-container") as container: + yield Pretty([], id="spans") + container.border_title = "Spans" + + yield Footer() + + def watch_show_variables(self, show_variables: bool) -> None: + self.query_one("#variables").display = show_variables + + def watch_show_spans(self, show_spans: bool) -> None: + self.query_one("#spans-container").display = show_spans @on(TextArea.Changed, "#editor") def on_markup_changed(self, event: TextArea.Changed) -> None: @@ -78,13 +103,16 @@ def on_markup_changed(self, event: TextArea.Changed) -> None: def update_markup(self) -> None: results = self.query_one("#results", Static) editor = self.query_one("#editor", TextArea) + spans = self.query_one("#spans", Pretty) try: content = Content.from_markup(editor.text, **self.variables) results.update(content) - except Exception as error: + spans.update(content.spans) + except Exception: from rich.traceback import Traceback results.update(Traceback()) + spans.update([]) self.query_one("#results-container").add_class("-error").scroll_end( animate=False diff --git a/src/textual/markup.py b/src/textual/markup.py index 2d92ae7353..06a0effd98 100644 --- a/src/textual/markup.py +++ b/src/textual/markup.py @@ -411,14 +411,13 @@ def process_text(template_text: str, /) -> str: content_text = "".join(text) text_length = len(content_text) - while style_stack: - position, tag_body, _ = style_stack.pop() + for position, tag_body, _ in style_stack: spans.append(Span(position, text_length, tag_body)) - if style: - content = Content(content_text, [Span(0, len(content_text), style), *spans]) - else: - content = Content(content_text, spans) + content = Content( + content_text, + [Span(0, len(content_text), style), *spans] if style else spans, + ) return content diff --git a/tests/test_markup.py b/tests/test_markup.py index 32032bf5bd..ebbd9aee1e 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -77,6 +77,13 @@ ], ), ), + ( + "[#ff0000]Hello, [#ffffff]world!\nMy work here is done.", + Content( + "Hello, world!\nMy work here is done.", + spans=[Span(1, 37, style="#ff0000"), Span(8, 37, style="#ffffff")], + ), + ), ], ) def test_to_content(markup: str, content: Content): From 8caf12d89ef73fa26dc60b832e361028026103a3 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 31 May 2025 16:28:58 +0100 Subject: [PATCH 2/3] style update --- src/textual/_markup_playground.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/textual/_markup_playground.py b/src/textual/_markup_playground.py index 88a6522655..5005016111 100644 --- a/src/textual/_markup_playground.py +++ b/src/textual/_markup_playground.py @@ -18,7 +18,7 @@ class MarkupPlayground(App): height: 1fr; border: tab $foreground 50%; padding: 1; - margin: 1 1 0 0; + margin: 1 0 0 0; &:focus { border: tab $primary; } @@ -29,7 +29,7 @@ class MarkupPlayground(App): height: 1fr; border: tab $foreground 50%; padding: 1; - margin: 1 1 0 1; + margin: 1 0 0 1; &:focus { border: tab $primary; } @@ -51,7 +51,7 @@ class MarkupPlayground(App): #spans-container { border: tab $success; overflow-y: auto; - margin: 0 1; + margin: 0 0 0 1; } #spans { padding: 1 1; From 2a7d586c2e2ee9f9c55026e926444c812bdfd2c2 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Sat, 31 May 2025 16:51:13 +0100 Subject: [PATCH 3/3] test fix --- tests/test_markup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_markup.py b/tests/test_markup.py index ebbd9aee1e..718c61752c 100644 --- a/tests/test_markup.py +++ b/tests/test_markup.py @@ -81,7 +81,7 @@ "[#ff0000]Hello, [#ffffff]world!\nMy work here is done.", Content( "Hello, world!\nMy work here is done.", - spans=[Span(1, 37, style="#ff0000"), Span(8, 37, style="#ffffff")], + spans=[Span(0, 35, style="#ff0000"), Span(7, 35, style="#ffffff")], ), ), ],