From 543fefa7441194bfa3e8235072acb7333c10834a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sat, 11 Jan 2025 21:02:47 +0100 Subject: [PATCH] next approach --- .eslintrc.json | 1 - addons/addon-progress/src/ProgressAddon.ts | 17 ++--- addons/addon-progress/src/tsconfig.json | 6 -- .../addon-progress/test/ProgressAddon.test.ts | 2 +- .../typings/addon-progress.d.ts | 8 +-- addons/addon-progress/webpack.config.js | 1 - bin/esbuild.mjs | 1 - demo/client.ts | 12 ++-- src/browser/public/Terminal.ts | 32 +++++---- src/browser/tsconfig.json | 6 +- src/common/shared/AddonDisposable.ts | 19 ++++++ src/headless/public/Terminal.ts | 19 +++++- src/shared/shared.test.ts | 0 src/shared/shared.ts | 42 ------------ src/shared/tsconfig.json | 24 ------- typings/xterm-headless.d.ts | 27 ++++++++ typings/xterm.d.ts | 66 ++++--------------- webpack.config.js | 1 - 18 files changed, 106 insertions(+), 178 deletions(-) create mode 100644 src/common/shared/AddonDisposable.ts delete mode 100644 src/shared/shared.test.ts delete mode 100644 src/shared/shared.ts delete mode 100644 src/shared/tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json index 399ef0bc77..acd85af60a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,7 +11,6 @@ "src/browser/tsconfig.json", "src/common/tsconfig.json", "src/headless/tsconfig.json", - "src/shared/tsconfig.json", "src/vs/tsconfig.json", "test/benchmark/tsconfig.json", "test/playwright/tsconfig.json", diff --git a/addons/addon-progress/src/ProgressAddon.ts b/addons/addon-progress/src/ProgressAddon.ts index 5eec7380b5..a600844412 100644 --- a/addons/addon-progress/src/ProgressAddon.ts +++ b/addons/addon-progress/src/ProgressAddon.ts @@ -3,17 +3,9 @@ * @license MIT */ -import { Terminal, ITerminalAddon, IDisposable, EmitterCtorType, IEmitter, IEvent } from '@xterm/xterm'; +import { Terminal, ITerminalAddon, IDisposable, IEmitter, IEvent, ISharedExports } from '@xterm/xterm'; import type { ProgressAddon as IProgressApi, IProgressState } from '@xterm/addon-progress'; -// to use impl parts: - -// in 3rd party addons -// import { EmitterAddon } from '@xterm/xterm'; - -// in xtermjs repo addons -import { EmitterAddon } from 'shared/shared'; - const enum ProgressType { REMOVE = 0, @@ -40,16 +32,15 @@ function toInt(s: string): number { } -export class ProgressAddon extends EmitterAddon implements ITerminalAddon, IProgressApi { +export class ProgressAddon implements ITerminalAddon, IProgressApi { private _seqHandler: IDisposable | undefined; private _st: ProgressType = ProgressType.REMOVE; private _pr = 0; private _onChange: IEmitter; public onChange: IEvent; - constructor(protected readonly _emitterCtor: EmitterCtorType) { - super(_emitterCtor); - this._onChange = new this._emitterCtor(); + constructor(sharedExports: ISharedExports) { + this._onChange = new sharedExports.Emitter(); this.onChange = this._onChange.event; } diff --git a/addons/addon-progress/src/tsconfig.json b/addons/addon-progress/src/tsconfig.json index cb24712e6a..ffc7b01a58 100644 --- a/addons/addon-progress/src/tsconfig.json +++ b/addons/addon-progress/src/tsconfig.json @@ -22,9 +22,6 @@ "vs/*": [ "../../../src/vs/*" ], - "shared/*": [ - "../../../src/shared/*" - ], "@xterm/addon-progress": [ "../typings/addon-progress.d.ts" ] @@ -40,9 +37,6 @@ }, { "path": "../../../src/vs" - }, - { - "path": "../../../src/shared" } ] } diff --git a/addons/addon-progress/test/ProgressAddon.test.ts b/addons/addon-progress/test/ProgressAddon.test.ts index ce4177a981..e532148805 100644 --- a/addons/addon-progress/test/ProgressAddon.test.ts +++ b/addons/addon-progress/test/ProgressAddon.test.ts @@ -23,7 +23,7 @@ test.describe('ProgressAddon', () => { window.progressStack = []; window.term.reset(); window.progressAddon?.dispose(); - window.progressAddon = new ProgressAddon(emitterCtor); + window.progressAddon = new ProgressAddon(sharedExports); window.term.loadAddon(window.progressAddon); window.progressAddon.onChange(progress => window.progressStack.push(progress)); `); diff --git a/addons/addon-progress/typings/addon-progress.d.ts b/addons/addon-progress/typings/addon-progress.d.ts index ea89b9a795..d72f29bbde 100644 --- a/addons/addon-progress/typings/addon-progress.d.ts +++ b/addons/addon-progress/typings/addon-progress.d.ts @@ -3,20 +3,20 @@ * @license MIT */ -import { Terminal, ITerminalAddon, IDisposable, IEvent, EmitterCtorType } from '@xterm/xterm'; -import { EmitterAddon } from 'shared/shared'; +import { Terminal, ITerminalAddon, IDisposable, IEvent, ISharedExports } from '@xterm/xterm'; + declare module '@xterm/addon-progress' { /** * An xterm.js addon that provides an interface for ConEmu's progress * sequence. */ - export class ProgressAddon extends EmitterAddon implements ITerminalAddon, IDisposable { + export class ProgressAddon implements ITerminalAddon, IDisposable { /** * Creates a new progress addon */ - constructor(_emitterCtor: EmitterCtorType); + constructor(sharedExports: ISharedExports); /** * Activates the addon diff --git a/addons/addon-progress/webpack.config.js b/addons/addon-progress/webpack.config.js index f2e96cfd25..5ee2531dab 100644 --- a/addons/addon-progress/webpack.config.js +++ b/addons/addon-progress/webpack.config.js @@ -28,7 +28,6 @@ module.exports = { common: path.resolve('../../out/common'), browser: path.resolve('../../out/browser'), vs: path.resolve('../../out/vs'), - shared: path.resolve('../../out/shared') } }, output: { diff --git a/bin/esbuild.mjs b/bin/esbuild.mjs index d05b9194ff..1727defe54 100644 --- a/bin/esbuild.mjs +++ b/bin/esbuild.mjs @@ -176,7 +176,6 @@ if (config.addon) { 'src/browser/**/*.ts', 'src/common/**/*.ts', 'src/headless/**/*.ts', - 'src/shared/**/*.ts', 'src/vs/base/**/*.ts', 'src/vs/patches/**/*.ts' ], diff --git a/demo/client.ts b/demo/client.ts index 613475aa2c..6a87b8f5fc 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -16,7 +16,7 @@ if ('WebAssembly' in window) { ImageAddon = imageAddon.ImageAddon; } -import { Terminal, ITerminalOptions, type IDisposable, type ITheme, emitterCtor } from '@xterm/xterm'; +import { Terminal, ITerminalOptions, type IDisposable, type ITheme, sharedExports, ISharedExports } from '@xterm/xterm'; import { AttachAddon } from '@xterm/addon-attach'; import { ClipboardAddon } from '@xterm/addon-clipboard'; import { FitAddon } from '@xterm/addon-fit'; @@ -32,6 +32,7 @@ import { UnicodeGraphemesAddon } from '@xterm/addon-unicode-graphemes'; export interface IWindowWithTerminal extends Window { term: typeof Terminal; Terminal: typeof Terminal; + sharedExports: ISharedExports; AttachAddon?: typeof AttachAddon; // eslint-disable-line @typescript-eslint/naming-convention ClipboardAddon?: typeof ClipboardAddon; // eslint-disable-line @typescript-eslint/naming-convention FitAddon?: typeof FitAddon; // eslint-disable-line @typescript-eslint/naming-convention @@ -44,8 +45,6 @@ export interface IWindowWithTerminal extends Window { Unicode11Addon?: typeof Unicode11Addon; // eslint-disable-line @typescript-eslint/naming-convention UnicodeGraphemesAddon?: typeof UnicodeGraphemesAddon; // eslint-disable-line @typescript-eslint/naming-convention LigaturesAddon?: typeof LigaturesAddon; // eslint-disable-line @typescript-eslint/naming-convention - - emitterCtor?: typeof emitterCtor; } declare let window: IWindowWithTerminal; @@ -216,6 +215,7 @@ const createNewWindowButtonHandler: () => void = () => { if (document.location.pathname === '/test') { window.Terminal = Terminal; + window.sharedExports = sharedExports; window.AttachAddon = AttachAddon; window.ClipboardAddon = ClipboardAddon; window.FitAddon = FitAddon; @@ -228,8 +228,6 @@ if (document.location.pathname === '/test') { window.LigaturesAddon = LigaturesAddon; window.WebLinksAddon = WebLinksAddon; window.WebglAddon = WebglAddon; - - window.emitterCtor = emitterCtor; } else { createTerminal(); document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); @@ -283,7 +281,8 @@ function createTerminal(): void { addons.serialize.instance = new SerializeAddon(); addons.fit.instance = new FitAddon(); addons.image.instance = new ImageAddon(); - addons.progress.instance = new ProgressAddon(emitterCtor); + //addons.progress.instance = new ProgressAddon(Terminal as unknown as IXtermSharedImports); + addons.progress.instance = new ProgressAddon(sharedExports); addons.unicodeGraphemes.instance = new UnicodeGraphemesAddon(); addons.clipboard.instance = new ClipboardAddon(); try { // try to start with webgl renderer (might throw on older safari/webkit) @@ -664,6 +663,7 @@ function initAddons(term: Terminal): void { } if (checkbox.checked) { // HACK: Manually remove addons that cannot be changes + // FIXME: re-enable this once done with the sharedExports //addon.instance = new (addon as IDemoAddon>).ctor(); try { term.loadAddon(addon.instance); diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index e15db2df80..d09ada4213 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -6,14 +6,26 @@ import * as Strings from 'browser/LocalizableStrings'; import { CoreBrowserTerminal as TerminalCore } from 'browser/CoreBrowserTerminal'; import { IBufferRange, ITerminal } from 'browser/Types'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { ITerminalOptions } from 'common/Types'; import { AddonManager } from 'common/public/AddonManager'; import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; import { ParserApi } from 'common/public/ParserApi'; import { UnicodeApi } from 'common/public/UnicodeApi'; -import { IBufferNamespace as IBufferNamespaceApi, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, ILocalizableStrings, IMarker, IModes, IParser, ITerminalAddon, Terminal as ITerminalApi, ITerminalInitOnlyOptions, IUnicodeHandling } from '@xterm/xterm'; -import { type Event } from 'vs/base/common/event'; +import { IBufferNamespace as IBufferNamespaceApi, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, ILocalizableStrings, IMarker, IModes, IParser, ITerminalAddon, Terminal as ITerminalApi, ITerminalInitOnlyOptions, IUnicodeHandling, ISharedExports } from '@xterm/xterm'; +import { type Event, Emitter } from 'vs/base/common/event'; + + +/** + * EXPERIMENTAL: + * Expose certain building blocks on the module to be used at runtime in addons. + */ +export const sharedExports: ISharedExports = { + DisposableStore, + Emitter, + toDisposable +}; + /** * The set of options that only have an effect when set in the Terminal constructor. @@ -272,17 +284,3 @@ export class Terminal extends Disposable implements ITerminalApi { } } } - - -/** - * Expose often needed vs/* parts in addons. - * Exposed statically on the xterm package, - * so they can be used on addon ctors already. - */ -export { - DisposableAddon, - EmitterAddon, - DisposableEmitterAddon -} from 'shared/shared'; -export { DisposableStore as disposableStoreCtor, toDisposable } from 'vs/base/common/lifecycle'; -export { Emitter as emitterCtor } from 'vs/base/common/event'; diff --git a/src/browser/tsconfig.json b/src/browser/tsconfig.json index e1b73cf642..38854e260f 100644 --- a/src/browser/tsconfig.json +++ b/src/browser/tsconfig.json @@ -13,8 +13,7 @@ "baseUrl": "..", "paths": { "common/*": [ "./common/*" ], - "vs/*": [ "./vs/*" ], - "shared/*": [ "./shared/*" ], + "vs/*": [ "./vs/*" ] } }, "include": [ @@ -23,7 +22,6 @@ ], "references": [ { "path": "../common" }, - { "path": "../vs" }, - { "path": "../shared" }, + { "path": "../vs" } ] } diff --git a/src/common/shared/AddonDisposable.ts b/src/common/shared/AddonDisposable.ts new file mode 100644 index 0000000000..36f2d4f5f3 --- /dev/null +++ b/src/common/shared/AddonDisposable.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2024 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IDisposable, IDisposableStore, ISharedExports } from '@xterm/xterm'; + + +export class AddonDisposable implements IDisposable { + protected readonly _store: IDisposableStore; + + constructor(sharedExports: ISharedExports) { + this._store = new sharedExports.DisposableStore(); + } + + public dispose(): void { + this._store.dispose(); + } +} diff --git a/src/headless/public/Terminal.ts b/src/headless/public/Terminal.ts index 738570c9e7..6ab7f2f290 100644 --- a/src/headless/public/Terminal.ts +++ b/src/headless/public/Terminal.ts @@ -6,12 +6,25 @@ import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; import { ParserApi } from 'common/public/ParserApi'; import { UnicodeApi } from 'common/public/UnicodeApi'; -import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalInitOnlyOptions, IUnicodeHandling, Terminal as ITerminalApi } from '@xterm/headless'; +import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalInitOnlyOptions, IUnicodeHandling, Terminal as ITerminalApi, ISharedExports } from '@xterm/headless'; import { Terminal as TerminalCore } from 'headless/Terminal'; import { AddonManager } from 'common/public/AddonManager'; import { ITerminalOptions } from 'common/Types'; -import { Disposable } from 'vs/base/common/lifecycle'; -import type { Event } from 'vs/base/common/event'; +import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { type Event, Emitter } from 'vs/base/common/event'; + + +/** + * EXPERIMENTAL: + * Expose certain building blocks on the module to be used at runtime in addons. + */ +export const sharedExports: ISharedExports = { + DisposableStore, + Emitter, + toDisposable +}; + + /** * The set of options that only have an effect when set in the Terminal constructor. */ diff --git a/src/shared/shared.test.ts b/src/shared/shared.test.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/shared/shared.ts b/src/shared/shared.ts deleted file mode 100644 index 7d9e3b7a04..0000000000 --- a/src/shared/shared.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2024 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IDisposable, IDisposableStore, DisposableStoreCtorType, EmitterCtorType } from '@xterm/xterm'; - - -export class DisposableAddon implements IDisposable { - protected readonly _store: IDisposableStore; - - constructor(protected readonly _storeCtor: DisposableStoreCtorType) { - this._store = new _storeCtor(); - } - - public dispose(): void { - this._store.dispose(); - } -} - - -export class EmitterAddon { - constructor( - protected readonly _emitterCtor: EmitterCtorType - ) {} -} - - -export class DisposableEmitterAddon implements IDisposable { - protected readonly _store: IDisposableStore; - - constructor( - protected readonly _storeCtor: DisposableStoreCtorType, - protected readonly _emitterCtor: EmitterCtorType - ) { - this._store = new _storeCtor(); - } - - public dispose(): void { - this._store.dispose(); - } -} diff --git a/src/shared/tsconfig.json b/src/shared/tsconfig.json deleted file mode 100644 index e9b3673ab2..0000000000 --- a/src/shared/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": "../tsconfig-library-base", - "compilerOptions": { - "lib": [ - "es2015", - "es2016.Array.Include" - ], - "outDir": "../../out", - "types": [ - "../../node_modules/@types/mocha" - ], - "baseUrl": "..", - "paths": { - "vs/*": [ "./vs/*" ] - } - }, - "include": [ - "./**/*", - "../../typings/xterm.d.ts" - ], - "references": [ - { "path": "../vs" } - ] -} diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 1085db9b43..e696713e21 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -1358,4 +1358,31 @@ declare module '@xterm/headless' { */ readonly wraparoundMode: boolean; } + + /** + * EXPERIMENTAL: + * Module exposure of certain building blocks to be used at runtime in addons. + */ + export interface ISharedExports { + readonly DisposableStore: new() => IDisposableStore; + readonly Emitter: new() => IEmitter; + readonly toDisposable: (fn: () => void) => IDisposable; + } + + export const sharedExports: ISharedExports; + + // FIXME: @Tyriar - plz have a look at the following interfaces and + // to what degree those should be exposed or get stripped down + export interface IEmitter extends IDisposable { + event: IEvent; + fire(event: T): void; + hasListeners(): boolean; + } + export interface IDisposableStore extends IDisposable { + isDisposed: boolean; + clear(): void; + add(o: T): T; + delete(o: T): void; + deleteAndLeak(o: T): void; + } } diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index d3a24ad821..1c18c9f730 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1957,72 +1957,30 @@ declare module '@xterm/xterm' { readonly wraparoundMode: boolean; } - - /** - * Get Emitter constructor. - */ - export const emitterCtor: EmitterCtorType; - - /** - * Get DisposableStore contructor. - */ - export const disposableStoreCtor: DisposableStoreCtorType; - /** - * Turn a function into a Disposable. + * EXPERIMENTAL: + * Module exposure of certain building blocks to be used at runtime in addons. */ - export const toDisposable: (fn: () => void) => IDisposable; + export interface ISharedExports { + readonly DisposableStore: new() => IDisposableStore; + readonly Emitter: new() => IEmitter; + readonly toDisposable: (fn: () => void) => IDisposable; + } + export const sharedExports: ISharedExports; - export interface IEmitter { - dispose(): void; + // FIXME: @Tyriar - plz have a look at the following interfaces and + // to what degree those should be exposed or get stripped down + export interface IEmitter extends IDisposable { event: IEvent; fire(event: T): void; hasListeners(): boolean; } - - interface IDisposableStore extends IDisposable { - /** - * `true` if this object has been disposed of. - */ + export interface IDisposableStore extends IDisposable { isDisposed: boolean; - /** - * Dispose of all registered disposables but do not mark this object - * as disposed. - */ clear(): void; - /** - * Add a new {@link IDisposable disposable} to the collection. - */ add(o: T): T; - /** - * Deletes a disposable from store and disposes of it. - * This will not throw or warn and proceed to dispose the - * disposable even when the disposable is not part in the store. - */ delete(o: T): void; - /** - * Deletes the value from the store, but does not dispose it. - */ deleteAndLeak(o: T): void; } - - export type EmitterCtorType = new() => IEmitter; - export type DisposableStoreCtorType = new() => IDisposableStore; - - export class DisposableAddon implements IDisposable { - protected readonly _store: IDisposableStore; - constructor(_storeCtor: DisposableStoreCtorType); - public dispose(): void; - } - export class EmitterAddon { - protected readonly _emitterCtor: EmitterCtorType; - constructor(_emitterCtor: EmitterCtorType); - } - export class DisposableEmitterAddon implements IDisposable { - protected readonly _store: IDisposableStore; - protected readonly _emitterCtor: EmitterCtorType; - constructor(_storeCtor: DisposableStoreCtorType, _emitterCtor: EmitterCtorType); - public dispose(): void; - } } diff --git a/webpack.config.js b/webpack.config.js index 37b07d1bbe..123e31dfbb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -35,7 +35,6 @@ const config = { common: path.resolve('./out/common'), browser: path.resolve('./out/browser'), vs: path.resolve('./out/vs'), - shared: path.resolve('./out/shared') } }, output: {