Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/textual/markup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from __future__ import annotations

from operator import itemgetter

from textual.css.parse import substitute_references
from textual.css.tokenizer import UnexpectedEnd

Expand Down Expand Up @@ -407,16 +409,25 @@ def process_text(template_text: str, /) -> str:
if not style_stack:
raise MarkupError("auto closing tag ('[/]') has nothing to close")
open_position, tag_body, _ = style_stack.pop()
spans.append(Span(open_position, position, tag_body))
if open_position != position:
spans.append(Span(open_position, position, tag_body))

content_text = "".join(text)
text_length = len(content_text)
for position, tag_body, _ in style_stack:
spans.append(Span(position, text_length, tag_body))
if style_stack and text_length:
spans.extend(
[
Span(position, text_length, tag_body)
for position, tag_body, _ in reversed(style_stack)
if position != text_length
]
)
spans.reverse()
spans.sort(key=itemgetter(0)) # Zeroth item of Span is 'start' attribute

content = Content(
content_text,
[Span(0, len(content_text), style), *spans] if style else spans,
[Span(0, text_length, style), *spans] if (style and text_length) else spans,
)

return content
Expand Down
60 changes: 59 additions & 1 deletion tests/test_markup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
Content(
"What is up with you?",
spans=[
Span(0, 20, style="b"),
Span(0, 10, style="on red"),
Span(5, 20, style="i"),
Span(0, 20, style="b"),
],
),
),
Expand Down Expand Up @@ -84,6 +84,64 @@
spans=[Span(0, 35, style="#ff0000"), Span(7, 35, style="#ffffff")],
),
),
(
"[blue][green][red]R[/red]G[/green]B[/blue]",
Content(
"RGB",
spans=[
Span(0, 3, "blue"),
Span(0, 2, "green"),
Span(0, 1, "red"),
],
),
),
(
"[red][blue]X[/blue][/red]",
Content(
"X",
spans=[
Span(0, 1, "red"),
Span(0, 1, "blue"),
],
),
),
# Non-nested tags
(
"[red][blue]X[/red][/blue]",
Content(
"X",
spans=[
Span(0, 1, "blue"),
Span(0, 1, "red"),
],
),
),
(
"[red][blue]X[/red]",
Content(
"X",
spans=[
Span(0, 1, "blue"),
Span(0, 1, "red"),
],
),
),
(
"[red][blue]X",
Content(
"X",
spans=[
Span(0, 1, "red"),
Span(0, 1, "blue"),
],
),
),
# Edge cases
("[bold][/bold]", Content("")),
("[bold][/]", Content("")),
("[bold]", Content("")),
("", Content("")),
("[red][green][/red]", Content("")),
],
)
def test_to_content(markup: str, content: Content):
Expand Down
Loading