Skip to content

Text and line breaking

text

Knuth-Plass line breaking.

Greedy breaking fills each line to the brim and pays for it on the next one; the classic total-fit algorithm instead scores every candidate breaking of the whole paragraph and keeps the cheapest. The result is what makes narrow columns readable: even spacing, no lone last word, no rivers.

The paragraph is modelled as the usual stream of boxes (words), glue (spaces that can stretch and shrink) and penalties (optional hyphens, forced breaks). Rendering is not decided here — a Line carries both its natural and its adjusted spacing, and the caller picks depending on alignment.

Line dataclass

Line(
    words: tuple[str, ...],
    widths: tuple[float, ...],
    gaps: tuple[float, ...],
    naturals: tuple[float, ...],
    styles: tuple[TextStyle, ...],
    space: float,
    last: bool,
)

One laid-out line: the words, their widths, and the gaps between them.

words instance-attribute
words: tuple[str, ...]
widths instance-attribute
widths: tuple[float, ...]
gaps instance-attribute
gaps: tuple[float, ...]
naturals instance-attribute
naturals: tuple[float, ...]
styles instance-attribute
styles: tuple[TextStyle, ...]
space instance-attribute
space: float
last instance-attribute
last: bool
text property
text: str
uniform property
uniform: bool

Whether the whole line is set in one style, and can be drawn as one.

natural_width property
natural_width: float
justified_width property
justified_width: float

break_paragraph cached

break_paragraph(
    text: str | tuple[Run, ...],
    style: TextStyle,
    measure: float,
    *,
    hyphenate: Callable[[str], Sequence[str]] | None = None,
    justify: bool = True,
) -> tuple[Line, ...]

Break text into the set of lines with the lowest total demerits.

text is either a plain string set in style, or a tuple of (text, style) runs — which is how one word inside a sentence gets a weight or a colour of its own. style is still the paragraph's default.

single_line

single_line(text: str | tuple[Run, ...], style: TextStyle) -> Line

One unbroken line — for headings, labels and anything not to be wrapped.

Each run is kept as one atom, spacing and all: a label that lines up on two spaces must still line up once it is drawn.