Cringe.Measure (cringe v0.3.1)

Copy Markdown View Source

Terminal-cell measurement and clipping helpers.

These functions operate on terminal cell width rather than byte size or grapheme count. They account for common wide emoji/CJK graphemes, combining marks, variation selectors, zero-width joiner sequences, and ANSI SGR styling.

Summary

Functions

Drops text until at least count terminal cells are removed.

Fits text to an exact terminal-cell width.

Pads text with spaces until it reaches a terminal-cell width.

Takes text up to a terminal-cell width.

Returns the visible terminal-cell width of a string.

Functions

drop(text, count)

@spec drop(String.t(), non_neg_integer()) :: String.t()

Drops text until at least count terminal cells are removed.

ANSI styling is stripped from the result.

iex> Cringe.Measure.drop("ab🚀cd", 4)
"cd"

iex> Cringe.Measure.drop("ab🚀cd", 3)
"cd"

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

@spec fit(String.t(), non_neg_integer(), keyword()) :: String.t()

Fits text to an exact terminal-cell width.

Text shorter than the target width is padded. Text longer than the target width is clipped. Pass ellipsis?: true to reserve one cell for when clipping.

iex> Cringe.Measure.fit("🚀", 4)
"🚀  "

iex> Cringe.Measure.fit("ab🚀cd", 4)
"ab🚀"

iex> Cringe.Measure.fit("ab🚀cd", 4, ellipsis?: true)
"ab…"

pad(text, width)

@spec pad(String.t(), non_neg_integer()) :: String.t()

Pads text with spaces until it reaches a terminal-cell width.

iex> Cringe.Measure.pad("🚀", 4)
"🚀  "

iex> Cringe.Measure.pad("hello", 2)
"hello"

take(text, width)

@spec take(String.t(), non_neg_integer()) :: String.t()

Takes text up to a terminal-cell width.

The result never splits a grapheme. ANSI SGR sequences are preserved, and an ANSI reset is appended when truncation leaves styling active.

iex> Cringe.Measure.take("ab🚀cd", 4)
"ab🚀"

iex> Cringe.Measure.take("ab🚀cd", 3)
"ab"

iex> Cringe.Measure.take("hello", 2)
"he"

width(text)

@spec width(String.t()) :: non_neg_integer()

Returns the visible terminal-cell width of a string.

iex> Cringe.Measure.width("abc")
3

iex> Cringe.Measure.width("🚀")
2

iex> Cringe.Measure.width("é")
1

iex> Cringe.Measure.width("red")
3