Skip to content

Latest commit

 

History

History
113 lines (84 loc) · 5.06 KB

File metadata and controls

113 lines (84 loc) · 5.06 KB

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:

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:

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:

terminal.parser.registerCsiHandler('m', params => {
  // Handle SGR sequences
  return true; // Handled
});

Buffer Access: Read terminal content via buffer API:

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.