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>
114 lines
5.1 KiB
Markdown
114 lines
5.1 KiB
Markdown
# xterm.js Copilot Instructions
|
|
|
|
## Architecture Overview
|
|
|
|
**Core Structure**: xterm.js is a multi-target terminal emulator with three main distributions:
|
|
- `src/browser/`: Full-featured browser terminal with DOM rendering
|
|
- `src/headless/`: Server-side terminal for Node.js (no DOM)
|
|
- `src/common/`: Shared core logic (parsing, buffer management, terminal state)
|
|
|
|
**Key Classes**:
|
|
- `Terminal` (browser/headless): Public API wrapper
|
|
- `CoreTerminal` (common): Core terminal logic and state
|
|
- `CoreBrowserTerminal` (browser): Browser-specific terminal implementation
|
|
|
|
## Development Workflow
|
|
|
|
**Build System**:
|
|
```bash
|
|
npm run build && npm run esbuild # Build all TypeScript and bundle
|
|
```
|
|
|
|
**Testing**:
|
|
- Unit tests: `npm run test-unit` (Mocha)
|
|
- Unit tests filtering to file: `npm run test-unit -- **/fileName.ts
|
|
- Per-addon unit tests: `npm run test-unit -- addons/addon-image/out-esbuild/*.test.js`
|
|
- Integration tests: `npm run test-integration` (Playwright across Chrome/Firefox/WebKit)
|
|
- Integration tests by file: `npm run test-integration -- test/playwright/InputHandler.test.ts`. Never use grep to filter tests, it doesn't work
|
|
- Integration tests by addon: `npm run test-integration -- --suite=addon-search`. Suites always follow the format `addon-<something>`
|
|
- Lint: `npm run lint` (oxlint with type-aware rules, then ESLint for `naming-convention` only), `npm run lint-api` for `typings/`, `npm run lint-fix` for oxlint auto-fix
|
|
- Lint changes: `npm run lint-changes` to lint only changed files, `npm run lint-changes-fix` to fix them
|
|
|
|
## Addon Development Pattern
|
|
|
|
All addons follow this structure:
|
|
```typescript
|
|
export class MyAddon implements ITerminalAddon {
|
|
activate(terminal: Terminal): void {
|
|
// Called when loaded via terminal.loadAddon()
|
|
// Register handlers, access terminal APIs
|
|
}
|
|
dispose(): void {
|
|
// Cleanup when addon is disposed
|
|
}
|
|
}
|
|
```
|
|
|
|
**Key Examples**:
|
|
- `addons/addon-fit/`: Terminal sizing
|
|
- `addons/addon-webgl/`: GPU-accelerated rendering
|
|
- `addons/addon-search/`: Text search functionality
|
|
|
|
## Project-Specific Conventions
|
|
|
|
**TypeScript Project Structure**: Uses TypeScript project references (`tsconfig.all.json`) for incremental builds across browser/headless/addons.
|
|
|
|
**API Design**:
|
|
- Browser and headless terminals share the same public API
|
|
- Proposed APIs require `allowProposedApi: true` option
|
|
- Constructor-only options (cols, rows) cannot be changed after instantiation
|
|
|
|
**Disposable Management**:
|
|
- When a disposable object can be replaced over time, prefer a registered `MutableDisposable` over manual dispose/reassign logic.
|
|
- Register it on the owning class (for example, `this._register(new MutableDisposable())`) and assign through `.value`; this automatically disposes the previous value and avoids accidentally leaking resources.
|
|
|
|
**TypeScript Constants**:
|
|
- Prefer `const enum` over top-level `const` declarations for primitive constants when appropriate, since values are inlined and avoid runtime property lookups.
|
|
|
|
**Testing Utilities**: Use `TestUtils.ts` helpers:
|
|
- `openTerminal(ctx, options)` for setup
|
|
- `pollFor(page, fn, expectedValue)` for async assertions
|
|
- `writeSync(page, data)` for terminal input
|
|
|
|
## Common Patterns
|
|
|
|
**Parser Integration**: Register custom escape sequence handlers:
|
|
```typescript
|
|
terminal.parser.registerCsiHandler('m', params => {
|
|
// Handle SGR sequences
|
|
return true; // Handled
|
|
});
|
|
```
|
|
|
|
**Buffer Access**: Read terminal content via buffer API:
|
|
```typescript
|
|
const line = terminal.buffer.active.getLine(0);
|
|
const cell = line?.getCell(0);
|
|
```
|
|
|
|
**Events**: All terminals emit standard events (onData, onResize, onRender) plus platform-specific ones.
|
|
|
|
## Critical Implementation Details
|
|
|
|
- Terminal rendering uses either DOM or WebGL renderers
|
|
- Buffer lines are immutable; create new instances for modifications
|
|
- Character width handling supports Unicode 11+ and grapheme clustering
|
|
- Mouse events translate web events to terminal protocols (X10, VT200, etc.)
|
|
- Color theming supports both palette and true color modes
|
|
|
|
## Writing unit tests
|
|
|
|
- Unit tests live alongside the source code file of the thing it's testing with a .test.ts suffix.
|
|
|
|
## Cursor Cloud specific instructions
|
|
|
|
**Demo server**: Start with `npm start` (port 3000). The demo server uses node-pty to spawn real shell sessions over WebSocket. Integration tests auto-start it via Playwright's `webServer` config, so you don't need to start it manually for `npm run test-integration`.
|
|
|
|
**Build before testing**: Always run `npm run build && npm run esbuild` before `npm run test-unit`. Integration tests also need `npm run esbuild-demo-client` and `npm run esbuild-demo-server`. The update script handles this automatically on session start.
|
|
|
|
**No external services**: This project has zero external dependencies (no databases, Docker, or APIs). Everything runs locally with Node.js.
|
|
|
|
**TypeScript compiler**: The project uses `tsgo` (native TypeScript compiler preview) rather than standard `tsc`. It's installed via the `@typescript/native-preview` package.
|
|
|
|
**Lint only changed files**: Prefer `npm run lint-changes` over `npm run lint` when iterating on code changes — it's significantly faster.
|