Raxol.UI.TextLayout (Raxol v2.6.1)

View Source

Canonical text-wrapping entry point implementing the CSS white-space property (CSS Text Module Level 3) for monospace/terminal text. Call wrap/3 with one of the five values below instead of hand-rolling collapsing/wrapping logic.

ValueNewlinesSpace/tab collapsingWraps at width?
:normalcollapsecollapseyes
:nowrapcollapsecollapseno
:prepreservepreserveno
:pre_wrappreservepreserveyes
:pre_linepreservecollapseyes

:normal delegates to TextWrapping.wrap_line_by_word/2 and is deliberately bit-identical to it. Since f99c152ba that wrapper measures in display columns (Raxol.UI.TextMeasure), so all five modes are CJK-width-safe; the old character-count divergence is gone (pinned by Raxol.Harness.WrapCorpusTest).

Word-vs-character break granularity (CSS word-break/overflow-wrap) is a separate axis not modeled here; see Raxol.UI.Components.Input.TextWrapping.wrap_line_by_char/2.

Summary

Functions

Wraps text to width columns (per white_space, default :normal) and keeps at most max_lines lines, implementing CSS Overflow Module Level 4 line-clamp.

Truncates a single line to width display columns per CSS text-overflow (:ellipsis) or a plain hard clip (:clip).

Wraps text to width display columns according to white_space.

wrap/3 with a CSS text-wrap style: :auto (greedy, identical to wrap/3) or :pretty (Knuth-Plass DP via TextLayout.Pretty — minimizes raggedness, avoids single-word orphan lines).

Types

white_space()

@type white_space() :: :normal | :nowrap | :pre | :pre_wrap | :pre_line

Functions

clamp(text, width, max_lines, opts \\ [])

@spec clamp(String.t(), integer(), integer(), keyword()) :: [String.t()]

Wraps text to width columns (per white_space, default :normal) and keeps at most max_lines lines, implementing CSS Overflow Module Level 4 line-clamp.

If wrapping produces max_lines or fewer lines, the result is returned unchanged -- no ellipsis is added when nothing was actually clamped.

If wrapping produces more lines than max_lines, the excess lines are dropped and the kept last line gets a block-ellipsis: a trailing single-cell "…" is appended, re-truncating that line first if appending it would push the line past width. The block-ellipsed line's display width never exceeds width.

max_lines <= 0 yields [].

Options

  • :white_space -- one of Raxol.UI.TextLayout.white_space/0, default :normal.

truncate(line, width, mode)

@spec truncate(String.t(), integer(), :ellipsis | :clip) :: String.t()

Truncates a single line to width display columns per CSS text-overflow (:ellipsis) or a plain hard clip (:clip).

Never splits a double-width grapheme in half -- the cut always lands one column earlier instead. Output display width is always <= width.

  • :clip -- hard cut at width, no indicator appended.
  • :ellipsis -- cut to make room for a trailing single-cell "…" (U+2026 HORIZONTAL ELLIPSIS). At width == 1 the whole line collapses to just the ellipsis character.

width <= 0 always yields "". A line that already fits within width is returned unchanged (no ellipsis appended, even in :ellipsis mode).

wrap(text, width, white_space \\ :normal)

@spec wrap(String.t(), integer(), white_space()) :: [String.t()]

Wraps text to width display columns according to white_space.

Returns a list of lines (each a String.t()). An empty input string always yields [""] (one empty line), matching how callers such as Raxol.UI.Components.Display.Text already special-case blank content before ever reaching a wrap function.

A single grapheme wider than width is never split -- it is emitted on its own line even though it exceeds width (this applies to the width-aware modes: :nowrap is not width-constrained at all, :pre is never split, and :normal also never splits inside a grapheme).

wrap(text, width, white_space, arg4)

@spec wrap(String.t(), integer(), white_space(), :auto | :pretty) :: [String.t()]

wrap/3 with a CSS text-wrap style: :auto (greedy, identical to wrap/3) or :pretty (Knuth-Plass DP via TextLayout.Pretty — minimizes raggedness, avoids single-word orphan lines).

:pretty applies only to white_space: :normal (the sole mode where break points are freely chosen); other modes ignore it.