* fix(addon-search): advance highlight scan by buffer match size
_highlightAllMatches() stepped to the next find() using term.length
and col + 1 when staying on the same row. Search results expose size
in buffer columns (wide glyphs, wrapped matches), which select() and
decorations already use.
Advance with col + size and wrap row/col when crossing the terminal
width so highlight-all does not skip, duplicate, or stop early on
non-ASCII matches.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(addon-search): regression for highlight-all wide char advance by size
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* test(addon-search): move highlight-all regression to integration tests
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Upgrade actions/checkout, setup-node, upload-artifact, download-artifact,
and codeql-action to their latest major versions that run on Node 24.
Replace NathanFirmo/wait-for-other-job with native needs: build for
test-unit and test-integration jobs.
Fixes#6006
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
Remove early return when ybase===0 && y===0 so clear() always
clears markers, resets buffer lines, and refills the viewport.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* fix(selection): drag-scroll end row matches last visible line
Use ydisp + rows - 1 for selectionEnd when scrolling down during drag,
consistent with finalSelectionEnd for select-all.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* fix(selection): reset start to origin when start row is trimmed
When handleTrim removes the selection start row, clamp to [0,0] and
refresh; do not keep a stale column on row 0.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* fix(addon-webgl): skip missing buffer lines in _updateModel
_updateModel force-unwrapped buffer.lines.get(row), which can be
undefined during trim or resize. That threw and left stale glyphs on
rows below the gap.
Clear the WebGL model row and glyph cells, reset blink state, and
continue with remaining viewport rows, matching DomRenderer and
ImageStorage handling.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(addon-webgl): extract _nullModelCell helper
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* fix(DomRenderer): skip missing buffer lines during row render
renderRows and link underline refresh stopped updating when any
viewport row lacked buffer data, leaving stale DOM on rows below.
Match ImageStorage.render behavior: clear the row element when
present and continue with remaining rows.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(DomRenderer): clear blink state when skipping missing lines
When a viewport row has no buffer line, renderRows clears the row DOM
and continues but did not reset _rowHasBlinkingCells for that row.
That could leave the text blink manager thinking blinking cells remain
after the row was emptied.
Clear blink state for the row when skipping a missing buffer line,
including during link underline refresh.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Character joiner scanning already iterated cells with
getTrimmedLength(), but trailing attribute runs and
_stringRangesToCellRanges used buffer cols. On short lines that
could run joiners on a single trailing cell and extend open ranges
through empty tail columns, affecting ligature/join rendering.
Use trimmed length consistently for trailing-run detection, the
cell-range walk, and the final range end column.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mocha 11.7.x pulls in serialize-javascript 6.0.2, which is affected by
code injection via RegExp.flags and Date.toISOString (CVE incomplete fix).
Force the patched 7.x release via npm overrides.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* 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>
* fix(buffer): bound combined-cell copy in copyCellsFrom
When copying a column range, combined-string metadata was copied for
every source column >= srcCol with no upper limit. Partial copies could
pull _combined entries from outside [srcCol, srcCol + length) into the
destination and corrupt cells beyond the copied span.
Only copy combined keys within the same range as the cell data loop.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(buffer): clear stale _combined entry in BufferLine.setCell
setCell updated combined data when IS_COMBINED_MASK was set but left
orphaned _combined[index] entries when writing a non-combined cell.
Delete the map entry in that case so later combined copies and lookups
stay aligned with cell content flags.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(buffer): clear stale extended attrs in BufferLine.setCell
setCell stored extended attributes when HAS_EXTENDED was set but did
not remove orphaned _extendedAttrs[index] when overwriting with a
cell without extended background data. Delete the entry in that case,
matching the combined-cell cleanup added for setCell earlier.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(buffer): clear dest extended attrs in copyCellsFrom
When copying a column range, extended attributes were copied from
source cells with HAS_EXTENDED but stale _extendedAttrs on the
destination were left for cells without extended data. Delete dest
entries in that case, matching setCell behavior and the bounded
_combined copy loop.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(buffer): clear extended attrs in setCellFromCodepoint
The input-handler fast path set extended data when HAS_EXTENDED was
present but left orphaned _extendedAttrs entries when overwriting
with non-extended cells. Delete the map entry in that case, matching
setCell and copyCellsFrom.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(buffer): clear stale combined data in setCellFromCodepoint
When the input handler overwrites a cell that previously held a
grapheme cluster (IS_COMBINED_MASK), setCellFromCodepoint updated
_data and _extendedAttrs but left this._combined[index] intact.
setCell already deletes _combined for non-combined cells; this path
did not, so getString and renderers could show the old cluster string
after a normal codepoint write.
Add delete this._combined[index] at the start of setCellFromCodepoint,
matching setCell's non-combined branch and the extended-attrs cleanup
already performed in the same method.
Co-authored-by: Cursor <cursoragent@cursor.com>
* perf(buffer): only delete stale combined/extended map entries when present
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
* fix(buffer): treat combined/extended maps as flag-gated caches
_flags in _data are authoritative; sparse maps are only read when
IS_COMBINED_MASK or HAS_EXTENDED is set. setCellFromCodepoint no longer
touches _combined. loadCell clears CellData side fields when flags are off.
copyCellsFrom copies map entries per-cell from src flags only.
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
PR #5966 switched benchmark imports to ../../src/ paths that do not
resolve at runtime. Restore common/* and browser/* imports (with
benchmark-only tsconfig paths for typechecking) and NODE_PATH=./out
on benchmark npm scripts so emitted requires resolve against out/.
Fixes#5970
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Daniel Imms <Tyriar@users.noreply.github.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary
Improves reliability and correctness of `bin/` maintenance scripts used for local development and CI.
## Behavioral fixes
- **Exit codes**: `test_integration.js` exits with code 1 when `--suite` names an unknown suite; `test_unit.js` uses a non-zero fallback (`-1`) when the coverage or mocha child process has no status; `esbuild_all.mjs` exits non-zero if any parallel esbuild child fails.
- **Repo root**: `setup-full.mjs` resolves the repository root one directory above `bin/` (was incorrectly using `bin/` as root).
- **esbuild_all**: Propagates child build failures instead of always exiting 0.
- **Integration suites**: When `--suite` is omitted, all configured Playwright suites (core + addons) run; when provided, only the matching suite runs.
- **test_unit.js**: Declares the `files` filter variable so file arguments from `npm run test-unit` work without a ReferenceError.
- **test_mousemodes.js**: Uses the correct cursor-home CSI (`ESC [ H`) when clearing the menu screen.
- **Cleanup**: Removes debug logging from the test-unit coverage path; adds a missing semicolon after the suite regex match.
## Affected scripts
- `bin/test_integration.js`
- `bin/test_unit.js`
- `bin/esbuild_all.mjs`
- `bin/setup-full.mjs`
- `bin/test_mousemodes.js`
## Testing
- Syntax-checked affected scripts with `node --check`
- Verified `node bin/test_integration.js --suite=unknown` exits 1 with an error message
- `npm run lint-changes` (no TypeScript files changed)
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a href="https://cursor.com/agents/bc-94b28f5d-740c-4cb6-8cd9-40f35bc6086c"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-94b28f5d-740c-4cb6-8cd9-40f35bc6086c"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
The integration test file used test.describe('Search Tests'), copied from
addon-search. That mislabels attach-addon results in Playwright reports and
makes the suite harder to filter or debug.
Rename the block to 'AttachAddon' so the describe name matches the addon
under test. No test logic changed.
Validated with: npm run build && npm run esbuild, npm run test-unit,
npm run esbuild-demo-client && npm run esbuild-demo-server &&
npm run test-integration, npm run package, npm run package-headless.
Co-authored-by: Cursor <cursoragent@cursor.com>
beforeAll always resolved the readFile promise with data even when
err was set, which led to calling toString on undefined. Reject the
promise on err so fixture load failures surface clearly. Use res/rej
callback names to avoid shadowing path.resolve.
Co-authored-by: Cursor <cursoragent@cursor.com>
The integration test intended to move the cursor forward with ESC [ C
but wrote the literal string \x1b[C due to double escaping. Use a
single-escaped '\x1b[CHi Hi' so the terminal receives the control
sequence and creates the null cell the scenario describes.
Co-authored-by: Cursor <cursoragent@cursor.com>
The webglcontextlost section repeated "fired" ("fires the ... event
fired on the canvas"). Drop the extra word.
Co-authored-by: Cursor <cursoragent@cursor.com>
Correct "transferred", remove duplicate "is", and use "one-off"
instead of "once of" in developer-facing comments.
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>
Use "a Unicode" instead of "an Unicode" on IUnicodeService.register,
and "user's platform" instead of "users platform" above the platform
detection exports.
Co-authored-by: Cursor <cursoragent@cursor.com>
Change "it's view" to "its view" in the comment explaining why new
rows are appended on Windows when using conpty.
Co-authored-by: Cursor <cursoragent@cursor.com>
The onChange event comment said "activate version changed" while the
property is activeVersion. Clarify that the event fires when the active
Unicode version changes.
Co-authored-by: Cursor <cursoragent@cursor.com>
getCoords had a truncated comment ("if there are no valid") and a typo
("addition" vs "additional") in the selection precision note. Complete
the char-size guard comment and fix the selection wording.
Co-authored-by: Cursor <cursoragent@cursor.com>
The Content bitmask JSDoc examples used camelCase names that do not
exist on the enum (codepointMask, isCombined, hasContent, widthMask,
widthShift). Update examples to match the real members:
CODEPOINT_MASK, IS_COMBINED_MASK, HAS_CONTENT_MASK, WIDTH_MASK, and
WIDTH_SHIFT as used throughout BufferLine and CellData.
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>
RENDER_DEBOUNCE_THRESHOLD_MS was declared above the import, which
breaks ES module conventions and can confuse tooling. Move the import
to the top of the module after the license header.
Co-authored-by: Cursor <cursoragent@cursor.com>
_clearIdleTimer() used truthiness on _idleTimeout, so a setTimeout
handle of 0 would not be cleared. Compare against undefined, consistent
with RenderDebouncer rAF handling.
Co-authored-by: Cursor <cursoragent@cursor.com>
dispose(), addRefreshCallback(), and refresh() used truthiness on
_animationFrame, so a requestAnimationFrame handle of 0 would not be
cancelled or deduplicated. Compare against undefined instead, matching
other timer checks in the browser layer.
Co-authored-by: Cursor <cursoragent@cursor.com>
TimeBasedDebouncer can schedule a trailing setTimeout when refresh
requests are throttled. If the debounce window later elapses and an
immediate refresh runs, that pending timeout was left armed and could
fire afterward, causing a duplicate _innerRefresh (e.g. extra live
region updates for screen readers).
Clear any pending timeout and reset _additionalRefreshRequested before
running the immediate refresh path.
Co-authored-by: Cursor <cursoragent@cursor.com>
LinkComputer rebuilt the search RegExp with (regex.flags || '') + 'g',
which throws if the caller already passed a global regex. Only append
g when it is not already present in regex.flags.
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>
The merging-pages index sort used (a, b) => a > b ? 1 : -1, which
returns -1 when a === b and violates the comparator contract. Use
(a, b) => a - b for ascending numeric order.
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>
Valid column indices are 0 through cols - 1. The previous check used
startCol > cols, so on an 80-column terminal column 80 was accepted while
column 100 correctly threw. Use >= so the out-of-range guard matches the
documented error for invalid search positions.
Co-authored-by: Cursor <cursoragent@cursor.com>
dispose() cleared the pending timeout but left _refreshTimeoutID and
_additionalRefreshRequested set. After dispose, a stale timeout id or
trailing-refresh flag could confuse a new instance or tests. Match
RenderDebouncer by clearing the timeout id and reset the trailing flag.
Co-authored-by: Cursor <cursoragent@cursor.com>
getCoordsRelativeToElement always returns a two-element tuple, so the
array is always truthy and if (!coords) could never run. hasValidCharSize
already handles the only early-exit path before coordinates are computed.
Co-authored-by: Cursor <cursoragent@cursor.com>
Nullish coalescing binds tighter than the conditional operator, so the
previous expression was parsed as (this._document ?? windowDefined) ?
window.document : null. When this._document was set (e.g. parent
ownerDocument or documentOverride), the ternary still returned
window.document instead of the configured document.
CoreBrowserService.mainDocument is used by AccessibilityManager, viewport
styles, and decoration renderers; CharSizeService already received
this._document directly. Add parentheses so the fallback applies only when
_document is nullish.
Co-authored-by: Cursor <cursoragent@cursor.com>
horizontalDirection called moveToRequestedRow with targetX as the first
argument, but that parameter is the starting row (startY). resetStartingRow
and moveToRequestedCol already pass startY correctly; only this copy-paste
mistake passed a column index where a row was expected.
That could miscompute wrapped-row offsets and emit the wrong horizontal
arrow key sequence when building selection/cursor movement strings.
Co-authored-by: Cursor <cursoragent@cursor.com>
CustomGlyphRasterizer parsed large-arc and sweep flags with parseInt
without a radix when drawing SVG arc paths. Use base 10 for 0/1 flags.
Co-authored-by: Cursor <cursoragent@cursor.com>
KittyGraphicsTypes parsed numeric control values with parseInt
without a radix. Use base 10 explicitly for format, id, dimensions,
and offset fields.
Co-authored-by: Cursor <cursoragent@cursor.com>
_dim() parsed percent, pixel, and cell dimension strings with
parseInt without an explicit radix. Use base 10 for all three paths,
consistent with other numeric parsing fixes in the repo.
Co-authored-by: Cursor <cursoragent@cursor.com>
proposeDimensions summed padding-top/bottom/left/right via bare
parseInt, so non-numeric padding values produced NaN and broke
available width/height. Use radix 10 and || 0 on each side, consistent
with parent element size parsing.
Co-authored-by: Cursor <cursoragent@cursor.com>
Align parent width parsing with the height fix: parseInt with radix
10 and || 0 inside Math.max so non-numeric CSS width does not yield
NaN cols in proposeDimensions.
Co-authored-by: Cursor <cursoragent@cursor.com>
InputHandler parsed palette indices from OSC color sequences with
parseInt without a radix after validating digits-only slots. Use
base 10 for set/report and restore color index parsing.
Co-authored-by: Cursor <cursoragent@cursor.com>
Wheel event DPR factoring parses Chrome/(\d+) with parseInt without a
radix. Add base 10 explicitly, matching getSafariVersion and other
version parsing in the codebase.
Co-authored-by: Cursor <cursoragent@cursor.com>
rgba/rgb CSS parsing used parseInt without a radix on captured digit
groups. Add base 10 explicitly, matching getSafariVersion and other
call sites in the codebase.
Co-authored-by: Cursor <cursoragent@cursor.com>
Safari major version parsing used parseInt without an explicit radix.
Other call sites in the repo use base 10; add the radix for consistency
and to avoid octal interpretation of leading-zero strings.
Co-authored-by: Cursor <cursoragent@cursor.com>
parseInt without a radix can mis-parse leading-zero padding values as
octal. Match AccessibilityManager and document rowCount JSDoc typo.
Co-authored-by: Cursor <cursoragent@cursor.com>
The import/no-cycle refactor had moved IInsertEvent, IDeleteEvent, and
ICircularList into Types.ts, with CircularList.ts re-exporting the event
types from there. That split the list abstraction from its implementation
and pulled Types into the circular-list dependency graph.
Define IInsertEvent, IDeleteEvent, and ICircularList in CircularList.ts
alongside the CircularList class. CircularList.ts now depends only on
Lifecycle and Event, not Types.ts.
Remove those definitions from Types.ts (and the unused Emitter import).
Update callers to import list types from CircularList:
- buffer/Types.ts (IBuffer.lines)
- DecorationService.ts (buffer line insert/delete handlers)
- browser TestUtils.test.ts (mock buffer lines)
Types.ts no longer imports or re-exports circular-list types, preserving
the acyclic Types -> buffer/CircularList boundary.
Co-authored-by: Cursor <cursoragent@cursor.com>
The import/no-cycle refactor had moved IBuffer, IBufferSet, and related
cell/line types into src/common/Types.ts, with buffer/Types.ts only
re-exporting them. That inverted the natural module boundary and made
buffer code depend on the top-level types hub.
Define buffer-owned types in buffer/Types.ts instead:
- CharData, IExtendedAttrs, IAttributeData, ICellData, IBufferLine
- IMarker, IBuffer, IBufferSet, BufferIndex
Restore UnderlineStyle to buffer/Constants.ts (used by IExtendedAttrs)
and remove those definitions from Types.ts.
buffer/Types.ts imports only what it needs from outside the buffer layer:
ICircularList and ICharset from Types, IDisposable from Lifecycle,
IEvent from Event, and UnderlineStyle from Constants. Types.ts does not
import buffer/Types.ts, so the previous Types <-> buffer cycle stays broken.
Update imports across common, browser, headless, addons, and tests to use
common/buffer/Types for buffer types rather than common/Types.
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>
Replace the primary lint pipeline with oxlint and oxlint-tsgolint for type-aware TypeScript rules, preserving existing rule behavior from eslint.config.mjs via @oxlint/migrate and targeted jsPlugins (@stylistic/eslint-plugin, eslint-plugin-jsdoc as jsdoc-js, oxlint-plugin-eslint for no-restricted-syntax and object-curly-spacing).
Keep a hybrid ESLint pass (eslint.config.naming.mjs) only for @typescript-eslint/naming-convention until tsgolint implements it (oxc-project/tsgolint#186). Legacy eslint.config.mjs and eslint.config.typings.mjs remain for reference but are no longer used by npm scripts.
Add .oxlintrc.json for src/addons/demo/test and .oxlintrc.typings.json for typings/ (syntax-only, no --type-aware). Update lint, lint-fix, lint-api, and lint-changes to run oxlint first, then naming ESLint. Platform binaries install via oxlint-tsgolint optionalDependencies on Linux, macOS, and Windows.
Fixes https://github.com/xtermjs/xterm.js/issues/5690
Co-authored-by: Cursor <cursoragent@cursor.com>
Follow-up to https://github.com/xtermjs/xterm.js/issues/5896 / PR #5966.
Converting addons to ../../../src/common relative imports broke unit tests:
esbuild emits addon code under addons/*/out-esbuild/ without mirroring the
shared tree, so Node could not load TypeScript sources at runtime
(Cannot find module '../../../src/common/Lifecycle').
Core src/, test/, and headless continue to use relative imports with no
common/* path mappings. Addons keep the prior model until build layout
can share out-esbuild the same way as the main package.
Changes:
- Restore common/* and browser/* paths in addon src/test/benchmark tsconfigs
- Revert addon imports to common/ and browser/ path-mapped specifiers
- Restore NODE_PATH=out-esbuild in bin/test_unit.js for Mocha resolution
- Restore webpack resolve.alias on addons that bundle against out/
Fixes CI test-unit failures on remove-path-mappings-5896.
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>
Extract AltMouseCursorController to bind DOM listeners only when the option and mouse protocol are active.
Co-authored-by: Cursor <cursoragent@cursor.com>
Alt is only used locally to gate passthrough; applications like tmux ignore alt-modified SGR sequences.
Co-authored-by: Cursor <cursoragent@cursor.com>