The WASM scanner could fill its fixed 4096-op buffer on large inputs (e.g. 5MB
of newlines or OSC traffic) and previously failed or appeared hung. ESC op
coalescing also corrupted the lengths field used for dispatch, causing millions
of redundant handler invocations on OSC benchmark data.
WASM scanner (parser.c / parser.h):
- Add scan_offset to ParserScanHeader; scan(offset, length) resumes after a
partial fill instead of returning -1 for the whole buffer.
- Return early from scan when the op buffer is full; all emit sites use
emit_or_stop() so scan_offset records where to continue.
- Coalesce consecutive OP_EXECUTE and OP_ESC ops with the same code/ident;
lengths holds repeat count, starts holds the input index for ESC.
- Keep CSI/DCS hook layout unchanged (lengths = final byte index, starts =
param arena offset).
TypeScript dispatch (EscapeSequenceParserWasm.ts):
- Drive parsing via runWasmScanChunks(): scan a slice, dispatch ops, advance
inputOffset to nextOffset until the chunk is consumed.
- Fix ESC dispatch: chunkPos uses starts (input index); escCount uses lengths
(repeat count). Avoid treating the CSI-style final-byte index as a loop bound.
- Throw if nextOffset does not advance to catch stuck scans.
EscapeSequenceParser.ts:
- Extend _scanCache for chunked scan state; reset() clears inputOffset and
cached scan data so later parses are not skipped.
Benchmarks:
- Import compiled modules from ../../out/common and ../../out/browser so
npm run benchmark works without NODE_PATH after path-mapping removal.
- Update benchmark skill notes accordingly.
Build:
- build_parser_wasm.sh selects a clang with wasm32 support (Homebrew LLVM on
macOS when Xcode clang lacks the target).
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>
When enabled during mouse events mode, click/drag/move events require the alt
key while wheel events are unaffected. Selection stays enabled by default
and takes precedence over macOptionClickForcesSelection.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Avoid per-call allocation when translating many lines in sequence by
resetting a module-level work StringBuilder before and after each use.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Avoid calling _getCurrentLinkId() twice per codepoint when a hyperlink
is active by reading the link id once before the print loop.
Fixes#5940
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Guard _innerWrite and public write methods after disposal so pending
setTimeout continuations cannot run against a disposed terminal.
Fixes#5936
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace existing.push(...bucket) with an indexed loop in
_mergeLineBucket to avoid intermediate array allocations during
buffer trim/insert/delete re-indexing.
Reuse _mergeLineBucket in _handleBufferLinesTrim for consistency.
Fixes#5941
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace map().reduce() with one accumulator loop in
reflowSmallerGetNewLineLengths to avoid allocating an intermediate
array when summing wrapped line trimmed lengths.
Fixes#5942
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
The windowsPty option change handler checked buildNumber twice
instead of requiring both backend and buildNumber to be defined.
This aligns with Buffer.ts and ensures ConPTY wrapping heuristics
are evaluated only when both fields are present.
Fixes#5934
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace O(n²) string concatenation in the translate loop with
StringBuilder.append, matching the pattern used elsewhere in the project.
Fixes#5939
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace PayloadStringBuffer with LimitedStringBuilder from common.
Add thorough StringBuilder and LimitedStringBuilder test coverage.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Remove common/Clone.ts and its tests. Use the native structuredClone API
for cloning default modes, options, and test fixtures.
Fixes#5911
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>
flushSync() processes pending writes synchronously (e.g. during
CoreTerminal.resize()) but did not emit onWriteParsed, unlike the
async _innerWrite path. Addons listening for parse completion could
miss updates after resize.
Fixes#5912
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Fixes#5913. Blinking is supported in renderers via TextBlinkStateManager,
and bright background colors (100-107) are handled in the SGR loop.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Wrap the onBufferActivate subscription in this._register so it is
disposed when BufferNamespaceApi is disposed, matching the pattern used
elsewhere in the codebase.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Document multi-variant escape handlers with separate /** ... */ lines
instead of multiline blocks.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Replace multiline-comment-style (starred-block), which also forces
multiline // comments into block comments, with jsdoc/multiline-blocks.
That rule only enforces starred JSDoc layout for /** blocks (no text on
the opening line) and leaves multiline // comments unchanged for
internal documentation.
Fix multiline JSDoc in Types.ts.
Fixes#5899
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Enable multiline-comment-style with starred-block to require JSDoc-style
block comments with content on separate lines from the opening delimiter.
Auto-fix existing violations across the codebase.
Fixes#5899
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Introduce MicrotaskTimer as a TimeoutTimer-style helper that schedules a
single runner via queueMicrotask, with set and cancel but no cancelAndSet.
Use it in DecorationLineCache to batch insert/delete line-index updates after
marker line adjustments, replacing ad-hoc queueMicrotask scheduling.
Co-authored-by: Cursor <cursoragent@cursor.com>
Extract the per-line lookup index from DecorationService into an exported
DecorationLineCache class in the same module, with DecorationService listed
first for readability.
Optimize buffer insert/delete maintenance to shift map keys in O(unique
indexed lines) instead of full re-indexing every affected decoration. Only
multi-line decorations that span the mutation point get a full re-index.
Add a direct DecorationLineCache unit test in DecorationService.test.ts.
Co-authored-by: Cursor <cursoragent@cursor.com>
Refs #5176.
forEachDecorationAtCell and getDecorationsAtCell previously scanned every
registered decoration on each call. With thousands of search highlights this
becomes O(total decorations) per cell and blocks rendering during viewport
refreshes.
Maintain a Map of buffer line -> decorations that cover that line. Multi-line
decorations are indexed on every line in their span, so mixed single-line and
multi-line workloads stay fast without falling back to a full scan.
Keep the index aligned with buffer mutations:
- Register and unregister decorations in the line buckets on add/dispose.
- On trim, shift line keys synchronously (before marker handlers run).
- On insert/delete, re-index affected decorations in a microtask after marker
line updates are applied.
Inject IBufferService so line listeners follow the active buffer. Add unit
tests for trim, dispose-on-trim, insert, and dense single-line plus multi-line
lookup. Add DecorationService.benchmark.ts to measure sparse hits and
viewport-sized grid scans with 20k decorations.
Co-authored-by: Cursor <cursoragent@cursor.com>
Per kovidgoyal/kitty#9999, enabling "Report event types" without
"Disambiguate escape codes" doesn't really make sense, and terminals may
choose whatever behavior they think makes sense. However, keys shouldn't
get swallowed (which, after #5791, happens when the !useCsiU branch
cannot handle the event), so instead make "Report event types" imply
"Disambiguate escape codes".
According to spec:
- The Enter, Tab and Backspace keys will not have release events unless
"Report all keys as escape codes" is also set.
- Key events that result in text are reported as plain UTF-8 text, so
events are not supported for them, unless the application requests
"key report" mode.
I checked kitty's behavior. While it does report release events for keys
that result in text as CSI sequences, press and repeat events for these
are reported as plain UTF-8 text. This commit changes Xterm.js to match
this behavior.