Skip to content

Commit d6c872b

Browse files
committed
add onImageAdded to api
1 parent dedf3b1 commit d6c872b

5 files changed

Lines changed: 38 additions & 1 deletion

File tree

addons/addon-image/src/ImageAddon.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import type { ITerminalAddon, IDisposable } from '@xterm/xterm';
77
import type { ImageAddon as IImageApi } from '@xterm/addon-image';
8+
import { Emitter, type IEvent } from 'common/Event';
89
import { IIPHandler } from './IIPHandler';
910
import { ImageRenderer } from './ImageRenderer';
1011
import { ImageStorage, CELL_SIZE_DEFAULT } from './ImageStorage';
@@ -62,6 +63,8 @@ export class ImageAddon implements ITerminalAddon, IImageApi {
6263
private _disposables: IDisposable[] = [];
6364
private _terminal: ITerminalExt | undefined;
6465
private _handlers: Map<String, IResetHandler> = new Map();
66+
private readonly _onImageAdded = new Emitter<void>();
67+
public readonly onImageAdded: IEvent<void> = this._onImageAdded.event;
6568

6669
constructor(opts?: Partial<IImageAddonOptions>) {
6770
this._opts = Object.assign({}, DEFAULT_OPTIONS, opts);
@@ -74,6 +77,7 @@ export class ImageAddon implements ITerminalAddon, IImageApi {
7477
}
7578
this._disposables.length = 0;
7679
this._handlers.clear();
80+
this._onImageAdded.dispose();
7781
}
7882

7983
private _disposeLater(...args: IDisposable[]): void {
@@ -88,6 +92,7 @@ export class ImageAddon implements ITerminalAddon, IImageApi {
8892
// internal data structures
8993
this._renderer = new ImageRenderer(terminal);
9094
this._storage = new ImageStorage(terminal, this._renderer, this._opts);
95+
this._storage.onImageAdded = () => this._onImageAdded.fire();
9196

9297
// enable size reports
9398
if (this._opts.enableSizeReports) {

addons/addon-image/src/ImageStorage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export class ImageStorage implements IDisposable {
124124
private _pixelLimit: number = 2500000;
125125

126126
private _viewportMetrics: { cols: number, rows: number };
127+
public onImageAdded: (() => void) | undefined;
127128
public onImageDeleted: ((storageId: number) => void) | undefined;
128129

129130
constructor(
@@ -336,6 +337,7 @@ export class ImageStorage implements IDisposable {
336337

337338
// finally add the image
338339
this._images.set(imageId, imgSpec);
340+
this.onImageAdded?.();
339341
return imageId;
340342
}
341343

addons/addon-image/test/ImageAddon.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,18 @@ test.describe('ImageAddon', () => {
196196
});
197197

198198
test.describe('image lifecycle & eviction', () => {
199+
test('onImageAdded fires for each image', async () => {
200+
await ctx.page.evaluate(`
201+
window._imageAddedCount = 0;
202+
window.imageAddon.onImageAdded(() => { window._imageAddedCount++; });
203+
`);
204+
await ctx.proxy.write(SIXEL_SEQ_0);
205+
await pollFor(ctx.page, 'window._imageAddedCount', 1);
206+
await ctx.proxy.write(SIXEL_SEQ_0);
207+
await pollFor(ctx.page, 'window._imageAddedCount', 2);
208+
await ctx.proxy.write(SIXEL_SEQ_0);
209+
await pollFor(ctx.page, 'window._imageAddedCount', 3);
210+
});
199211
test('delete image once scrolled off', async () => {
200212
await ctx.proxy.write(SIXEL_SEQ_0);
201213
pollFor(ctx.page, 'window.imageAddon._storage._images.size', 1);

addons/addon-image/test/KittyGraphics.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,19 @@ test.describe('Kitty Graphics Protocol', () => {
21592159
strictEqual(await ctx.page.evaluate(`window.imageAddon._storage._images.has(${oldStorageId})`), false);
21602160
});
21612161
});
2162+
2163+
test.describe('onImageAdded callback', () => {
2164+
test('onImageAdded fires for each kitty image', async () => {
2165+
await ctx.page.evaluate(`
2166+
window._imageAddedCount = 0;
2167+
window.imageAddon.onImageAdded(() => { window._imageAddedCount++; });
2168+
`);
2169+
await ctx.proxy.write(`\x1b_Ga=T,f=100;${KITTY_BLACK_1X1_BASE64}\x1b\\`);
2170+
await pollFor(ctx.page, 'window._imageAddedCount', 1);
2171+
await ctx.proxy.write(`\x1b_Ga=T,f=100;${KITTY_RGB_3X1_BASE64}\x1b\\`);
2172+
await pollFor(ctx.page, 'window._imageAddedCount', 2);
2173+
});
2174+
});
21622175
});
21632176

21642177
/**

addons/addon-image/typings/addon-image.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @license MIT
44
*/
55

6-
import { Terminal, ITerminalAddon } from '@xterm/xterm';
6+
import { Terminal, ITerminalAddon, IEvent } from '@xterm/xterm';
77

88
declare module '@xterm/addon-image' {
99
export interface IImageAddonOptions {
@@ -116,6 +116,11 @@ declare module '@xterm/addon-image' {
116116
*/
117117
public showPlaceholder: boolean;
118118

119+
/**
120+
* Event fired whenever a new image is added to storage.
121+
*/
122+
public readonly onImageAdded: IEvent<void>;
123+
119124
/**
120125
* Get original image canvas at buffer position.
121126
*/

0 commit comments

Comments
 (0)