diff --git a/src/textual/content.py b/src/textual/content.py index 490ec2011e..6c4d24ca15 100644 --- a/src/textual/content.py +++ b/src/textual/content.py @@ -334,10 +334,7 @@ def styled( """ if not text: return Content("") - span_length = cell_len(text) if cell_length is None else cell_length - new_content = cls( - text, [Span(0, span_length, style)] if style else None, span_length - ) + new_content = cls(text, [Span(0, len(text), style)] if style else None) return new_content @classmethod @@ -844,6 +841,8 @@ def iter_content() -> Iterable[Content]: total_cell_length: int | None = self._cell_length for content in iter_content(): + if not content: + continue extend_text(content._text) extend_spans( _Span(offset + start, offset + end, style) @@ -1437,6 +1436,9 @@ def expand_tabs(self, tab_size: int = 8) -> Content: if "\t" not in self.plain: return self + if not self._spans: + return Content(self.plain.expandtabs(tab_size)) + new_text: list[Content] = [] append = new_text.append @@ -1449,7 +1451,7 @@ def expand_tabs(self, tab_size: int = 8) -> Content: for part in parts: if part.plain.endswith("\t"): part = Content( - part._text[-1][:-1] + " ", part._spans, part._cell_length + part._text[:-1] + " ", part._spans, part._cell_length ) cell_position += part.cell_length tab_remainder = cell_position % tab_size diff --git a/src/textual/style.py b/src/textual/style.py index 43c4be0920..1a96b8102f 100644 --- a/src/textual/style.py +++ b/src/textual/style.py @@ -41,7 +41,7 @@ ) -@rich.repr.auto(angular=True) +@rich.repr.auto() @dataclass(frozen=True) class Style: """Represents a style in the Visual interface (color and other attributes). diff --git a/tests/test_content.py b/tests/test_content.py index c5034054c7..1ca13423bd 100644 --- a/tests/test_content.py +++ b/tests/test_content.py @@ -294,3 +294,47 @@ def test_simplify(): assert content.spans == [Span(0, 3, "bold"), Span(3, 6, "bold")] content.simplify() assert content.spans == [Span(0, 6, "bold")] + + +@pytest.mark.parametrize( + ["input", "tab_width", "expected"], + [ + (Content(""), 8, Content("")), + (Content("H"), 8, Content("H")), + (Content("Hello"), 8, Content("Hello")), + (Content("\t"), 8, Content(" " * 8)), + (Content("A\t"), 8, Content("A" + " " * 7)), + (Content("ABCD\t"), 8, Content("ABCD" + " " * 4)), + (Content("ABCDEFG\t"), 8, Content("ABCDEFG ")), + (Content("ABCDEFGH\t"), 8, Content("ABCDEFGH" + " " * 8)), + (Content("Hel\tlo!"), 4, Content("Hel lo!")), + (Content("\t\t"), 4, Content(" " * 8)), + (Content("FO\t\t"), 4, Content("FO ")), + (Content("FO\tOB\t"), 4, Content("FO OB ")), + ( + Content("FOO", spans=[Span(0, 3, "red")]), + 4, + Content("FOO", spans=[Span(0, 3, "red")]), + ), + ( + Content("FOO\tBAR", spans=[Span(0, 3, "red")]), + 8, + Content("FOO BAR", spans=[Span(0, 3, "red")]), + ), + ( + Content("FOO\tBAR", spans=[Span(0, 3, "red"), Span(4, 8, "blue")]), + 8, + Content("FOO BAR", spans=[Span(0, 3, "red"), Span(8, 11, "blue")]), + ), + ( + Content("foo\tbar\nbaz", spans=[Span(0, 11, "red")]), + 8, + Content("foo bar\nbaz", spans=[Span(0, 15, "red")]), + ), + ], +) +def test_expand_tabs(input: Content, tab_width: int, expected: Content): + output = input.expand_tabs(tab_width).simplify() + print(repr(output)) + assert output.plain == expected.plain + assert output._spans == expected._spans