Core Package - rahulpandita/react-term GitHub Wiki
The @next_term/core package provides the fundamental data structures and algorithms: the SharedArrayBuffer-backed cell grid, buffer management, the VT parser, and Unicode character-width utilities.
classDiagram
direction LR
class CellGrid {
+SharedArrayBuffer data
+SharedArrayBuffer dirtyRows
+setCell(row, col, cp, attrs)
+isWide(row, col) bool
+isSpacerCell(row, col) bool
+markDirty(row)
+rotateUp()
+extractText(row) string
}
class Buffer {
+CellGrid grid
+CursorState cursor
+scrollTop number
+scrollBottom number
+scrollUp()
+scrollDown()
+saveCursor()
+restoreCursor()
}
class BufferSet {
+Buffer normal
+Buffer alternate
+Buffer active
+scrollback Uint32Array[]
+activateAlternate()
+activateNormal()
+pushScrollback()
+borrowRowBuffer(size)
}
class VTParser {
+parse(data Uint8Array)
+onOsc(code, data)
+onDcs(data)
+onPrint(cp)
+onExecute(cp)
}
class wcwidth {
+wcwidth(cp) 0|1|2
+isCombining(cp) bool
}
Buffer --> CellGrid
BufferSet --> Buffer
VTParser --> BufferSet
VTParser --> wcwidth
CellGrid
CellGrid is the low-level terminal display buffer backed by SharedArrayBuffer. It can be shared across Web Workers with zero-copy access via getBuffer(), which returns the underlying SAB.
Each cell occupies 8 bytes (2 Γ Uint32):
| Word | Content |
|---|---|
| Word 0 | Unicode codepoint |
| Word 1 (bits 0β7) | Foreground ANSI color index |
| Word 1 (bits 8β14) | Attribute flags: bold, italic, underline, blink, strikethrough, inverse |
| Word 1 (bit 15) | ATTR_WIDE β set on the left cell of a 2-column character |
| Word 1 (bits 16β31) | Reserved |
const grid = new CellGrid(cols, rows);
// Share the backing buffer with a worker
worker.postMessage({ sab: grid.getBuffer() });
// Read and write cells
grid.setCell(row, col, codepoint, attrs);
grid.isWide(row, col); // true if this is the left cell of a wide character
grid.isSpacerCell(row, col); // true if this is the right-half spacer cell
Circular scroll: rotateUp() advances the row-origin pointer in O(1) time β no data is copied. Workers sharing the same SAB see the rotation immediately.
Buffer and BufferSet
Buffer wraps a CellGrid with cursor state, scroll region (top/bottom), and tab stops. It implements full-screen scrolls using O(1) circular rotation and partial scroll regions using copyWithin.
BufferSet manages the normal screen, alternate screen (DECALTBUF), and scrollback history.
Scroll optimization: When the scrollback buffer is full and a line is about to be evicted, borrowRowBuffer(size) returns the evicted Uint32Array for reuse. copyRowInto(rowIdx, dest) fills it in place. This eliminates ~60 K allocations per 5 MB of output and reduces scrollback time by approximately 38%.
const bs = new BufferSet(cols, rows, maxScrollback);
bs.activateAlternate(); // Enter alternate screen (e.g., vim, less)
bs.activateNormal(); // Return to normal screen
VTParser
VTParser is a VT100/ANSI state machine that handles the full escape sequence repertoire including CSI, OSC, DCS, and Kitty keyboard extensions.
Wide character handling: For non-ASCII codepoints (cp >= 0x80), the parser calls wcwidth(cp) to determine display width. Wide characters (width === 2) are written with ATTR_WIDE set and a spacer cell (codepoint 0) placed in the next column. A wide character at the last column causes an automatic line wrap. Combining marks (isCombining(cp) === true) are absorbed without advancing the cursor.
OSC callbacks:
| Code | Purpose |
|---|---|
| OSC 4 / 104 | Set / reset indexed color palette |
| OSC 7 | Report working directory |
| OSC 8 | Hyperlink |
| OSC 10 / 11 / 12 | Set/query foreground, background, cursor colors |
| OSC 52 | Clipboard access |
| OSC 133 | Shell integration (semantic zones) |
Kitty keyboard: Supports push/pop/query of keyboard protocol modes via CSI = sequences.
wcwidth Module
wcwidth.ts provides Unicode 15.1 character-width lookup. Both wcwidth and isCombining are exported from @next_term/core.
import { wcwidth, isCombining } from '`@next_term/core`';
wcwidth(0x0041); // 1 β 'A' (normal ASCII)
wcwidth(0x4e2d); // 2 β 'δΈ' (CJK Unified Ideograph)
wcwidth(0x1f600); // 2 β 'π' (emoji)
wcwidth(0x0301); // 0 β combining acute accent
isCombining(0x0301); // true β attaches to previous character
isCombining(0x4e2d); // false
Implementation:
- O(1) BMP lookup β A 64 KB
Uint8Arrayindexed by codepoint (U+0000βU+FFFF) is populated once at module load from East Asian Width and General Category data. Each entry stores width 0, 1, or 2. - Binary search for supplementary planes β Codepoints U+10000 and above use binary search over compacted zero-width and wide range tables covering emoji, CJK Ext BβI, and tag components.
| Return value | Meaning | Examples |
|---|---|---|
0 |
Zero-width | Combining marks (U+0300+), ZWJ (U+200D), variation selectors, BOM |
1 |
Normal β 1 column | ASCII, Latin, Greek, Cyrillic, most BMP characters |
2 |
Wide β 2 columns | CJK Unified Ideographs, Hangul syllables, fullwidth forms, emoji |
isCombining(cp) returns true for codepoints β₯ U+0300 that have width 0 β the subset the parser uses to identify marks that attach to the preceding character without advancing the cursor.
Types
types.ts exports the shared TypeScript interfaces:
| Type | Fields |
|---|---|
CursorState |
row, col, visible, style, wrapPending |
TerminalOptions |
cols, rows, scrollback, theme? |
Theme |
foreground, background, cursor, cursorAccent, selection, 16 ANSI color slots |
DirtyState |
NONE / PARTIAL / FULL enum |
SelectionState |
anchor, focus |
SelectionRange |
startRow, startCol, endRow, endCol |