Skip to main content

uncurses/text/
mod.rs

1//! Text measurement and string painting for terminal-cell surfaces.
2//!
3//! This module is the text layer for [`SurfaceMut`](crate::buffer::SurfaceMut):
4//! it segments UTF-8 strings into grapheme clusters, measures their terminal
5//! display width, and writes cells into any mutable surface implementation.
6//! Painting is literal by default; the optional [`Painter`] interprets inline
7//! SGR and OSC 8 escapes as styling.
8//!
9//! ## Width measurement and grapheme handling
10//!
11//! Terminal layout is expressed in cells, not bytes or scalar values. The
12//! width API therefore separates **segmentation** from **measurement**:
13//!
14//! * [`grapheme_cells`] always walks a string as extended grapheme clusters.
15//! * [`WidthMode::Wc`] measures each cluster by its first code point.
16//! * [`WidthMode::Grapheme`] measures the whole cluster with
17//!   [`grapheme_width`], including variation selectors, regional indicators,
18//!   zero-width joiners, and pictographic presentation.
19//! * [`char_width`] measures a single code point and is useful for code that
20//!   already has its own segmentation.
21//!
22//! ```text
23//! bytes/scalars             grapheme cluster              terminal cells
24//! ┌───────────────┐         ┌───────────────┐             ┌────┬────┐
25//! │ "e" + U+0301  │ ──────▶ │ "e\u{0301}"   │ ─ width 1 ▶ │ é  │    │
26//! └───────────────┘         └───────────────┘             └────┴────┘
27//!
28//! ┌───────────────┐         ┌───────────────┐             ┌────┬────┐
29//! │ "中"          │ ──────▶ │ "中"          │ ─ width 2 ▶ │ 中 │ ▶  │
30//! └───────────────┘         └───────────────┘             └────┴────┘
31//! ```
32//!
33//! A width of `0` is not written as a standalone cell. While painting, a
34//! zero-width cluster is appended to the previous pending cluster so combining
35//! marks and similar suffixes stay attached to the base cell.
36//!
37//! ## East-Asian-Width policy
38//!
39//! The `eaw_wide` boolean is the East-Asian Ambiguous policy. When it is
40//! `true`, code points whose East-Asian-Width property is `Ambiguous` are
41//! measured as two cells; when it is `false`, they are measured as one. This is
42//! intentionally independent from [`WidthMode`] so callers can choose the
43//! terminal's ambiguous-width policy without changing grapheme segmentation.
44//!
45//! ## Painting and wrapping
46//!
47//! [`Painter`] binds a target [`SurfaceMut`](crate::buffer::SurfaceMut), a
48//! [`WidthMode`], and an `eaw_wide` policy. It paints styled strings into the
49//! target, honoring inline SGR (`CSI … m`) attributes and OSC 8 hyperlinks.
50//! [`WrapMode`] controls only what happens when a non-zero-width cluster would
51//! cross the right edge of the clipping rectangle: truncate or continue at the
52//! next row.
53//!
54//! ## The `TextSurface` trait
55//!
56//! [`TextSurface`] is the ergonomic extension trait for drawing text onto any
57//! surface. A surface supplies its [`WidthMode`] and East-Asian-Width policy;
58//! the trait then provides [`TextSurface::set_str`],
59//! [`TextSurface::set_str_wrap`], [`TextSurface::set_str_rect`],
60//! [`TextSurface::set_str_rect_wrap`], and [`TextSurface::str_width`]. This
61//! keeps higher-level widgets generic over `&mut impl TextSurface` instead of
62//! depending on a concrete buffer type.
63//!
64//! ## Feature backends
65//!
66//! The default `unicode-rs` feature uses compact built-in tables for code-point
67//! width plus a conservative pictographic/default-ignorable subset. Enabling
68//! the `icu` feature uses property data with broader Unicode coverage. The
69//! public API is identical for both backends; select the backend that matches
70//! your binary-size and Unicode-coverage needs.
71
72mod display;
73mod mode;
74mod painter;
75mod surface;
76mod width;
77
78pub use display::{Encode, SurfaceDisplay};
79pub use mode::{WidthMode, WrapMode, grapheme_cells};
80pub use painter::Painter;
81pub use surface::TextSurface;
82pub use width::{char_width, grapheme_width};