@@ -86,6 +86,7 @@ test.describe('Kitty Graphics Protocol', () => {
8686 // TODO: Add tests for animation frames
8787 // TODO: Add performance tests for streaming large images
8888 // TODO: Implement cursor movement per Kitty spec - cursor should move by cols/rows after placement (unless C=1)
89+ // TODO: Distinguish lowercase delete selectors (placement only) from uppercase (placement + free data)
8990
9091 test . beforeEach ( async ( { } , testInfo ) => {
9192 // DEBT: This test never worked on webkit
@@ -227,12 +228,12 @@ test.describe('Kitty Graphics Protocol', () => {
227228 } ) ;
228229
229230 test . describe ( 'Delete commands' , ( ) => {
230- test ( 'delete command (a=d) removes specific image by id' , async ( ) => {
231+ test ( 'delete command (a=d,d=i ) removes specific image by id' , async ( ) => {
231232 await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=10;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
232233 await timeout ( 50 ) ;
233234 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
234235
235- await ctx . proxy . write ( `\x1b_Ga=d,i=10\x1b\\` ) ;
236+ await ctx . proxy . write ( `\x1b_Ga=d,d=i, i=10\x1b\\` ) ;
236237 await timeout ( 50 ) ;
237238 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 0 ) ;
238239 } ) ;
@@ -256,7 +257,7 @@ test.describe('Kitty Graphics Protocol', () => {
256257 await timeout ( 50 ) ;
257258 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.size` ) , 1 ) ;
258259
259- await ctx . proxy . write ( `\x1b_Ga=d,i=50\x1b\\` ) ;
260+ await ctx . proxy . write ( `\x1b_Ga=d,d=i, i=50\x1b\\` ) ;
260261 await timeout ( 50 ) ;
261262 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.size` ) , 0 ) ;
262263 } ) ;
@@ -270,7 +271,7 @@ test.describe('Kitty Graphics Protocol', () => {
270271 await timeout ( 50 ) ;
271272 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.size` ) , 2 ) ;
272273
273- await ctx . proxy . write ( `\x1b_Ga=d,i=55\x1b\\` ) ;
274+ await ctx . proxy . write ( `\x1b_Ga=d,d=i, i=55\x1b\\` ) ;
274275 await timeout ( 50 ) ;
275276 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.size` ) , 1 ) ;
276277 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.has(56)` ) , true ) ;
@@ -290,6 +291,112 @@ test.describe('Kitty Graphics Protocol', () => {
290291 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').pendingTransmissions.size` ) , 0 ) ;
291292 } ) ;
292293
294+ test ( 'd=i selector deletes specific image by id' , async ( ) => {
295+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=80;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
296+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=81;${ KITTY_RGB_3X1_BASE64 } \x1b\\` ) ;
297+ await timeout ( 50 ) ;
298+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 2 ) ;
299+
300+ await ctx . proxy . write ( `\x1b_Ga=d,d=i,i=80\x1b\\` ) ;
301+ await timeout ( 50 ) ;
302+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
303+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.has(81)` ) , true ) ;
304+ } ) ;
305+
306+ test ( 'd=I selector deletes specific image by id (uppercase)' , async ( ) => {
307+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=82;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
308+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=83;${ KITTY_RGB_3X1_BASE64 } \x1b\\` ) ;
309+ await timeout ( 50 ) ;
310+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 2 ) ;
311+
312+ await ctx . proxy . write ( `\x1b_Ga=d,d=I,i=82\x1b\\` ) ;
313+ await timeout ( 50 ) ;
314+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
315+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.has(83)` ) , true ) ;
316+ } ) ;
317+
318+ test ( 'd=a selector deletes all images' , async ( ) => {
319+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=84;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
320+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=85;${ KITTY_RGB_3X1_BASE64 } \x1b\\` ) ;
321+ await timeout ( 50 ) ;
322+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 2 ) ;
323+
324+ await ctx . proxy . write ( `\x1b_Ga=d,d=a\x1b\\` ) ;
325+ await timeout ( 50 ) ;
326+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 0 ) ;
327+ } ) ;
328+
329+ test ( 'd=A selector deletes all images (uppercase)' , async ( ) => {
330+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=86;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
331+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=87;${ KITTY_RGB_3X1_BASE64 } \x1b\\` ) ;
332+ await timeout ( 50 ) ;
333+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 2 ) ;
334+
335+ await ctx . proxy . write ( `\x1b_Ga=d,d=A\x1b\\` ) ;
336+ await timeout ( 50 ) ;
337+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 0 ) ;
338+ } ) ;
339+
340+ test ( 'd=a selector also removes displayed images from storage' , async ( ) => {
341+ await ctx . proxy . write ( `\x1b_Ga=T,f=100,i=88;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
342+ await timeout ( 100 ) ;
343+ strictEqual ( await getImageStorageLength ( ) , 1 ) ;
344+
345+ await ctx . proxy . write ( `\x1b_Ga=d,d=a\x1b\\` ) ;
346+ await timeout ( 50 ) ;
347+ strictEqual ( await getImageStorageLength ( ) , 0 ) ;
348+ } ) ;
349+
350+ test ( 'd=i selector also removes displayed image from storage' , async ( ) => {
351+ await ctx . proxy . write ( `\x1b_Ga=T,f=100,i=89;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
352+ await timeout ( 100 ) ;
353+ strictEqual ( await getImageStorageLength ( ) , 1 ) ;
354+
355+ await ctx . proxy . write ( `\x1b_Ga=d,d=i,i=89\x1b\\` ) ;
356+ await timeout ( 50 ) ;
357+ strictEqual ( await getImageStorageLength ( ) , 0 ) ;
358+ } ) ;
359+
360+ test ( 'd=i without id does nothing' , async ( ) => {
361+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=90;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
362+ await timeout ( 50 ) ;
363+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
364+
365+ await ctx . proxy . write ( `\x1b_Ga=d,d=i\x1b\\` ) ;
366+ await timeout ( 50 ) ;
367+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
368+ } ) ;
369+
370+ test ( 'd=i selector clears pixels from canvas' , async ( ) => {
371+ await ctx . proxy . write ( `\x1b_Ga=T,f=100,i=92,q=1;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
372+ await timeout ( 100 ) ;
373+ deepStrictEqual ( await getPixel ( 0 , 0 , 0 , 0 ) , [ 0 , 0 , 0 , 255 ] ) ;
374+
375+ await ctx . proxy . write ( `\x1b_Ga=d,d=i,i=92\x1b\\` ) ;
376+ await timeout ( 100 ) ;
377+ strictEqual ( await getPixel ( 0 , 0 , 0 , 0 ) , null ) ;
378+ } ) ;
379+
380+ test ( 'd=a selector clears all pixels from canvas' , async ( ) => {
381+ await ctx . proxy . write ( `\x1b_Ga=T,f=100,i=93,q=1;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
382+ await timeout ( 100 ) ;
383+ deepStrictEqual ( await getPixel ( 0 , 0 , 0 , 0 ) , [ 0 , 0 , 0 , 255 ] ) ;
384+
385+ await ctx . proxy . write ( `\x1b_Ga=d,d=a\x1b\\` ) ;
386+ await timeout ( 100 ) ;
387+ strictEqual ( await getPixel ( 0 , 0 , 0 , 0 ) , null ) ;
388+ } ) ;
389+
390+ test ( 'unsupported delete selector is ignored' , async ( ) => {
391+ await ctx . proxy . write ( `\x1b_Ga=t,f=100,i=91;${ KITTY_BLACK_1X1_BASE64 } \x1b\\` ) ;
392+ await timeout ( 50 ) ;
393+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
394+
395+ await ctx . proxy . write ( `\x1b_Ga=d,d=c\x1b\\` ) ;
396+ await timeout ( 50 ) ;
397+ strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.size` ) , 1 ) ;
398+ } ) ;
399+
293400 test ( 'chunks sent after delete are not assembled with previous data' , async ( ) => {
294401 const half = Math . floor ( KITTY_BLACK_1X1_BASE64 . length / 2 ) ;
295402 const part1 = KITTY_BLACK_1X1_BASE64 . substring ( 0 , half ) ;
@@ -865,7 +972,7 @@ test.describe('Kitty Graphics Protocol', () => {
865972 await timeout ( 200 ) ;
866973 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.has(700)` ) , true ) ;
867974
868- await ctx . proxy . write ( `\x1b_Ga=d,i=700\x1b\\` ) ;
975+ await ctx . proxy . write ( `\x1b_Ga=d,d=i, i=700\x1b\\` ) ;
869976 await timeout ( 50 ) ;
870977 strictEqual ( await ctx . page . evaluate ( `window.imageAddon._handlers.get('kitty').images.has(700)` ) , false ) ;
871978 } ) ;
0 commit comments