struct
Termisu::Cell
- Termisu::Cell
- Struct
- Value
- Object
Overview
Cell represents a single character cell in the terminal buffer.
Cell contains:
- grapheme: The Unicode grapheme cluster (single grapheme for leading cells)
- width: Display column width (0, 1, or 2)
- continuation: True for trailing cell of a wide grapheme
- fg: Foreground color (supports ANSI-8, ANSI-256, and RGB)
- bg: Background color (supports ANSI-8, ANSI-256, and RGB)
- attr: Text attributes (bold, underline, etc.)
Grapheme and Continuation Cells
Wide characters (CJK, emoji) occupy 2 columns. The Cell model represents this:
- Leading cell:
continuation = false,width = 2,#graphemecontains the full grapheme - Trailing cell:
continuation = true,width = 0,#graphemeis empty
Example:
# Leading cell for "中" (width auto-calculated as 2)
lead = Termisu::Cell.new("中")
lead.grapheme # => "中"
lead.width # => 2
lead.continuation? # => false
# Trailing continuation cell
trail = Termisu::Cell.continuation
trail.grapheme # => ""
trail.width # => 0
trail.continuation? # => true
Compatibility (Public API)
The #grapheme property provides backward-compatible access:
cell = Termisu::Cell.new("ABC")
cell.grapheme # => "A" (first grapheme of input-String is stored)
continuation = Termisu::Cell.continuation
continuation.grapheme # => "" (empty for continuation cells)
Defined in:
termisu/cell.crConstant Summary
-
CONTINUATION_KEY =
Cell.new(continuation: true).key -
Key of the canonical continuation cell, so Buffer's key planes can write continuation cells without materializing a Cell.
-
DEFAULT_KEY =
Cell.new.key -
Key of the canonical default cell, resolved lazily so default_state? stays a single integer compare.
-
KEY_STYLE_MASK =
(1_u128 << 84) - 1 -
Style portion of a key (attr + fg + bg, bits 0..83). Cells with equal masked keys render with identical styling (see injectivity notes on #key).
Constructors
-
.new(grapheme : String = " ", continuation : Bool = false, fg : Color = Color.white, bg : Color = Color.default, attr : Attribute = Attribute::None)
Creates a new Cell with the specified grapheme and colors.
Class Method Summary
-
.continuation
Continuation cells represent the trailing column occupied by a wide character.
-
.default
default empty cell (space with default colors, width 1, not continuation).
Instance Method Summary
- #attr : Attribute
- #attr=(attr : Attribute)
- #bg : Color
- #bg=(bg : Color)
- #continuation? : Bool
-
#default_state? : Bool
Returns true when this cell is the canonical default blank cell.
- #fg : Color
-
#fg=(fg : Color)
Style setters splice only their own key field instead of re-running compute_key, which would re-derive the grapheme id and take the process-global intern mutex for non-ASCII cells.
- #grapheme : String
- #grapheme=(grapheme : String)
-
#key : UInt128
Packed identity key: equal keys <=> equal cells (memberwise equality).
- #width : UInt8
Constructor Detail
Creates a new Cell with the specified grapheme and colors.
Parameters:
- grapheme: Unicode grapheme cluster to display (if multi-grapheme string is passed, only the first grapheme cluster is stored)
- continuation: True if this is a trailing cell of a wide grapheme
- fg: Foreground color (default: white)
- bg: Background color (default: default terminal color)
- attr: Text attributes (default: None)
Note: Width is derived from grapheme content to ensure consistency. Continuation cells always have empty grapheme and width 0.
Occupancy invariants enforced:
- Continuation cells: always empty grapheme, width 0
- Empty non-continuation: normalized to default space cell (width 1)
- Leading cells: width derived via grapheme_width (handles VS16, ZWJ, flags)
- Multi-grapheme strings: only first grapheme is stored; debug log warns of truncation
Class Method Detail
Continuation cells represent the trailing column occupied by a wide character. They have empty grapheme, width 0, and are never rendered directly.
trail = Termisu::Cell.continuation
trail.continuation? # => true
trail.width # => 0
trail.grapheme # => ""
Instance Method Detail
Returns true when this cell is the canonical default blank cell.
Used by Buffer hot paths (clear/dirtiness accounting) to avoid expensive full-buffer work when rows are already blank.
Style setters splice only their own key field instead of re-running compute_key, which would re-derive the grapheme id and take the process-global intern mutex for non-ASCII cells.
Packed identity key: equal keys <=> equal cells (memberwise equality). Buffer hot paths (write dedup, diff scan, default_state?) compare this single UInt128 instead of walking the struct field-by-field.
Bit layout (LSB first):
- 0..15 attr (UInt16 flags value)
- 16..49 fg color key (2-bit mode + 32-bit canonical payload)
- 50..83 bg color key (same encoding)
- 84..115 grapheme id (ASCII byte direct; non-ASCII interned)
- 116..117 width (0..2)
- 118 continuation flag
Injectivity notes: color payload encodes exactly the fields Color#== compares per mode (index for ANSI, r/g/b for RGB), and public Color constructors zero the unused fields, so equal color keys imply Color#==. Grapheme ids are content-interned, so equal ids imply equal strings.