* Add InputHandler unit tests for ISO-2022 charset mapping
InputHandler unit tests always used MockCharsetService, so regressions in
print()'s ASCII remapping, G0/G1 designation (ESC ( ) * +), and SO/SI
level switching were never caught at unit level.
Add an ISO-2022 character sets suite wired to real CharsetService and
BufferService that verifies DEC line drawing on G0 (ESC ( 0), G1 after
ESC ) 0 + SO, and charset/glevel restoration via ESC 7 / ESC 8 before
printing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add BufferService.scroll unit tests for isUserScrolling
BufferService.scroll() adjusts ybase and ydisp differently depending on
whether the circular buffer is full and whether isUserScrolling is set,
but no unit test asserted those branches. InputHandler and other callers
use MockBufferService.scroll, which throws, so real scroll viewport logic
was only exercised indirectly.
Add BufferService.test.ts covering full-buffer scroll with the user
scrolled up (ydisp decrements), partial-buffer scroll while scrolled up
(ydisp unchanged), and full-buffer scroll at the viewport bottom
(ydisp tracks ybase).
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add InputHandler unit tests for DECOM cursor positioning
CUP with DEC origin mode (DECOM) offsets rows by the scroll region top
and clamps within DECSTBM margins, but unit tests only toggled the mode
for save/restore. Playwright covered the combination; headless unit tests
did not.
Add a cursor positioning test matching the Playwright DECOM case: with
margins and origin on, CUP places the cursor relative to scrollTop, clamps
to the margin, and uses absolute rows when origin is off.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add WindowsMode unit tests for wrap heuristic edges
ConPTY does not set isWrapped on soft-wrapped lines; updateWindowsModeWrappedState
infers wrapping from the last cell of the previous row. Browser Terminal tests
exercise this only through full writes, with no direct coverage of the helper
or negative cases (trailing space or null).
Add WindowsMode.test.ts asserting isWrapped is set for a full non-space line,
cleared for trailing whitespace, and cleared when the previous line ends empty.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add OscParser.reset unit test for mid-payload abort
OscParser.reset() must call end(false) on active handlers when aborted
during PAYLOAD, but no test invoked reset() directly. EscapeSequenceParser
tests mock OSC, so production reset/cleanup was unverified at unit level.
Add a reset describe block asserting handlers receive END false after a
partial payload, then a subsequent OSC sequence completes normally.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add DcsParser.reset unit test for mid-payload abort
DcsParser.reset() must call unhook(false) on hooked handlers when aborted
mid-DCS, matching OscParser's end(false) cleanup. No DcsParser test called
reset() directly, leaving the abort path unverified at unit level.
Add a reset describe block asserting UNHOOK false after partial put, then a
subsequent DCS sequence completes with UNHOOK true.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add InputHandler print tests for grapheme joining
print() uses UnicodeService.shouldJoin to merge combining marks, but
InputHandler tests never exercised that path. The U+200B infinite-loop
regression test used mocks and had no assertions, so it would pass even
if print() misbehaved.
Add tests for e + combining acute in one parse and across two parses.
Strengthen the U+200B regression test to use BufferService and assert the
buffer does not grow spurious rows.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add CharsetService unit tests for glevel and designation
CharsetService only updates the active charset when setgCharset targets the
current glevel; most InputHandler tests use MockCharsetService instead. A
regression in setgLevel or inactive-slot designation would not be caught
without direct service tests.
Add CharsetService.test.ts covering inactive designation, setgLevel
activation, active-slot updates, and reset clearing state.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add reflowCursorLine unit tests for ConPTY resize behavior
reflowCursorLine lets resize reflow wrapped lines that contain the cursor
(needed when ConPTY does not). No test referenced the option or
reflowLargerGetLinesToRemove's cursor skip branch.
Add BufferReflow tests for skip vs reflow when the cursor is inside a
wrapped block, and Buffer.resize tests showing merge on widen only when
reflowCursorLine is enabled.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add EscapeSequenceParser reset test for async pause recovery
reset() sets ParserStackType.RESET so the next parse continues in GROUND
at chunkPos + 1 without resuming a paused async handler. Existing async
tests only verified reset lifts FAIL after improper continuation, not
mid-chunk recovery with trailing printable data.
Add a test that pauses on async CSI, calls reset(), then continues parsing
and asserts XY is printed once and the stack returns to NONE.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add Buffer.resize unit test for ConPTY row growth
When rows increase on Windows ConPTY, Buffer.resize appends lines without
decrementing ybase or ydisp so the viewport stays stable while ConPTY
repaints. Buffer tests covered the non-Windows scroll-up path but never
passed windowsPty into options.
Add a ConPTY row-growth test asserting ybase, ydisp, and line count when
windowsPty is configured.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add Buffer reflow test for ConPTY buildNumber threshold
Buffer disables reflow on ConPTY when buildNumber is below 21376, but no
unit test asserted that gate. Column shrink without reflow leaves wrapped
content on a single line instead of splitting across rows.
Add a test comparing shrink behavior at build 21375 versus 21376, plus
retain unwrap-on-widen coverage for supported ConPTY builds.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add ApcParser.reset unit test for mid-payload abort
ApcParser.reset() calls end(false) on active handlers when aborted mid-APC,
matching OscParser and DcsParser, but no ApcParser test invoked reset()
directly.
Add a reset describe block asserting END false after partial put and a
clean subsequent APC sequence.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add InputHandler unit test for REP with grapheme clusters
repeatPrecedingCharacter uses parser.precedingJoinState and reprints the
full cluster from the buffer, but only Playwright covered e + combining
acute with CSI b. A regression could break REP for joined sequences without
failing unit tests.
Add a print-suite test asserting CSI 2 b triples e + acute in one parse.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add InputHandler unit tests for REP no-op cases
repeatPrecedingCharacter returns early when parser.precedingJoinState is
zero, including after another escape sequence clears join state. Only the
positive grapheme REP case was unit tested.
Add tests for bare CSI b and for REP following SGR so regressions cannot
spuriously duplicate buffer content.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add DecorationManager unit test for wrapped search matches
DecorationManager splits matches across wrapped rows with per-segment x
and width, but only SearchEngine had unit coverage; decoration geometry
was left to Playwright.
Add DecorationManager.test.ts using a real Terminal, a wrapped-buffer
match from SearchEngine, and assertions on registerDecoration options
for both row segments.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add BufferService.scroll unit test for DECSTBM margins
When scrollTop is non-zero, scroll() shifts lines inside the margin with
shiftElements instead of pushing scrollback. Existing BufferService tests
only covered scrollTop === 0.
Add a test with margins on rows 1–3 that verifies rows outside the region
stay fixed and lines inside the region scroll correctly.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add BufferService.scrollLines unit tests
scrollLines adjusts ydisp and toggles isUserScrolling for viewport
scrolling, but only scroll() had unit coverage. Regressions in the
user-scroll flag or ydisp clamping would affect the whole viewport.
Add tests for scrolling up, clamping at ydisp 0, and clearing
isUserScrolling when reaching the buffer bottom.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add DecorationManager overview ruler dedup unit test
Multiple highlight matches on the same buffer line should only register
one overview ruler marker; later matches on that line omit ruler options.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Assert overview ruler on each line of wrapped search match
Wrapped highlight decorations span two buffer lines; each segment
should register overview ruler options unlike same-line dedup.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Correct "representation" and "registration" spelling in the comment
describing how handler identifiers are encoded for EscapeSequenceParser.
Co-authored-by: Cursor <cursoragent@cursor.com>
addSubParam documents a cap on stored sub parameters; the limit is
enforced via maxSubParamsLength, not subParamsLength (the current count).
Co-authored-by: Cursor <cursoragent@cursor.com>
Correct "occurred" in IMouseEvent and keydown JSDoc, remove duplicate
"This" in EscapeSequenceParser ZDM comment, use "elapsed" instead of
"lapsed" in TimeBasedDebouncer, and fix "event" in Keyboard comment.
Co-authored-by: Cursor <cursoragent@cursor.com>
- EscapeSequenceParser: ESC ST is ESC backslash (0x1B 0x5C), not ESC
plus a double-quote character; align @vt metadata with C1 ST on the
following line.
- Color.contrastRatio: document l2 as the second luminance argument.
- Marker.dispose: fix "change" -> "chance" in dispose listener comment.
- Buffer.clear: fix possessive "it's" -> "its" in JSDoc.
Co-authored-by: Cursor <cursoragent@cursor.com>
_identifier() checked custom prefix bytes with
`res && 0x3c > res || res > 0x3f`, which parsed as
`(res && 0x3c > res) || (res > 0x3f)` because && binds tighter
than ||. A prefix of NUL (0x00) skipped both clauses and was
accepted even though only 0x3c..0x3f are valid.
Use an explicit range test: res < 0x3c || res > 0x3f. Mirror the
same fix in ApcParser and DcsParser test identifier helpers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace "values lesser than -1" with "values less than -1" in
addParam and addSubParam throw messages. "Lesser" is not standard
English for numeric comparisons; tests assert the exact message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Enable oxlint's import/no-cycle rule (import plugin) so circular module
dependencies are caught in CI, similar to eslint-plugin-import/no-cycle
and biome no-import-cycles discussed in the issue.
Relocate shared types and dependencies to remove cycles under src/common:
- Types.ts: host IInsertEvent, IDeleteEvent, IParams, UnderlineStyle,
IBuffer, and IBufferSet; drop imports from CircularList, buffer/Types,
parser/Types, and Services
- CoreTerminal.ts: define and export ICoreTerminal
- ServiceRegistry.ts: define IServiceIdentifier (break Services registry loop)
- UnicodeService: stop constructing UnicodeV6; CoreTerminal registers the
default v6 provider after service creation
- buffer/Types.ts and parser/Types.ts: re-export moved types for callers
Fixes https://github.com/xtermjs/xterm.js/issues/5897
Co-authored-by: Cursor <cursoragent@cursor.com>
Fixes https://github.com/xtermjs/xterm.js/issues/5896
TypeScript path mappings for common/*, browser/*, and headless/*
were not rewritten in emitted JavaScript, which forced webpack resolve
aliases and NODE_PATH workarounds so runtime could resolve modules.
That added build complexity and broke tooling such as ESLint import/no-cycle.
Changes:
- Convert ~750 imports across src/, addons/, and test/ to relative paths
- Remove common/browser/headless paths and src catch-all mappings from tsconfigs
(keep @xterm/addon-* demo and addon typings paths)
- Remove webpack resolve.alias for common, browser, headless, and vs
- Drop NODE_PATH from unit tests, benchmarks, and VS Code launch config
- Fix addon-image IIPImageStorage to import ./Types after removing catch-all *
Verified: npm run build, esbuild, package, package-headless
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace PayloadStringBuffer with LimitedStringBuilder from common.
Add thorough StringBuilder and LimitedStringBuilder test coverage.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace repeated string concatenation with a chunk buffer that joins
once on completion. Fixes#5916.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
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>