wrap and overflow docs

This commit is contained in:
Will McGugan
2025-01-27 12:18:59 +00:00
parent c2f4c2a684
commit a0910ceb30
9 changed files with 235 additions and 5 deletions

View File

@@ -0,0 +1,33 @@
# <text-wrap>
The `<text-wrap>` CSS type sets how Textual wraps text.
## Syntax
The [`<text-wrap>`](./text_wrap.md) type can take any of the following values:
| Value | Description |
| -------- | ------------------------- |
| `wrap` | Word wrap text (default). |
| `nowrap` | Disable text wrapping. |
## Examples
### CSS
```css
#widget {
text-wrap: nowrap; /* Disable wrapping */
}
```
### Python
```py
widget.styles.text_wrap = "nowrap" # Disable wrapping
```
## See also
- [`text-overflow`](./overflow.md) is used to change what happens to overflowing text.

View File

@@ -0,0 +1,18 @@
from textual.app import App, ComposeResult
from textual.widgets import Static
TEXT = """I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear."""
class WrapApp(App):
CSS_PATH = "text_overflow.tcss"
def compose(self) -> ComposeResult:
yield Static(TEXT, id="static1")
yield Static(TEXT, id="static2")
yield Static(TEXT, id="static3")
if __name__ == "__main__":
app = WrapApp()
app.run()

View File

@@ -0,0 +1,17 @@
Static {
height: 1fr;
text-wrap: nowrap;
}
#static1 {
text-overflow: clip; # Overflowing text is clipped
background: red 20%;
}
#static2 {
text-overflow: fold; # Overflowing text is folded on to the next line
background: green 20%;
}
#static3 {
text-overflow: ellipsis; # Overflowing text is truncated with an ellipsis
background: blue 20%;
}

View File

@@ -0,0 +1,17 @@
from textual.app import App, ComposeResult
from textual.widgets import Static
TEXT = """I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear."""
class WrapApp(App):
CSS_PATH = "text_wrap.tcss"
def compose(self) -> ComposeResult:
yield Static(TEXT, id="static1")
yield Static(TEXT, id="static2")
if __name__ == "__main__":
app = WrapApp()
app.run()

View File

@@ -0,0 +1,12 @@
Static {
height: 1fr;
}
#static1 {
text-wrap: wrap; /* this is the default */
background: blue 20%;
}
#static2 {
text-wrap: nowrap; /* disable wrapping */
background: green 20%;
}

View File

@@ -0,0 +1,65 @@
# &lt;text-overflow&gt;
The `<text-overflow>` CSS type sets how Textual wraps text.
## Syntax
The [`<text-overflow>`](./text_overflow.md) type can take any of the following values:
| Value | Description |
| ---------- | ----------------------------------------------------------------------------------- |
| `clip` | Overflowing text will be clipped (the overflow portion is removed from the output). |
| `fold` | Overflowing text will fold on to the next line. |
| `ellipsis` | Overflowing text will be truncate and the last character replaced with an ellipsis. |
## Examples
In the following example we show the output of each of the values of `text_overflow`.
The widgets all have [text wrapping][`text-wrap`](./text_wrap.md) disabled.
Since the string is longer than the width, it will overflow.
In the first (top) widget, "text-overflow" is set to "clip" which clips any text that is overflowing, resulting in a single line.
In the second widget, "text-overflow" is set to "fold", which causes the overflowing text to *fold* on to the next line.
When text folds like this, it won't respect word boundaries--so you may get words broken across lines.
In the third widget, "text-overflow" is set to "ellipsis", which is similar to "clip", but with the last character set to an ellipsis.
This option is useful to indicate to the user that there may be more text.
=== "Output"
```{.textual path="docs/examples/styles/text_overflow.py"}
```
=== "text_overflow.py"
```py
--8<-- "docs/examples/styles/text_overflow.py"
```
=== "text_overflow.tcss"
```css
--8<-- "docs/examples/styles/text_overflow.tcss"
```
### CSS
```css
#widget {
text-overflow: ellipsis;
}
```
### Python
```py
widget.styles.text_overflow = "ellipsis"
```
## See also
- [`text-wrap`](./text_wrap.md) is used to control wrapping.

61
docs/styles/text_wrap.md Normal file
View File

@@ -0,0 +1,61 @@
<!-- This is the template file for a CSS style reference page. -->
# Text-wrap
The `text-wrap` style set how Textual should wrap text.
The default value is `wrap` which will word-wrap text.
You can also set this style to `nowrap` which will disable wrapping entirely.
## Syntax
--8<-- "docs/snippets/syntax_block_start.md"
Formal syntax description of the style
style-name: <a href="../../css_types/text_wrap">&lt;text_wrap&gt;</a>;
--8<-- "docs/snippets/syntax_block_end.md"
## Examples
In the following example we have to pieces of text.
The first (top) text has the default `text-wrap` setting which will word wrap.
The second has `text-wrap` set to `nowrap`, which disables text wrapping, and results in a single line.
=== "Output"
```{.textual path="docs/examples/styles/text_wrap.py"}
```
=== "text_wrap.py"
```py
--8<-- "docs/examples/styles/text_wrap.py"
```
=== "text_wrap.tcss"
```css
--8<-- "docs/examples/styles/text_wrap.tcss"
```
-->
## CSS
```css
text-wrap: wrap;
text-wrap: nowrap;
```
## Python
```py
widget.styles.text_wrap = "wrap"
widget.styles.text_wrap = "nowrap"
```

View File

@@ -41,7 +41,9 @@ nav:
- "css_types/percentage.md"
- "css_types/scalar.md"
- "css_types/text_align.md"
- "css_types/text_overflow.md"
- "css_types/text_style.md"
- "css_types/text_wrap.md"
- "css_types/vertical.md"
- Events:
- "events/index.md"
@@ -137,6 +139,8 @@ nav:
- "styles/scrollbar_size.md"
- "styles/text_align.md"
- "styles/text_opacity.md"
- "styles/text_overflow.md"
- "styles/text_wrap.md"
- "styles/text_style.md"
- "styles/tint.md"
- "styles/visibility.md"

View File

@@ -361,7 +361,13 @@ class Content(Visual):
line = line.expand_tabs(tab_size)
if no_wrap:
if no_wrap and overflow == "fold":
cuts = list(range(0, line.cell_length, width))[1:]
new_lines = [
FormattedLine(line, width, y=y, align=align)
for line in line.divide(cuts)
]
elif no_wrap:
if overflow == "ellipsis" and no_wrap:
line = line.truncate(width, ellipsis=True)
content_line = FormattedLine(line, width, y=y, align=align)
@@ -923,10 +929,7 @@ class Content(Visual):
]
return segments
def divide(
self,
offsets: Sequence[int],
) -> list[Content]:
def divide(self, offsets: Sequence[int]) -> list[Content]:
if not offsets:
return [self]