From c01e4b7be7f98ee6f75369c36faaecde60d71d70 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Wed, 11 Feb 2026 10:56:30 -0800 Subject: [PATCH 1/4] Separate image storage per mechanism (sixel, iip) --- addons/addon-image/src/IIPHandler.ts | 5 ++- addons/addon-image/src/IIPImageStorage.ts | 26 +++++++++++ addons/addon-image/src/ImageAddon.ts | 8 +++- addons/addon-image/src/ImageStorage.ts | 31 ++++--------- addons/addon-image/src/SixelHandler.ts | 4 +- addons/addon-image/src/SixelImageStorage.ts | 50 +++++++++++++++++++++ 6 files changed, 96 insertions(+), 28 deletions(-) create mode 100644 addons/addon-image/src/IIPImageStorage.ts create mode 100644 addons/addon-image/src/SixelImageStorage.ts diff --git a/addons/addon-image/src/IIPHandler.ts b/addons/addon-image/src/IIPHandler.ts index 9662303f..76492c40 100644 --- a/addons/addon-image/src/IIPHandler.ts +++ b/addons/addon-image/src/IIPHandler.ts @@ -4,7 +4,8 @@ */ import { IImageAddonOptions, IOscHandler, IResetHandler, ITerminalExt } from './Types'; import { ImageRenderer } from './ImageRenderer'; -import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage'; +import { IIPImageStorage } from './IIPImageStorage'; +import { CELL_SIZE_DEFAULT } from './ImageStorage'; import Base64Decoder from 'xterm-wasm-parts/lib/base64/Base64Decoder.wasm'; import { HeaderParser, IHeaderFields, HeaderState } from './IIPHeaderParser'; import { imageType, UNSUPPORTED_TYPE } from './IIPMetrics'; @@ -40,7 +41,7 @@ export class IIPHandler implements IOscHandler, IResetHandler { constructor( private readonly _opts: IImageAddonOptions, private readonly _renderer: ImageRenderer, - private readonly _storage: ImageStorage, + private readonly _storage: IIPImageStorage, private readonly _coreTerminal: ITerminalExt ) { const maxEncodedBytes = Math.ceil(this._opts.iipSizeLimit * 4 / 3); diff --git a/addons/addon-image/src/IIPImageStorage.ts b/addons/addon-image/src/IIPImageStorage.ts new file mode 100644 index 00000000..0da91607 --- /dev/null +++ b/addons/addon-image/src/IIPImageStorage.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2023 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ImageStorage } from './ImageStorage'; + +/** + * IIP (iTerm Image Protocol) specific image storage controller. + * + * Wraps the shared ImageStorage with IIP protocol semantics: + * - Always uses scrolling mode (cursor advances with image) + */ +export class IIPImageStorage { + constructor( + private readonly _storage: ImageStorage + ) {} + + /** + * Add an IIP image to storage. + * Always uses scrolling mode — cursor advances past the image. + */ + public addImage(img: HTMLCanvasElement | ImageBitmap): void { + this._storage.addImage(img, true); + } +} diff --git a/addons/addon-image/src/ImageAddon.ts b/addons/addon-image/src/ImageAddon.ts index d18b59a0..4c30a104 100644 --- a/addons/addon-image/src/ImageAddon.ts +++ b/addons/addon-image/src/ImageAddon.ts @@ -9,6 +9,8 @@ import { IIPHandler } from './IIPHandler'; import { ImageRenderer } from './ImageRenderer'; import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage'; import { SixelHandler } from './SixelHandler'; +import { SixelImageStorage } from './SixelImageStorage'; +import { IIPImageStorage } from './IIPImageStorage'; import { ITerminalExt, IImageAddonOptions, IResetHandler } from './Types'; // default values of addon ctor options @@ -129,7 +131,8 @@ export class ImageAddon implements ITerminalAddon, IImageApi { // SIXEL handler if (this._opts.sixelSupport) { - const sixelHandler = new SixelHandler(this._opts, this._storage!, terminal); + const sixelStorage = new SixelImageStorage(this._storage!, this._opts, this._renderer!, terminal); + const sixelHandler = new SixelHandler(this._opts, sixelStorage, terminal); this._handlers.set('sixel', sixelHandler); this._disposeLater( terminal._core._inputHandler._parser.registerDcsHandler({ final: 'q' }, sixelHandler) @@ -138,7 +141,8 @@ export class ImageAddon implements ITerminalAddon, IImageApi { // iTerm IIP handler if (this._opts.iipSupport) { - const iipHandler = new IIPHandler(this._opts, this._renderer!, this._storage!, terminal); + const iipStorage = new IIPImageStorage(this._storage!); + const iipHandler = new IIPHandler(this._opts, this._renderer!, iipStorage, terminal); this._handlers.set('iip', iipHandler); this._disposeLater( terminal._core._inputHandler._parser.registerOscHandler(1337, iipHandler) diff --git a/addons/addon-image/src/ImageStorage.ts b/addons/addon-image/src/ImageStorage.ts index aea9b5e5..73a7cd69 100644 --- a/addons/addon-image/src/ImageStorage.ts +++ b/addons/addon-image/src/ImageStorage.ts @@ -216,28 +216,14 @@ export class ImageStorage implements IDisposable { this._fullyCleared = false; } - /** - * Only advance text cursor. - * This is an edge case from empty sixels carrying only a height but no pixels. - * Partially fixes https://github.com/jerch/xterm-addon-image/issues/37. - */ - public advanceCursor(height: number): void { - if (this._opts.sixelScrolling) { - let cellSize = this._renderer.cellSize; - if (cellSize.width === -1 || cellSize.height === -1) { - cellSize = CELL_SIZE_DEFAULT; - } - const rows = Math.ceil(height / cellSize.height); - for (let i = 1; i < rows; ++i) { - this._terminal._core._inputHandler.lineFeed(); - } - } - } - /** * Method to add an image to the storage. + * @param img - The image to add (canvas or bitmap). + * @param scrolling - When true, cursor advances with the image (lineFeed per row). + * When false, image is placed at (0,0) and cursor is restored (DECSET 80 / sixel origin mode). + * @returns The internal image ID assigned to the stored image. */ - public addImage(img: HTMLCanvasElement | ImageBitmap): void { + public addImage(img: HTMLCanvasElement | ImageBitmap, scrolling: boolean): number { // never allow storage to exceed memory limit this._evictOldest(img.width * img.height); @@ -259,7 +245,7 @@ export class ImageStorage implements IDisposable { let offset = originX; let tileCount = 0; - if (!this._opts.sixelScrolling) { + if (!scrolling) { buffer.x = 0; buffer.y = 0; offset = 0; @@ -273,7 +259,7 @@ export class ImageStorage implements IDisposable { this._writeToCell(line as IBufferLineExt, offset + col, imageId, row * cols + col); tileCount++; } - if (this._opts.sixelScrolling) { + if (scrolling) { if (row < rows - 1) this._terminal._core._inputHandler.lineFeed(); } else { if (++buffer.y >= termRows) break; @@ -283,7 +269,7 @@ export class ImageStorage implements IDisposable { this._terminal._core._inputHandler._dirtyRowTracker.markDirty(buffer.y); // cursor positioning modes - if (this._opts.sixelScrolling) { + if (scrolling) { buffer.x = offset; } else { buffer.x = originX; @@ -331,6 +317,7 @@ export class ImageStorage implements IDisposable { // finally add the image this._images.set(imageId, imgSpec); + return imageId; } diff --git a/addons/addon-image/src/SixelHandler.ts b/addons/addon-image/src/SixelHandler.ts index 07d90341..2f12fbe1 100644 --- a/addons/addon-image/src/SixelHandler.ts +++ b/addons/addon-image/src/SixelHandler.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { ImageStorage } from './ImageStorage'; +import { SixelImageStorage } from './SixelImageStorage'; import { IDcsHandler, IParams, IImageAddonOptions, ITerminalExt, AttributeData, IResetHandler, ReadonlyColorSet } from './Types'; import { toRGBA8888, BIG_ENDIAN, PALETTE_ANSI_256, PALETTE_VT340_COLOR } from 'sixel/lib/Colors'; import { RGBA8888 } from 'sixel/lib/Types'; @@ -26,7 +26,7 @@ export class SixelHandler implements IDcsHandler, IResetHandler { constructor( private readonly _opts: IImageAddonOptions, - private readonly _storage: ImageStorage, + private readonly _storage: SixelImageStorage, private readonly _coreTerminal: ITerminalExt ) { DecoderAsync({ diff --git a/addons/addon-image/src/SixelImageStorage.ts b/addons/addon-image/src/SixelImageStorage.ts new file mode 100644 index 00000000..4c5f555b --- /dev/null +++ b/addons/addon-image/src/SixelImageStorage.ts @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2020 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage'; +import { IImageAddonOptions, ITerminalExt } from './Types'; +import { ImageRenderer } from './ImageRenderer'; + +/** + * Sixel-specific image storage controller. + * + * Wraps the shared ImageStorage with sixel protocol semantics: + * - Cursor behavior governed by DECSET 80 (sixelScrolling option) + * - advanceCursor for empty sixels carrying only height + */ +export class SixelImageStorage { + constructor( + private readonly _storage: ImageStorage, + private readonly _opts: IImageAddonOptions, + private readonly _renderer: ImageRenderer, + private readonly _terminal: ITerminalExt + ) {} + + /** + * Add a sixel image to storage. + * Cursor behavior depends on the sixelScrolling option (DECSET 80). + */ + public addImage(img: HTMLCanvasElement | ImageBitmap): void { + this._storage.addImage(img, this._opts.sixelScrolling); + } + + /** + * Only advance text cursor. + * This is an edge case from empty sixels carrying only a height but no pixels. + * Partially fixes https://github.com/jerch/xterm-addon-image/issues/37. + */ + public advanceCursor(height: number): void { + if (this._opts.sixelScrolling) { + let cellSize = this._renderer.cellSize; + if (cellSize.width === -1 || cellSize.height === -1) { + cellSize = CELL_SIZE_DEFAULT; + } + const rows = Math.ceil(height / cellSize.height); + for (let i = 1; i < rows; ++i) { + this._terminal._core._inputHandler.lineFeed(); + } + } + } +} From eccbc60aa0f0b05ef74bbc48d7ec29570a7ae9c4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Feb 2026 05:29:22 -0800 Subject: [PATCH 2/4] Migrate to tsgo Fixes #5689 --- addons/addon-attach/package.json | 2 +- addons/addon-attach/test/tsconfig.json | 4 +- addons/addon-clipboard/package.json | 2 +- addons/addon-clipboard/test/tsconfig.json | 4 +- addons/addon-fit/package.json | 2 +- addons/addon-fit/test/tsconfig.json | 4 +- addons/addon-image/package.json | 2 +- addons/addon-image/src/tsconfig.json | 4 +- addons/addon-image/test/tsconfig.json | 4 +- addons/addon-ligatures/package.json | 4 +- addons/addon-ligatures/test/tsconfig.json | 6 +- addons/addon-progress/package.json | 2 +- addons/addon-progress/test/tsconfig.json | 4 +- addons/addon-search/package.json | 2 +- addons/addon-search/test/tsconfig.json | 4 +- .../addon-serialize/benchmark/tsconfig.json | 2 +- addons/addon-serialize/package.json | 2 +- addons/addon-serialize/src/tsconfig.json | 2 +- addons/addon-serialize/test/tsconfig.json | 1 - .../benchmark/tsconfig.json | 2 +- addons/addon-unicode-graphemes/package.json | 2 +- .../addon-unicode-graphemes/src/tsconfig.json | 1 - .../test/tsconfig.json | 1 - addons/addon-unicode11/package.json | 2 +- addons/addon-unicode11/src/tsconfig.json | 4 +- addons/addon-unicode11/test/tsconfig.json | 4 +- addons/addon-web-fonts/package.json | 2 +- addons/addon-web-fonts/test/tsconfig.json | 4 +- addons/addon-web-links/package.json | 2 +- addons/addon-web-links/test/tsconfig.json | 4 +- addons/addon-webgl/package.json | 2 +- .../customGlyphs/CustomGlyphDefinitions.ts | 57 ++++----- addons/addon-webgl/src/tsconfig.json | 4 +- addons/addon-webgl/test/tsconfig.json | 4 +- demo/client/tsconfig.json | 5 +- demo/server/tsconfig.json | 3 +- package-lock.json | 118 ++++++++++++++++++ package.json | 5 +- src/browser/tsconfig.json | 5 +- src/common/services/Services.ts | 2 +- src/common/tsconfig.json | 4 +- src/headless/tsconfig.json | 4 +- test/benchmark/tsconfig.json | 1 - test/playwright/TestUtils.ts | 17 +-- test/playwright/tsconfig.json | 3 +- 45 files changed, 234 insertions(+), 85 deletions(-) diff --git a/addons/addon-attach/package.json b/addons/addon-attach/package.json index ca4ee237..7d874cd0 100644 --- a/addons/addon-attach/package.json +++ b/addons/addon-attach/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-attach/test/tsconfig.json b/addons/addon-attach/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-attach/test/tsconfig.json +++ b/addons/addon-attach/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-clipboard/package.json b/addons/addon-clipboard/package.json index 3ab8e7f3..176fa861 100644 --- a/addons/addon-clipboard/package.json +++ b/addons/addon-clipboard/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-clipboard/test/tsconfig.json b/addons/addon-clipboard/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-clipboard/test/tsconfig.json +++ b/addons/addon-clipboard/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-fit/package.json b/addons/addon-fit/package.json index 5b00a3b2..22158e79 100644 --- a/addons/addon-fit/package.json +++ b/addons/addon-fit/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-fit/test/tsconfig.json b/addons/addon-fit/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-fit/test/tsconfig.json +++ b/addons/addon-fit/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-image/package.json b/addons/addon-image/package.json index 5078a57f..3d5fa37f 100644 --- a/addons/addon-image/package.json +++ b/addons/addon-image/package.json @@ -18,7 +18,7 @@ "xterm.js" ], "scripts": { - "prepackage": "../../node_modules/.bin/tsc -p .", + "prepackage": "../../node_modules/.bin/tsgo -p .", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", "start": "node ../../demo/start" diff --git a/addons/addon-image/src/tsconfig.json b/addons/addon-image/src/tsconfig.json index a18b47c9..9a5d24c1 100644 --- a/addons/addon-image/src/tsconfig.json +++ b/addons/addon-image/src/tsconfig.json @@ -11,11 +11,11 @@ "types": [ "../../../node_modules/@types/mocha" ], - "baseUrl": ".", "paths": { "browser/*": [ "../../../src/browser/*" ], "common/*": [ "../../../src/common/*" ], - "@xterm/addon-image": [ "../typings/addon-image.d.ts" ] + "@xterm/addon-image": [ "../typings/addon-image.d.ts" ], + "*": [ "./*" ] } }, "include": [ diff --git a/addons/addon-image/test/tsconfig.json b/addons/addon-image/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-image/test/tsconfig.json +++ b/addons/addon-image/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-ligatures/package.json b/addons/addon-ligatures/package.json index 3117b7e8..1b972c95 100644 --- a/addons/addon-ligatures/package.json +++ b/addons/addon-ligatures/package.json @@ -14,8 +14,8 @@ "node": ">8.0.0" }, "scripts": { - "build": "tsc -p src", - "watch": "tsc -w -p src", + "build": "tsgo -p src", + "watch": "tsgo -w -p src", "prepackage": "npm run build", "package": "webpack", "pretest": "npm run build", diff --git a/addons/addon-ligatures/test/tsconfig.json b/addons/addon-ligatures/test/tsconfig.json index ca68b468..6986e2b4 100644 --- a/addons/addon-ligatures/test/tsconfig.json +++ b/addons/addon-ligatures/test/tsconfig.json @@ -9,8 +9,12 @@ "outDir": "../out-esbuild-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "strict": true, + "paths": { + "*": [ + "./*" + ] + }, "types": [ "../../../node_modules/@types/mocha", "../../../node_modules/@types/node" diff --git a/addons/addon-progress/package.json b/addons/addon-progress/package.json index 11e13abb..8b130d6c 100644 --- a/addons/addon-progress/package.json +++ b/addons/addon-progress/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-progress/test/tsconfig.json b/addons/addon-progress/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-progress/test/tsconfig.json +++ b/addons/addon-progress/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-search/package.json b/addons/addon-search/package.json index 2a8ca6f7..ebec5a8b 100644 --- a/addons/addon-search/package.json +++ b/addons/addon-search/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "prepackage": "../../node_modules/.bin/tsc -p .", + "prepackage": "../../node_modules/.bin/tsgo -p .", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", "start": "node ../../demo/start" diff --git a/addons/addon-search/test/tsconfig.json b/addons/addon-search/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-search/test/tsconfig.json +++ b/addons/addon-search/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-serialize/benchmark/tsconfig.json b/addons/addon-serialize/benchmark/tsconfig.json index 1f6429f6..afc3944a 100644 --- a/addons/addon-serialize/benchmark/tsconfig.json +++ b/addons/addon-serialize/benchmark/tsconfig.json @@ -4,13 +4,13 @@ "dom", "es2021" ], + "rootDir": "..", "outDir": "../out-benchmark", "types": ["../../../node_modules/@types/node"], "moduleResolution": "node", "strict": false, "target": "es2021", "module": "commonjs", - "baseUrl": ".", "paths": { "common/*": ["../../../src/common/*"], "browser/*": ["../../../src/browser/*"], diff --git a/addons/addon-serialize/package.json b/addons/addon-serialize/package.json index f6acb018..6fa91ffe 100644 --- a/addons/addon-serialize/package.json +++ b/addons/addon-serialize/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-serialize/src/tsconfig.json b/addons/addon-serialize/src/tsconfig.json index 6fb641ef..72564736 100644 --- a/addons/addon-serialize/src/tsconfig.json +++ b/addons/addon-serialize/src/tsconfig.json @@ -10,7 +10,6 @@ "outDir": "../out", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" @@ -23,6 +22,7 @@ ] }, "strict": true, + "skipLibCheck": true, "types": [ "../../../node_modules/@types/mocha" ] diff --git a/addons/addon-serialize/test/tsconfig.json b/addons/addon-serialize/test/tsconfig.json index cff27705..769909b1 100644 --- a/addons/addon-serialize/test/tsconfig.json +++ b/addons/addon-serialize/test/tsconfig.json @@ -9,7 +9,6 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" diff --git a/addons/addon-unicode-graphemes/benchmark/tsconfig.json b/addons/addon-unicode-graphemes/benchmark/tsconfig.json index c6f37a6c..47e6b53a 100644 --- a/addons/addon-unicode-graphemes/benchmark/tsconfig.json +++ b/addons/addon-unicode-graphemes/benchmark/tsconfig.json @@ -1,13 +1,13 @@ { "compilerOptions": { "lib": ["dom", "es6"], + "rootDir": "..", "outDir": "../out-benchmark", "types": ["../../../node_modules/@types/node"], "moduleResolution": "node", "strict": false, "target": "es2015", "module": "commonjs", - "baseUrl": ".", "paths": { "common/*": ["../../../src/common/*"], "browser/*": ["../../../src/browser/*"], diff --git a/addons/addon-unicode-graphemes/package.json b/addons/addon-unicode-graphemes/package.json index 16840770..640a61a7 100644 --- a/addons/addon-unicode-graphemes/package.json +++ b/addons/addon-unicode-graphemes/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-unicode-graphemes/src/tsconfig.json b/addons/addon-unicode-graphemes/src/tsconfig.json index e9967bbe..824909db 100644 --- a/addons/addon-unicode-graphemes/src/tsconfig.json +++ b/addons/addon-unicode-graphemes/src/tsconfig.json @@ -11,7 +11,6 @@ "sourceMap": true, "removeComments": true, "strict": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" diff --git a/addons/addon-unicode-graphemes/test/tsconfig.json b/addons/addon-unicode-graphemes/test/tsconfig.json index cff27705..769909b1 100644 --- a/addons/addon-unicode-graphemes/test/tsconfig.json +++ b/addons/addon-unicode-graphemes/test/tsconfig.json @@ -9,7 +9,6 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" diff --git a/addons/addon-unicode11/package.json b/addons/addon-unicode11/package.json index d027996b..65c9b076 100644 --- a/addons/addon-unicode11/package.json +++ b/addons/addon-unicode11/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-unicode11/src/tsconfig.json b/addons/addon-unicode11/src/tsconfig.json index 8eb7752b..31286fb0 100644 --- a/addons/addon-unicode11/src/tsconfig.json +++ b/addons/addon-unicode11/src/tsconfig.json @@ -11,13 +11,15 @@ "sourceMap": true, "removeComments": true, "strict": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "@xterm/addon-unicode11": [ "../typings/addon-unicode11.d.ts" + ], + "*": [ + "./*" ] }, "types": [ diff --git a/addons/addon-unicode11/test/tsconfig.json b/addons/addon-unicode11/test/tsconfig.json index cff27705..900a727e 100644 --- a/addons/addon-unicode11/test/tsconfig.json +++ b/addons/addon-unicode11/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-web-fonts/package.json b/addons/addon-web-fonts/package.json index 856c7e25..ee52931d 100644 --- a/addons/addon-web-fonts/package.json +++ b/addons/addon-web-fonts/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-web-fonts/test/tsconfig.json b/addons/addon-web-fonts/test/tsconfig.json index 120fccdc..4151488a 100644 --- a/addons/addon-web-fonts/test/tsconfig.json +++ b/addons/addon-web-fonts/test/tsconfig.json @@ -10,13 +10,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-web-links/package.json b/addons/addon-web-links/package.json index 214a26d4..d058376c 100644 --- a/addons/addon-web-links/package.json +++ b/addons/addon-web-links/package.json @@ -16,7 +16,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-web-links/test/tsconfig.json b/addons/addon-web-links/test/tsconfig.json index 120fccdc..4151488a 100644 --- a/addons/addon-web-links/test/tsconfig.json +++ b/addons/addon-web-links/test/tsconfig.json @@ -10,13 +10,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-webgl/package.json b/addons/addon-webgl/package.json index d8aea18c..4ad686b0 100644 --- a/addons/addon-webgl/package.json +++ b/addons/addon-webgl/package.json @@ -17,7 +17,7 @@ "xterm.js" ], "scripts": { - "build": "../../node_modules/.bin/tsc -p .", + "build": "../../node_modules/.bin/tsgo -p .", "prepackage": "npm run build", "package": "../../node_modules/.bin/webpack", "prepublishOnly": "npm run package", diff --git a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts index 22ffdfa9..c3529980 100644 --- a/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts +++ b/addons/addon-webgl/src/customGlyphs/CustomGlyphDefinitions.ts @@ -7,6 +7,35 @@ import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, /* eslint-disable max-len */ +const enum Shapes { + /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', + /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', + + /** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5', + /** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5', + /** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1', + /** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5', + + /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0', + /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5', + /** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5', + /** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1', + + /** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0', + /** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5', + /** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5', + /** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1', + + /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', + + /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled + /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled + /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled + /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9', + /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333', + /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95', +} + namespace GitBranchSymbolsParts { // Lines export const LINE_H: CustomGlyphDefinitionPart = Object.freeze({ type: CustomGlyphDefinitionType.PATH_FUNCTION, data: Shapes.LEFT_TO_RIGHT, strokeWidth: 1 }); @@ -988,31 +1017,3 @@ function segmentedDigit(pattern: number): string { return paths.join(' '); } -const enum Shapes { - /** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1', - /** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5', - - /** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5', - /** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5', - /** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1', - /** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5', - - /** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0', - /** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5', - /** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5', - /** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1', - - /** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0', - /** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5', - /** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5', - /** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1', - - /** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1', - - /** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled - /** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled - /** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled - /** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9', - /** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333', - /** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95', -} diff --git a/addons/addon-webgl/src/tsconfig.json b/addons/addon-webgl/src/tsconfig.json index 924d3762..aeb42a1b 100644 --- a/addons/addon-webgl/src/tsconfig.json +++ b/addons/addon-webgl/src/tsconfig.json @@ -10,7 +10,6 @@ "outDir": "../out", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" @@ -20,6 +19,9 @@ ], "@xterm/addon-webgl": [ "../typings/addon-webgl.d.ts" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/addons/addon-webgl/test/tsconfig.json b/addons/addon-webgl/test/tsconfig.json index c602c462..73439ddc 100644 --- a/addons/addon-webgl/test/tsconfig.json +++ b/addons/addon-webgl/test/tsconfig.json @@ -9,13 +9,15 @@ "outDir": "../out-test", "sourceMap": true, "removeComments": true, - "baseUrl": ".", "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" + ], + "*": [ + "./*" ] }, "strict": true, diff --git a/demo/client/tsconfig.json b/demo/client/tsconfig.json index 6c601531..244f19c6 100644 --- a/demo/client/tsconfig.json +++ b/demo/client/tsconfig.json @@ -5,8 +5,8 @@ "outDir": "../out-demo/client", "rootDir": ".", "sourceMap": true, - "baseUrl": ".", "strict": true, + "skipLibCheck": true, "paths": { "@xterm/addon-attach": ["../../addons/addon-attach"], "@xterm/addon-clipboard": ["../../addons/addon-clipboard"], @@ -20,7 +20,8 @@ "@xterm/addon-webgl": ["../../addons/addon-webgl"], "@xterm/addon-unicode11": ["../../addons/addon-unicode11"], "@xterm/addon-unicode-graphemes": ["../../addons/addon-unicode-graphemes"], - "@xterm/addon-ligatures": ["../../addons/addon-ligatures"] + "@xterm/addon-ligatures": ["../../addons/addon-ligatures"], + "*": ["./*"] } }, "include": [ diff --git a/demo/server/tsconfig.json b/demo/server/tsconfig.json index 2cddc3c9..e31d6904 100644 --- a/demo/server/tsconfig.json +++ b/demo/server/tsconfig.json @@ -5,7 +5,8 @@ "outDir": "../out-demo/server", "rootDir": ".", "sourceMap": true, - "esModuleInterop": true + "esModuleInterop": true, + "skipLibCheck": true }, "include": [ "./**/*", diff --git a/package-lock.json b/package-lock.json index 791c0521..9c83261b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@types/ws": "^8.2.0", "@typescript-eslint/eslint-plugin": "^8.50.1", "@typescript-eslint/parser": "^8.50.1", + "@typescript/native-preview": "^7.0.0-dev.20260213.1", "chai": "^4.3.4", "concurrently": "^9.1.2", "cross-env": "^7.0.3", @@ -1970,6 +1971,123 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript/native-preview": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-TZ/0Tv954jRpn5IHQJZQF0gaNmw//ZTvkgr3nC2H8u9t4GxUhIk5vfAHVFgdl8JnNGbl7gZks37FVsEwXjdHqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsgo": "bin/tsgo.js" + }, + "optionalDependencies": { + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260213.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260213.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20260213.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260213.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20260213.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260213.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20260213.1" + } + }, + "node_modules/@typescript/native-preview-darwin-arm64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-nqfuHgFZ8MvaHeb1XOkAGIGc6cR91dwQdlHmlbH918n63JguKzkYjzzulpr48IVn1SVewGwjtfs1moCpaDpWcg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-darwin-x64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-JDVDVLPIYhYZR12omTKwzKbdw+wnPEtLnkmM+nioqbISlV29fg7IBgFx0/mf1D+Gz1ztUQVHDTqw4GEgOZ9VTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@typescript/native-preview-linux-arm": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-O6iVB8tTnLZJVYrChH6VJuCwqAa2ObWVdMtrKQw5UtmLXBhsOhZ3isttSuGzQrPfTiGN091IdW1KuRi8Ft1lnQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-arm64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-d7Gwl8W4aics0KI4H0zz3TP1ngnP8L5COND0TPBZ7ifWVrxKDNSLhF2V9OuStW43RPfA4Gzik9iIv+l0Lg+eGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-linux-x64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-Aq55fID1fE5/8K4XvfVddgw8LKUgY3kp5IOb+QEklfyle4MuAV5gtat3MnEv9XMbiidk8iKVxYrYASlUQEQzDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@typescript/native-preview-win32-arm64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-VlyULgXApmGMSqAANjskGx0AcjHchf3I8rhZ47AxF/XKAkZPe/5ewfleJ97iln7dg1UL3lq2cJY2CXxU+JPcFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@typescript/native-preview-win32-x64": { + "version": "7.0.0-dev.20260213.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260213.1.tgz", + "integrity": "sha512-lEtWvZDa2oCgqJ2gbP6BRLUeTyHLyrt5BfJmVlvmVSTZzdoBpFROJdp9yprsa2Zry2o5GK8HFAxd3RlvxkOU5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", diff --git a/package.json b/package.json index 5ae5a4e7..8c0f4462 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "dev": "concurrently -k -p [{name}] -n tsc,esbuild,esbuild-demo-client,esbuild-demo-server,server -c blue,yellow,cyan,green,magenta \"npm:tsc-watch\" \"npm:esbuild-watch\" \"npm:esbuild-demo-client-watch\" \"npm:esbuild-demo-server-watch\" \"npm:start\"", "build": "npm run tsc", "watch": "npm run tsc-watch", - "tsc": "tsc -b ./tsconfig.all.json", - "tsc-watch": "tsc -b -w ./tsconfig.all.json --preserveWatchOutput", + "tsc": "tsgo -b ./tsconfig.all.json", + "tsc-watch": "tsgo -b -w ./tsconfig.all.json --preserveWatchOutput", "esbuild": "node bin/esbuild_all.mjs", "esbuild-watch": "node bin/esbuild_all.mjs --watch", "esbuild-package": "node bin/esbuild_all.mjs --prod", @@ -92,6 +92,7 @@ "@types/ws": "^8.2.0", "@typescript-eslint/eslint-plugin": "^8.50.1", "@typescript-eslint/parser": "^8.50.1", + "@typescript/native-preview": "^7.0.0-dev.20260213.1", "chai": "^4.3.4", "concurrently": "^9.1.2", "cross-env": "^7.0.3", diff --git a/src/browser/tsconfig.json b/src/browser/tsconfig.json index 673a55a6..ff5bf6ad 100644 --- a/src/browser/tsconfig.json +++ b/src/browser/tsconfig.json @@ -9,9 +9,10 @@ "types": [ "../../node_modules/@types/mocha" ], - "baseUrl": "..", + "skipLibCheck": true, "paths": { - "common/*": [ "./common/*" ] + "common/*": [ "./../common/*" ], + "*": [ "./../*" ] } }, "include": [ diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index b40f16fd..e0af27ee 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty, type IOverviewRulerOptions } from '@xterm/xterm'; +import type { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty, IOverviewRulerOptions } from '@xterm/xterm'; import { CoreMouseEncoding, CoreMouseEventType, CursorInactiveStyle, CursorStyle, IAttributeData, ICharset, IColor, ICoreMouseEvent, ICoreMouseProtocol, IDecPrivateModes, IDisposable, IKittyKeyboardState, IModes, IOscLinkData, IWindowOptions } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { createDecorator } from 'common/services/ServiceRegistry'; diff --git a/src/common/tsconfig.json b/src/common/tsconfig.json index 28f5205c..22501b9c 100644 --- a/src/common/tsconfig.json +++ b/src/common/tsconfig.json @@ -9,9 +9,9 @@ "types": [ "../../node_modules/@types/mocha" ], - "baseUrl": "..", "paths": { - "common/*": [ "./common/*" ] + "common/*": [ "./../common/*" ], + "*": [ "./../*" ] } }, "include": [ diff --git a/src/headless/tsconfig.json b/src/headless/tsconfig.json index e48c4fd5..6ae7b1dc 100644 --- a/src/headless/tsconfig.json +++ b/src/headless/tsconfig.json @@ -10,9 +10,9 @@ "../../node_modules/@types/mocha", "../../node_modules/@types/node" ], - "baseUrl": "../", "paths": { - "common/*": [ "./common/*" ] + "common/*": [ "./../common/*" ], + "*": [ "./../*" ] } }, "include": [ diff --git a/test/benchmark/tsconfig.json b/test/benchmark/tsconfig.json index 8d1736df..2f24f076 100644 --- a/test/benchmark/tsconfig.json +++ b/test/benchmark/tsconfig.json @@ -12,7 +12,6 @@ "strict": false, "target": "es2021", "module": "commonjs", - "baseUrl": ".", "paths": { "common/*": [ "../../src/common/*" ], "browser/*": [ "../../src/browser/*" ], diff --git a/test/playwright/TestUtils.ts b/test/playwright/TestUtils.ts index f1569d41..8a76c882 100644 --- a/test/playwright/TestUtils.ts +++ b/test/playwright/TestUtils.ts @@ -9,9 +9,10 @@ import type { IRenderDimensions as IRenderDimensionsInternal } from 'browser/ren import type { IRenderService } from 'browser/services/Services'; import type { ICoreTerminal, IDisposable, IMarker } from 'common/Types'; import * as playwright from '@playwright/test'; -import { PageFunction } from 'playwright-core/types/structs'; import { IBuffer, IBufferCell, IBufferLine, IBufferNamespace, IBufferRange, IDecoration, IDecorationOptions, IModes, IRenderDimensions, ITerminalInitOnlyOptions, ITerminalOptions, Terminal } from '@xterm/xterm'; +type PageFunction = (arg: Arg) => R | Promise; + export interface ITestContext { browser: Browser; page: Page; @@ -106,7 +107,7 @@ type PlaywrightApiProxy(pageFunction: PageFunction[], T>): Promise; + evaluate(pageFunction: PageFunction): Promise; write(data: string | Uint8Array): Promise; } @@ -288,11 +289,11 @@ export class TerminalProxy implements ITerminalProxyCustomMethods, PlaywrightApi public async clearTextureAtlas(): Promise { return this.evaluate(([term]) => term.clearTextureAtlas()); } // #endregion - public async evaluate(pageFunction: PageFunction[], T>): Promise { + public async evaluate(pageFunction: PageFunction): Promise { return this._page.evaluate(pageFunction, [await this.getHandle()]); } - public async evaluateHandle(pageFunction: PageFunction[], T>): Promise> { + public async evaluateHandle(pageFunction: PageFunction): Promise> { return this._page.evaluateHandle(pageFunction, [await this.getHandle()]); } @@ -342,7 +343,7 @@ class TerminalBufferProxy /* implements EnsureAsyncProperties*/ { return undefined; } - public async evaluate(pageFunction: PageFunction[], T>): Promise { + public async evaluate(pageFunction: PageFunction): Promise { return this._page.evaluate(pageFunction, [await this._handle]); } } @@ -373,7 +374,7 @@ class TerminalBufferLine { return undefined; } - public async evaluate(pageFunction: PageFunction[], T>): Promise { + public async evaluate(pageFunction: PageFunction): Promise { return this._page.evaluate(pageFunction, [this._handle]); } } @@ -414,7 +415,7 @@ class TerminalBufferCell { public isAttributeDefault(): Promise { return this.evaluate(([cell]) => cell.isAttributeDefault()); } - public async evaluate(pageFunction: PageFunction[], T>): Promise { + public async evaluate(pageFunction: PageFunction): Promise { return this._page.evaluate(pageFunction, [this._handle]); } } @@ -438,7 +439,7 @@ class TerminalCoreProxy { return this._proxy.evaluateHandle(([term]) => (term as any)._core as ICoreTerminal); } - public async evaluate(pageFunction: PageFunction[], T>): Promise { + public async evaluate(pageFunction: PageFunction): Promise { return this._page.evaluate(pageFunction, [await this._getCoreHandle()]); } } diff --git a/test/playwright/tsconfig.json b/test/playwright/tsconfig.json index 255e6eb0..f1372e89 100644 --- a/test/playwright/tsconfig.json +++ b/test/playwright/tsconfig.json @@ -14,8 +14,9 @@ "removeComments": true, "pretty": true, "strict": true, + "noImplicitAny": false, "declaration": true, - "baseUrl": ".", + "moduleResolution": "node", "paths": { "browser/*": [ "../../src/browser/*" From e60c96823d45e89c2d8dea6e0ab7cb280dccd57a Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:10:16 -0800 Subject: [PATCH 3/4] Add hook to setup repo when agent starts Fixes #5605 --- .github/hooks/setupRepo.json | 10 +++ bin/agent/setup-repo.mjs | 138 +++++++++++++++++++++++++++++++++++ package.json | 3 +- 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 .github/hooks/setupRepo.json create mode 100644 bin/agent/setup-repo.mjs diff --git a/.github/hooks/setupRepo.json b/.github/hooks/setupRepo.json new file mode 100644 index 00000000..5dd0c656 --- /dev/null +++ b/.github/hooks/setupRepo.json @@ -0,0 +1,10 @@ +{ + "hooks": { + "SessionStart": [ + { + "type": "command", + "command": "npm run agent:setup-repo" + } + ] + } +} \ No newline at end of file diff --git a/bin/agent/setup-repo.mjs b/bin/agent/setup-repo.mjs new file mode 100644 index 00000000..2db85d87 --- /dev/null +++ b/bin/agent/setup-repo.mjs @@ -0,0 +1,138 @@ +// @ts-check + +import { cpSync, existsSync, lstatSync, readFileSync } from 'node:fs'; +import { spawnSync } from 'node:child_process'; +import { basename, dirname, resolve, sep } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const nodeModulesPath = resolve(repoRoot, 'node_modules'); +const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; + +/** @typedef {{ folder: string; reason: string }} Candidate */ + +/** @param {string} message */ +function log(message) { + console.info(`[setup-fast] ${message}`); +} + +/** @param {string[]} args */ +function runNpm(args) { + log(`Running: npm ${args.join(' ')}`); + const result = spawnSync(npmExecutable, args, { + cwd: repoRoot, + stdio: 'inherit' + }); + if (result.error) { + throw result.error; + } + if ((result.status ?? 1) !== 0) { + process.exit(result.status ?? 1); + } +} + +/** + * @param {Candidate[]} candidates + * @param {string | undefined} folder + * @param {string} reason + */ +function addCandidate(candidates, folder, reason) { + if (!folder) { + return; + } + if (candidates.some(candidate => candidate.folder === folder)) { + return; + } + candidates.push({ folder, reason }); + log(`Candidate found (${reason}): ${folder}`); +} + +function detectMainSiblingFolder() { + const currentFolderName = basename(repoRoot); + if (!currentFolderName.startsWith('xterm.js') || currentFolderName === 'xterm.js') { + log(`Current folder is "${currentFolderName}", skipping xterm.js sibling lookup.`); + return undefined; + } + const siblingFolder = resolve(dirname(repoRoot), 'xterm.js'); + log(`Current folder is "${currentFolderName}", sibling main folder candidate: ${siblingFolder}`); + return siblingFolder; +} + +function detectWorktreeMainFolder() { + const gitPath = resolve(repoRoot, '.git'); + if (!existsSync(gitPath)) { + log('No .git entry found at repo root.'); + return undefined; + } + const gitStat = lstatSync(gitPath); + if (!gitStat.isFile()) { + log('.git is not a file, this repo does not appear to be a worktree checkout.'); + return undefined; + } + const gitFileContent = readFileSync(gitPath, 'utf8').trim(); + const gitDirMatch = /^gitdir:\s*(.+)$/m.exec(gitFileContent); + if (!gitDirMatch) { + log('Could not parse gitdir from .git file.'); + return undefined; + } + + const gitDirPath = resolve(repoRoot, gitDirMatch[1].trim()); + log(`Parsed gitdir from .git file: ${gitDirPath}`); + + const normalizedGitDirPath = gitDirPath.replace(/\\/g, '/'); + const worktreeMarker = '/.git/worktrees/'; + const markerIndex = normalizedGitDirPath.indexOf(worktreeMarker); + if (markerIndex === -1) { + log('gitdir path does not contain /.git/worktrees/, skipping worktree main folder lookup.'); + return undefined; + } + + const normalizedMainFolder = normalizedGitDirPath.slice(0, markerIndex); + const mainFolder = sep === '/' ? normalizedMainFolder : normalizedMainFolder.split('/').join(sep); + log(`Worktree main folder candidate: ${mainFolder}`); + return mainFolder; +} + +function resolveSourceFolder() { + /** @type {Candidate[]} */ + const candidates = []; + addCandidate(candidates, detectMainSiblingFolder(), 'xterm.js sibling'); + addCandidate(candidates, detectWorktreeMainFolder(), 'worktree main repo'); + + for (const candidate of candidates) { + const candidateNodeModulesPath = resolve(candidate.folder, 'node_modules'); + if (existsSync(candidateNodeModulesPath)) { + log(`Using candidate (${candidate.reason}) with node_modules: ${candidate.folder}`); + return candidate.folder; + } + log(`Candidate skipped (${candidate.reason}), node_modules missing: ${candidateNodeModulesPath}`); + } + + log('No candidate folder with node_modules was found.'); + return undefined; +} + +if (!existsSync(nodeModulesPath)) { + log(`node_modules missing: ${nodeModulesPath}`); + const sourceFolder = resolveSourceFolder(); + if (sourceFolder) { + const sourceNodeModulesPath = resolve(sourceFolder, 'node_modules'); + log(`Copying node_modules from ${sourceNodeModulesPath} to ${nodeModulesPath}`); + try { + cpSync(sourceNodeModulesPath, nodeModulesPath, { recursive: true }); + log('node_modules copy completed.'); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + log(`node_modules copy failed: ${message}`); + log('Falling back to npm ci.'); + runNpm(['ci']); + } + } else { + log('No source folder available, running npm ci.'); + runNpm(['ci']); + } +} else { + log(`node_modules already exists: ${nodeModulesPath}`); +} + +runNpm(['run', 'setup']); diff --git a/package.json b/package.json index 8c0f4462..267477a1 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,8 @@ "prepackage-headless": "npm run esbuild-package-headless-only", "package-headless": "webpack --config ./webpack.config.headless.js", "postpackage-headless": "node ./bin/package_headless.js", - "prepublishOnly": "npm run package" + "prepublishOnly": "npm run package", + "agent:session-start": "node bin/agent/setup-repo.mjs" }, "devDependencies": { "@lunapaint/png-codec": "^0.2.0", From fbf1f7bc5d48e1c092182ed6eea7dee3e30278ec Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 13 Feb 2026 08:25:59 -0800 Subject: [PATCH 4/4] Fix hook npm script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 267477a1..15156654 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "package-headless": "webpack --config ./webpack.config.headless.js", "postpackage-headless": "node ./bin/package_headless.js", "prepublishOnly": "npm run package", - "agent:session-start": "node bin/agent/setup-repo.mjs" + "agent:setup-repo": "node bin/agent/setup-repo.mjs" }, "devDependencies": { "@lunapaint/png-codec": "^0.2.0",