Skip to main content

justerm_core/
logical.rs

1//! Viewport logical lines (#113, ADR-0017): soft-wrap-joined text plus a
2//! per-char map back to viewport cells. This is the buffer-wide *mechanism* a
3//! frame-mode consumer needs for URL detection — the regex and `new URL()`
4//! validation stay consumer-side (policy). It also serves the a11y screen-reader
5//! mirror (#119). The cell-aware assembly lives in `term/logical.rs` — the `Term` half
6//! of this model, moved out of `term.rs` in #601; this module is just the returned shape.
7
8/// One soft-wrap-joined logical line touching the viewport.
9///
10/// **No `#[non_exhaustive]` (#844): nothing outside this crate has a reason to build one.** No
11/// public function accepts it — the engine hands it out — and there are zero out-of-crate literal
12/// sites, so the attribute would bind nothing it does not already bind.
13#[derive(Clone, PartialEq, Eq, Debug)]
14pub struct LogicalLine {
15    /// The line text: wrap-joined across soft-wrapped rows, wide-char spacers
16    /// skipped, trailing blanks trimmed. This is **not** the equivalence to xterm.js's
17    /// `BufferLine.translateToString(true)` an earlier version of this comment claimed. The
18    /// spacer skip matches; the wrap join does not (that method spans one `BufferLine` —
19    /// xterm pairs it with `Buffer.getWrappedRangeForLine`); and the trim still differs,
20    /// but on a **narrower** case than this comment used to name. Until #685 the trim was
21    /// `str::trim_end()`, the Unicode `White_Space` property, so it dropped a printed
22    /// U+00A0 / U+3000 / U+2003 as well. It now removes only `' '` — the codepoint a blank
23    /// cell packs, and therefore the only one that can be padding. What remains is a
24    /// printed trailing **ASCII space**, which xterm keeps (it bounds by written extent)
25    /// and this cannot, because `Cell` has no bit distinguishing a written `' '` from a
26    /// blank. Pinned in `docs/agents/reference-facts.md` § "Trimming a line's end" and
27    /// `docs/map/invariant/only-u0020-can-be-padding.md`.
28    pub text: String,
29    /// Per `text` char, the viewport cell `(row, col)` it came from. A `row`
30    /// outside `0..rows` is off-screen wrapped context (a line that wraps in from
31    /// above the top / out past the bottom) — present so a URL spanning the edge
32    /// still matches; the consumer highlights only the in-range cells.
33    pub cells: Vec<(i32, usize)>,
34}