Skip to Content
ftui-textOverview

Text Pipeline Overview

ftui-text is a full-stack text pipeline that takes bytes and produces renderable, styled, display-width-correct units — without knowing anything about ANSI, Cells, or the terminal. Everything in this crate is a pure function of its input; the render layer consumes the outputs.

The pipeline, stage by stage

bytes (your source: file, network, tick) ┌──────────────────────────────────────────────────────────┐ │ 1. Rope storage │ │ rope.rs — balanced tree of chunks, O(log n) edits │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 2. Editor (optional) │ │ editor.rs — cursor, selection, undo/redo, clipboard │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 3. Normalization │ │ normalization.rs — NFC / NFD / NFKC / NFKD │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 4. Script segmentation │ │ script_segmentation.rs — TextRun per script/direction │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 5. Bidi │ │ bidi.rs — UAX#9 runs, visual ↔ logical mapping │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 6. Shaping │ │ shaping.rs — LRU-cached glyph layout, OpenType │ └──────────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────────┐ │ 7. Width cache │ │ width_cache.rs — per-grapheme cell width lookup │ └──────────────────────────────────────────────────────────┘ Segments, Spans, Text (styled, measured, shaped) ftui-render (out of scope for this crate)

You don’t have to use every stage. The rope alone is useful as a dictionary-free editable string; the width cache alone is useful for any ANSI-emitting program that needs correct column math for emoji.

Where each stage is documented

The three-Cow philosophy

Every user-facing type in this crate — Rope::slice(range), Segment<'a>, Line<'a>, Span<'a> — uses std::borrow::Cow<'a, str> so static strings never allocate and dynamic strings allocate exactly once:

// Zero-allocation Span::raw("Status: ") // One allocation Span::raw(format!("Status: {count}"))

That discipline runs top-to-bottom. Even the rope’s slice borrows from the underlying chunks when the range lives in a single chunk, and only allocates when the range crosses chunks.

Independent of the render layer

ftui-text does not import ftui-render. A width, a shaped run, a BiDi segment — none of these know about Cells, Buffers, or ANSI. The boundary is deliberate: the same text pipeline is used by the terminal backend, the web backend, the snapshot tester, and any future renderer (PDF, image) with zero rewrites.

Memory discipline

  • Rope chunking keeps edits local; no full-buffer rebalance.
  • LRU caches bound memory for width and shaping; evictions are O(1).
  • SmallVec inlining keeps the hot vectors (control codes in a Segment, font features in a shaping key) stack-resident in the common case.
  • Generation counters on the shaping cache allow lazy invalidation when a font changes — no need to walk the cache.

Where to go next