Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
jerch committed Jan 11, 2025
1 parent 543fefa commit 893d89a
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 43 deletions.
6 changes: 3 additions & 3 deletions addons/addon-image/src/ImageAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @license MIT
*/

import type { ITerminalAddon, IDisposable } from '@xterm/xterm';
import type { ITerminalAddon, IDisposable, ISharedExports } from '@xterm/xterm';
import type { ImageAddon as IImageApi } from '@xterm/addon-image';
import { IIPHandler } from './IIPHandler';
import { ImageRenderer } from './ImageRenderer';
Expand Down Expand Up @@ -57,7 +57,7 @@ export class ImageAddon implements ITerminalAddon , IImageApi {
private _terminal: ITerminalExt | undefined;
private _handlers: Map<String, IResetHandler> = new Map();

constructor(opts?: Partial<IImageAddonOptions>) {
constructor(private _sharedExports: ISharedExports, opts?: Partial<IImageAddonOptions>) {
this._opts = Object.assign({}, DEFAULT_OPTIONS, opts);
this._defaultOpts = Object.assign({}, DEFAULT_OPTIONS, opts);
}
Expand All @@ -80,7 +80,7 @@ export class ImageAddon implements ITerminalAddon , IImageApi {
this._terminal = terminal;

// internal data structures
this._renderer = new ImageRenderer(terminal);
this._renderer = new ImageRenderer(this._sharedExports, terminal);
this._storage = new ImageStorage(terminal, this._renderer, this._opts);

// enable size reports
Expand Down
15 changes: 8 additions & 7 deletions addons/addon-image/src/ImageRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*/

import { toRGBA8888 } from 'sixel/lib/Colors';
import { IDisposable } from '@xterm/xterm';
import { IDisposable, IMutableDisposable, ISharedExports } from '@xterm/xterm';
import { ICellSize, ITerminalExt, IImageSpec, IRenderDimensions, IRenderService } from './Types';
import { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { AddonDisposable } from 'common/shared/AddonDisposable';

const PLACEHOLDER_LENGTH = 4096;
const PLACEHOLDER_HEIGHT = 24;
Expand All @@ -17,12 +17,12 @@ const PLACEHOLDER_HEIGHT = 24;
* - add canvas layer to DOM (browser only for now)
* - draw image tiles onRender
*/
export class ImageRenderer extends Disposable implements IDisposable {
export class ImageRenderer extends AddonDisposable implements IDisposable {
public canvas: HTMLCanvasElement | undefined;
private _ctx: CanvasRenderingContext2D | null | undefined;
private _placeholder: HTMLCanvasElement | undefined;
private _placeholderBitmap: ImageBitmap | undefined;
private _optionsRefresh = this._register(new MutableDisposable());
private _optionsRefresh: IMutableDisposable<IDisposable>;
private _oldOpen: ((parent: HTMLElement) => void) | undefined;
private _renderService: IRenderService | undefined;
private _oldSetRenderer: ((renderer: any) => void) | undefined;
Expand Down Expand Up @@ -67,8 +67,8 @@ export class ImageRenderer extends Disposable implements IDisposable {
}


constructor(private _terminal: ITerminalExt) {
super();
constructor(sharedExports: ISharedExports, private _terminal: ITerminalExt) {
super(sharedExports);
this._oldOpen = this._terminal._core.open;
this._terminal._core.open = (parent: HTMLElement): void => {
this._oldOpen?.call(this._terminal._core, parent);
Expand All @@ -78,13 +78,14 @@ export class ImageRenderer extends Disposable implements IDisposable {
this._open();
}
// hack to spot fontSize changes
this._optionsRefresh = new sharedExports.MutableDisposable();
this._optionsRefresh.value = this._terminal._core.optionsService.onOptionChange(option => {
if (option === 'fontSize') {
this.rescaleCanvas();
this._renderService?.refreshRows(0, this._terminal.rows);
}
});
this._register(toDisposable(() => {
this._register(sharedExports.toDisposable(() => {
this.removeLayerFromDom();
if (this._terminal._core && this._oldOpen) {
this._terminal._core.open = this._oldOpen;
Expand Down
7 changes: 4 additions & 3 deletions addons/addon-image/test/ImageAddon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { readFileSync } from 'fs';
import { FINALIZER, introducer, sixelEncode } from 'sixel';
import { ITestContext, createTestContext, openTerminal, pollFor, timeout } from '../../../test/playwright/TestUtils';
import { deepStrictEqual, ok, strictEqual } from 'assert';
import { ISharedExports } from '@xterm/xterm';

/**
* Plugin ctor options.
Expand All @@ -27,7 +28,7 @@ export interface IImageAddonOptions {

// eslint-disable-next-line
declare const ImageAddon: {
new(options?: Partial<IImageAddonOptions>): any;
new(sharedExports: ISharedExports, options?: Partial<IImageAddonOptions>): any;
};

interface ITestData {
Expand Down Expand Up @@ -91,7 +92,7 @@ test.describe('ImageAddon', () => {
await ctx.page.evaluate(`
window.term.reset()
window.imageAddon?.dispose();
window.imageAddon = new ImageAddon({ sixelPaletteLimit: 512 });
window.imageAddon = new ImageAddon(sharedExports, { sixelPaletteLimit: 512 });
window.term.loadAddon(window.imageAddon);
`);
});
Expand Down Expand Up @@ -152,7 +153,7 @@ test.describe('ImageAddon', () => {
iipSizeLimit: 1000
};
await ctx.page.evaluate(opts => {
(window as any).imageAddonCustom = new ImageAddon(opts.opts);
(window as any).imageAddonCustom = new ImageAddon((window as any).sharedExports, opts.opts);
(window as any).term.loadAddon((window as any).imageAddonCustom);
}, { opts: customSettings });
deepStrictEqual(await ctx.page.evaluate(`window.imageAddonCustom._opts`), customSettings);
Expand Down
4 changes: 2 additions & 2 deletions addons/addon-image/typings/addon-image.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @license MIT
*/

import { Terminal, ITerminalAddon } from '@xterm/xterm';
import { Terminal, ITerminalAddon, ISharedExports } from '@xterm/xterm';

declare module '@xterm/addon-image' {
export interface IImageAddonOptions {
Expand Down Expand Up @@ -79,7 +79,7 @@ declare module '@xterm/addon-image' {
}

export class ImageAddon implements ITerminalAddon {
constructor(options?: IImageAddonOptions);
constructor(sharedExports: ISharedExports, options?: IImageAddonOptions);
public activate(terminal: Terminal): void;
public dispose(): void;

Expand Down
2 changes: 1 addition & 1 deletion addons/addon-progress/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = {
alias: {
common: path.resolve('../../out/common'),
browser: path.resolve('../../out/browser'),
vs: path.resolve('../../out/vs'),
vs: path.resolve('../../out/vs')
}
},
output: {
Expand Down
7 changes: 3 additions & 4 deletions demo/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,7 @@ function createTerminal(): void {
addons.search.instance = new SearchAddon();
addons.serialize.instance = new SerializeAddon();
addons.fit.instance = new FitAddon();
addons.image.instance = new ImageAddon();
//addons.progress.instance = new ProgressAddon(Terminal as unknown as IXtermSharedImports);
addons.image.instance = new ImageAddon(sharedExports);
addons.progress.instance = new ProgressAddon(sharedExports);
addons.unicodeGraphemes.instance = new UnicodeGraphemesAddon();
addons.clipboard.instance = new ClipboardAddon();
Expand Down Expand Up @@ -640,8 +639,8 @@ function initAddons(term: Terminal): void {
if (checkbox.checked) {
const ctorOptionsJson = document.querySelector<HTMLTextAreaElement>('#image-options').value;
addon.instance = ctorOptionsJson
? new addons[name].ctor(JSON.parse(ctorOptionsJson))
: new addons[name].ctor();
? new addons[name].ctor(sharedExports, JSON.parse(ctorOptionsJson))
: new addons[name].ctor(sharedExports);
term.loadAddon(addon.instance);
} else {
addon.instance!.dispose();
Expand Down
3 changes: 2 additions & 1 deletion src/browser/public/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as Strings from 'browser/LocalizableStrings';
import { CoreBrowserTerminal as TerminalCore } from 'browser/CoreBrowserTerminal';
import { IBufferRange, ITerminal } from 'browser/Types';
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { ITerminalOptions } from 'common/Types';
import { AddonManager } from 'common/public/AddonManager';
import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi';
Expand All @@ -22,6 +22,7 @@ import { type Event, Emitter } from 'vs/base/common/event';
*/
export const sharedExports: ISharedExports = {
DisposableStore,
MutableDisposable,
Emitter,
toDisposable
};
Expand Down
7 changes: 7 additions & 0 deletions src/common/shared/AddonDisposable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ export class AddonDisposable implements IDisposable {
this._store = new sharedExports.DisposableStore();
}

protected _register<T extends IDisposable>(o: T): T {
if ((o as unknown as IDisposable) === this) {
throw new Error('Cannot register a disposable on itself!');
}
return this._store.add(o);
}

public dispose(): void {
this._store.dispose();
}
Expand Down
44 changes: 22 additions & 22 deletions typings/xterm-headless.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1363,26 +1363,26 @@ declare module '@xterm/headless' {
* EXPERIMENTAL:
* Module exposure of certain building blocks to be used at runtime in addons.
*/
export interface ISharedExports {
readonly DisposableStore: new() => IDisposableStore;
readonly Emitter: new<T>() => IEmitter<T>;
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<T> extends IDisposable {
event: IEvent<T>;
fire(event: T): void;
hasListeners(): boolean;
}
export interface IDisposableStore extends IDisposable {
isDisposed: boolean;
clear(): void;
add<T extends IDisposable>(o: T): T;
delete<T extends IDisposable>(o: T): void;
deleteAndLeak<T extends IDisposable>(o: T): void;
}
export interface ISharedExports {
readonly DisposableStore: new() => IDisposableStore;
readonly Emitter: new<T>() => IEmitter<T>;
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<T> extends IDisposable {
event: IEvent<T>;
fire(event: T): void;
hasListeners(): boolean;
}
export interface IDisposableStore extends IDisposable {
isDisposed: boolean;
clear(): void;
add<T extends IDisposable>(o: T): T;
delete<T extends IDisposable>(o: T): void;
deleteAndLeak<T extends IDisposable>(o: T): void;
}
}
6 changes: 6 additions & 0 deletions typings/xterm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1963,6 +1963,7 @@ declare module '@xterm/xterm' {
*/
export interface ISharedExports {
readonly DisposableStore: new() => IDisposableStore;
readonly MutableDisposable: new<T extends IDisposable>() => IMutableDisposable<T>;
readonly Emitter: new<T>() => IEmitter<T>;
readonly toDisposable: (fn: () => void) => IDisposable;
}
Expand All @@ -1983,4 +1984,9 @@ declare module '@xterm/xterm' {
delete<T extends IDisposable>(o: T): void;
deleteAndLeak<T extends IDisposable>(o: T): void;
}
export interface IMutableDisposable<T> extends IDisposable {
value: T | undefined;
clear(): void;
dispose(): void;
}
}

0 comments on commit 893d89a

Please sign in to comment.