@@ -415,46 +415,56 @@ export class ImageStorage implements IDisposable {
415415 const placeholderCalls : { col : number , row : number , count : number } [ ] = [ ] ;
416416
417417 // walk all cells in viewport and collect tiles found
418+ // Note: We check _extendedAttrs directly (not just HAS_EXTENDED flag)
419+ // because text writes clear the BG flag but leave image tile data intact.
420+ // This lets top-layer images survive text overwrites (kitty C=1 behavior).
418421 for ( let row = start ; row <= end ; ++ row ) {
419422 const line = buffer . lines . get ( row + buffer . ydisp ) as IBufferLineExt ;
420423 if ( ! line ) return ;
421424 for ( let col = 0 ; col < cols ; ++ col ) {
425+ let e : IExtendedAttrsImage ;
422426 if ( line . getBg ( col ) & BgFlags . HAS_EXTENDED ) {
423- let e : IExtendedAttrsImage = line . _extendedAttrs [ col ] ?? EMPTY_ATTRS ;
424- const imageId = e . imageId ;
425- if ( imageId === undefined || imageId === - 1 ) {
427+ e = line . _extendedAttrs [ col ] ?? EMPTY_ATTRS ;
428+ } else {
429+ const maybeImg = line . _extendedAttrs [ col ] as IExtendedAttrsImage | undefined ;
430+ if ( ! maybeImg || maybeImg . imageId === undefined || maybeImg . imageId === - 1 ) {
426431 continue ;
427432 }
428- const imgSpec = this . _images . get ( imageId ) ;
429- if ( e . tileId !== - 1 ) {
430- const startTile = e . tileId ;
431- const startCol = col ;
432- let count = 1 ;
433- /**
434- * merge tiles to the right into a single draw call, if:
435- * - not at end of line
436- * - cell has same image id
437- * - cell has consecutive tile id
438- */
439- while (
440- ++ col < cols
441- && ( line . getBg ( col ) & BgFlags . HAS_EXTENDED )
442- && ( e = line . _extendedAttrs [ col ] ?? EMPTY_ATTRS )
443- && ( e . imageId === imageId )
444- && ( e . tileId === startTile + count )
445- ) {
446- count ++ ;
433+ e = maybeImg ;
434+ }
435+ const imageId = e . imageId ;
436+ if ( imageId === undefined || imageId === - 1 ) {
437+ continue ;
438+ }
439+ const imgSpec = this . _images . get ( imageId ) ;
440+ if ( e . tileId !== - 1 ) {
441+ const startTile = e . tileId ;
442+ const startCol = col ;
443+ let count = 1 ;
444+ /**
445+ * merge tiles to the right into a single draw call, if:
446+ * - not at end of line
447+ * - cell has same image id
448+ * - cell has consecutive tile id
449+ * Also check _extendedAttrs directly for cells where text cleared HAS_EXTENDED.
450+ */
451+ while ( ++ col < cols ) {
452+ const nextE = line . _extendedAttrs [ col ] as IExtendedAttrsImage | undefined ;
453+ if ( ! nextE || nextE . imageId !== imageId || nextE . tileId !== startTile + count ) {
454+ break ;
447455 }
448- col -- ;
449- if ( imgSpec ) {
450- if ( imgSpec . actual ) {
451- drawCalls . push ( { imgSpec , tileId : startTile , col : startCol , row , count } ) ;
452- }
453- } else if ( this . _opts . showPlaceholder ) {
454- placeholderCalls . push ( { col : startCol , row, count } ) ;
456+ e = nextE ;
457+ count ++ ;
458+ }
459+ col -- ;
460+ if ( imgSpec ) {
461+ if ( imgSpec . actual ) {
462+ drawCalls . push ( { imgSpec , tileId : startTile , col : startCol , row, count } ) ;
455463 }
456- this . _fullyCleared = false ;
464+ } else if ( this . _opts . showPlaceholder ) {
465+ placeholderCalls . push ( { col : startCol , row, count } ) ;
457466 }
467+ this . _fullyCleared = false ;
458468 }
459469 }
460470 }
0 commit comments