diff --git a/addons/addon-kitty-graphics/src/KittyGraphicsAddon.test.ts b/addons/addon-kitty-graphics/src/KittyGraphicsAddon.test.ts index 9378e954..4066a45f 100644 --- a/addons/addon-kitty-graphics/src/KittyGraphicsAddon.test.ts +++ b/addons/addon-kitty-graphics/src/KittyGraphicsAddon.test.ts @@ -69,6 +69,19 @@ describe('KittyGraphicsAddon', () => { assert.equal(cmd.action, 'd'); assert.equal(cmd.id, 5); }); + + it('should parse empty action as empty string', () => { + const cmd = parseKittyCommand('a=,f=100'); + assert.equal(cmd.action, ''); + assert.equal(cmd.format, 100); + }); + + it('should leave action undefined when key is not present (parser only)', () => { + const cmd = parseKittyCommand('f=100,i=5'); + assert.equal(cmd.action, undefined); + assert.equal(cmd.format, 100); + assert.equal(cmd.id, 5); + }); }); describe('APC handler', () => { @@ -112,6 +125,24 @@ describe('KittyGraphicsAddon', () => { assert.equal(addon.images.size, 1); }); + it('should default to transmit action when action is omitted', async () => { + // No a= key - should default to 't' (transmit) + const sequence = `\x1b_Gf=100;${BLACK_1X1_BASE64}\x1b\\`; + await writeP(terminal, sequence); + + // Image should be stored (transmit action) + assert.equal(addon.images.size, 1); + }); + + it('should ignore command when action is empty string', async () => { + // a= with no value is invalid - should be ignored + const sequence = `\x1b_Ga=,f=100;${BLACK_1X1_BASE64}\x1b\\`; + await writeP(terminal, sequence); + + // Empty action is invalid, command should be ignored + assert.equal(addon.images.size, 0); + }); + it('should delete image by id', async () => { // First store an image with id=5 await writeP(terminal, `\x1b_Ga=T,f=100,i=5;${BLACK_1X1_BASE64}\x1b\\`); diff --git a/addons/addon-kitty-graphics/src/KittyGraphicsAddon.ts b/addons/addon-kitty-graphics/src/KittyGraphicsAddon.ts index 10be97b7..4ce0aa8a 100644 --- a/addons/addon-kitty-graphics/src/KittyGraphicsAddon.ts +++ b/addons/addon-kitty-graphics/src/KittyGraphicsAddon.ts @@ -171,7 +171,7 @@ export class KittyGraphicsAddon implements ITerminalAddon, IKittyGraphicsApi { console.log('[KittyGraphicsAddon] Received command:', cmd); } - const action = cmd.action || 't'; + const action = cmd.action ?? 't'; // Actions from: https://sw.kovidgoyal.net/kitty/graphics-protocol/#control-data-reference switch (action) { @@ -535,8 +535,8 @@ export class KittyGraphicsAddon implements ITerminalAddon, IKittyGraphicsApi { * @param cmd - The parsed Kitty command */ private _handleQuery(cmd: IKittyCommand): boolean { - const id = cmd.id || 0; - const quiet = cmd.quiet || 0; + const id = cmd.id ?? 0; + const quiet = cmd.quiet ?? 0; if (this._debug) { console.log(`[KittyGraphicsAddon] Query received, id=${id}, quiet=${quiet}`); diff --git a/addons/addon-kitty-graphics/src/KittyImageRenderer.ts b/addons/addon-kitty-graphics/src/KittyImageRenderer.ts index e6a85ccf..4d950105 100644 --- a/addons/addon-kitty-graphics/src/KittyImageRenderer.ts +++ b/addons/addon-kitty-graphics/src/KittyImageRenderer.ts @@ -41,6 +41,23 @@ export class KittyImageRenderer implements IDisposable { this._terminal = terminal; } + public dispose(): void { + this._renderDisposable?.dispose(); + this._resizeDisposable?.dispose(); + + // Close all bitmaps + for (const placement of this._placements.values()) { + placement.bitmap.close(); + } + this._placements.clear(); + + if (this._canvas) { + this._canvas.remove(); + this._canvas = undefined; + this._ctx = undefined; + } + } + /** * Initialize the canvas layer. Called when first image is placed. */ @@ -217,21 +234,4 @@ export class KittyImageRenderer implements IDisposable { this._draw(); } } - - public dispose(): void { - this._renderDisposable?.dispose(); - this._resizeDisposable?.dispose(); - - // Close all bitmaps - for (const placement of this._placements.values()) { - placement.bitmap.close(); - } - this._placements.clear(); - - if (this._canvas) { - this._canvas.remove(); - this._canvas = undefined; - this._ctx = undefined; - } - } }