Raxol.UI.TextLayout.Pretty (Raxol v2.6.1)

View Source

text-wrap: pretty -- a Knuth-Plass-style dynamic program for the monospace grid.

Unlike greedy wrapping (packs each line until the next token overflows, often stranding one "orphan" word on the final line), this considers every legal way to break a paragraph and picks the one minimizing total raggedness (squared slack) plus an orphan penalty, subject to no line exceeding width (a single overlong token is force-broken).

Break opportunities (UAX #14 subset): whitespace runs, after a hyphen-minus inside a word, and between any two CJK ideographs/kana.

All display-width math goes through Raxol.UI.TextMeasure (never String.length/1). Pure and self-contained -- no dependency on Raxol.UI.TextLayout; callers cache if needed.

Summary

Functions

Wraps text to width display columns using the pretty (Knuth-Plass-style) algorithm.

Types

token()

@type token() :: %{
  text: String.t(),
  width: non_neg_integer(),
  kind: token_kind(),
  word_id: non_neg_integer() | nil
}

token_kind()

@type token_kind() :: :word | :space | :cjk | :hyphen_piece | :split_piece

Functions

wrap(text, width, opts \\ [])

@spec wrap(String.t(), pos_integer(), keyword()) :: [String.t()]

Wraps text to width display columns using the pretty (Knuth-Plass-style) algorithm.

Paragraphs (separated by "\n") are wrapped independently and their resulting lines concatenated in order. A blank paragraph produces a single empty line, so the number of "\n"-delimited input paragraphs is a lower bound on the number of output lines.

Options

  • :orphan_penalty - integer cost added when a paragraph's last line would contain a single word while the paragraph has more than :orphan_threshold words total. Defaults to width * width.
  • :orphan_threshold - word count above which the orphan penalty applies. Defaults to 2 (i.e. the penalty applies once a paragraph has more than 2 words).
  • :badness_exponent - exponent used in the raggedness cost abs(width - line_width) ** exponent. Defaults to 2. An exponent of 0 makes every non-perfect line cost 1, which degenerates the DP toward "minimize line count" (useful as a greedy-ish reference).