Add a parallel array container for execute handlers (codes < 0x18)
alongside the existing object. Setters populate both, the EXE
fast-path reads from the array with nullish coalescing to avoid
branching. ExecuteHandlerType updated to accept optional ident param
to allow the ?? pattern with the fallback handler.
Replaces 10 separate reset()+addParam(0) pairs across the parser with
a single resetZdm() method that inlines both operations, avoiding two
calls to a foreign object per sequence reset.
Remove intermediate byte handling from the fast-path, bail to table
lookup instead. Remove redundant per-step length checks by requiring
i + 2 < length upfront and letting the for-loop guard the rest.
Replace three !== checks (OSC_STRING, DCS_PASSTHROUGH, APC_STRING)
with one < OSC_STRING comparison. States below OSC_STRING are all
safe for the CSI fast-path; states above need the normal table path
for proper subparser abort propagation.
Address reviewer feedback:
- CSI fast-path is now a condition at the top of the codepoint loop
instead of inside CLEAR, avoiding table lookups for the common case
- EXE bytes < 0x18 get a fast-path before the CSI check so control
bytes don't pay the penalty
- PRINT loop unrolling replaced with while-based version that uses
trueish eval and spares individual length checks in the unrolled case
- Removed misplaced PRINT scan-ahead from CSI dispatch
The CSI fast-path check previously ran on every byte of input, causing
3-18% regressions on ESCAPE, OSC, DCS, and other non-CSI sequences.
Moving the check into the CLEAR action handler means it only evaluates
after the state machine already identified an ESC byte. The fast-path
body is extracted into a separate _csiFast method to keep the switch
case body small for V8 optimization.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
repeatPrecedingCharacter (for REP sequence) changed to look at
the grapheme cluser to the "left" in the BufferLine, and repeat that.
This is an extension of the xterm behavior, and changes the
semantics of REP, so is not fully compatible.
However, the new behavior is cleaner and saner.
Moved precedingJoinState property to EscapeSequenceParser.