We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 2d98a45 commit 02fd245Copy full SHA for 02fd245
CHANGELOG.md
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
24
- Added `Screen.size` https://github.com/Textualize/textual/pull/6105
25
- Added `compact` to Binding.Group https://github.com/Textualize/textual/pull/6132
26
- Added `Screen.get_hover_widgets_at` https://github.com/Textualize/textual/pull/6132
27
+- Added `Content.wrap`
28
29
### Fixed
30
src/textual/content.py
@@ -869,6 +869,23 @@ def iter_content() -> Iterable[Content]:
869
870
return Content("".join(text), spans, total_cell_length)
871
872
+ def wrap(
873
+ self, width: int, align: TextAlign = "left", overflow: TextOverflow = "fold"
874
+ ) -> list[Content]:
875
+ """Wrap text so that it fits within the given dimensions.
876
+
877
+ Args:
878
+ width: Maximum width of the line (in cells).
879
+ align: Alignment of lines.
880
+ overflow: Overflow of lines (what happens when the text doesn't fit).
881
882
+ Returns:
883
+ A list of Content objects, one per line.
884
+ """
885
+ lines = self._wrap_and_format(width, align, overflow)
886
+ content_lines = [line.content for line in lines]
887
+ return content_lines
888
889
def get_style_at_offset(self, offset: int) -> Style:
890
"""Get the style of a character at give offset.
891
src/textual/widgets/_text_area.py
@@ -1206,24 +1206,24 @@ def render_line(self, y: int) -> Strip:
1206
Returns:
1207
A rendered line.
1208
"""
1209
- if y == 0 and not self.text and self.placeholder:
1210
- style = self.get_visual_style("text-area--placeholder")
1211
- content = (
1212
- Content(self.placeholder)
1213
- if isinstance(self.placeholder, str)
1214
- else self.placeholder
1215
- )
1216
- content = content.stylize(style)
1217
- if self._draw_cursor:
1218
- theme = self._theme
1219
- cursor_style = theme.cursor_style if theme else None
1220
- if cursor_style:
1221
- content = content.stylize(
1222
- ContentStyle.from_rich_style(cursor_style), 0, 1
1223
1224
- return Strip(
1225
- content.render_segments(self.visual_style), content.cell_length
+ if not self.text and self.placeholder:
+ placeholder_lines = Content.from_text(self.placeholder).wrap(
+ self.content_size.width
1226
)
+ if y < len(placeholder_lines):
+ style = self.get_visual_style("text-area--placeholder")
+ content = placeholder_lines[y].stylize(style)
+ if self._draw_cursor and y == 0:
+ theme = self._theme
+ cursor_style = theme.cursor_style if theme else None
+ if cursor_style:
+ content = content.stylize(
+ ContentStyle.from_rich_style(cursor_style), 0, 1
+ )
+ return Strip(
+ content.render_segments(self.visual_style), content.cell_length
1227
1228
scroll_x, scroll_y = self.scroll_offset
1229
absolute_y = scroll_y + y
tests/snapshot_tests/test_snapshots.py
@@ -4626,3 +4626,27 @@ def compose(self) -> ComposeResult:
4626
yield Header()
4627
4628
assert snap_compare(HeaderApp())
4629
4630
4631
+def test_long_textarea_placeholder(snap_compare) -> None:
4632
4633
+ TEXT = """I must not fear.
4634
+Fear is the mind-killer.
4635
+Fear is the little-death that brings total obliteration.
4636
+I will face my fear.
4637
+I will permit it to pass over me and through me.
4638
+And when it has gone past, I will turn the inner eye to see its path.
4639
+Where the fear has gone there will be nothing. Only I will remain."""
4640
4641
+ class PlaceholderApp(App):
4642
4643
+ CSS = """
4644
+ TextArea {
4645
+ width: 50%;
4646
+ }
4647
4648
4649
+ def compose(self) -> ComposeResult:
4650
+ yield TextArea(placeholder=TEXT)
4651
4652
+ assert snap_compare(PlaceholderApp())
tests/test_content.py
@@ -349,3 +349,19 @@ def test_add_spans() -> None:
349
Span(7, 9, style="blue"),
350
]
351
assert content.spans == expected
352
353
354
+def test_wrap() -> None:
355
+ content = Content.from_markup("[green]Hello, [b]World, One two three[/b]")
356
+ wrapped = content.wrap(6)
357
+ print(wrapped)
358
+ expected = [
359
+ Content("Hello,", spans=[Span(0, 6, style="green")]),
360
+ Content("World,", spans=[Span(0, 6, style="green"), Span(0, 6, style="b")]),
361
+ Content("One", spans=[Span(0, 3, style="green"), Span(0, 3, style="b")]),
362
+ Content("two", spans=[Span(0, 3, style="green"), Span(0, 3, style="b")]),
363
+ Content("three", spans=[Span(0, 5, style="green"), Span(0, 5, style="b")]),
364
+ ]
365
+ assert len(wrapped) == len(expected)
366
+ for line1, line2 in zip(wrapped, expected):
367
+ assert line1.is_same(line2)
0 commit comments