Skip to content

Commit 019c2fc

Browse files
rlogmanclaude
andcommitted
Clip images to editor bounds, prevent overflow into output panel
Images that would extend past the editor content area into the output panel or status bar are now skipped entirely. Removed the ECH-based erase approach (doesn't clear Sixel pixels) in favor of simply not rendering images that don't fit within the editor. tcell's own screen redraw clears the cell-level content when scrolling, and Sixel images only render when they fully fit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7e1c3d4 commit 019c2fc

2 files changed

Lines changed: 15 additions & 23 deletions

File tree

internal/editor/editor.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,7 @@ type Editor struct {
182182

183183
// Pending inline images to render after tcell draw completes.
184184
// Collected during Draw(), flushed at the end via raw escape sequences.
185-
pendingImages []PendingImage
186-
lastImageAreas []PendingImage // previous frame's image positions for clearing
185+
pendingImages []PendingImage
187186

188187
// ttyFile is a handle to /dev/tty (or os.Stdout on Windows) for writing
189188
// raw escape sequences that bypass tcell's screen buffer.

internal/editor/image_output.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,33 +42,26 @@ func (e *Editor) flushPendingImages() {
4242
return
4343
}
4444

45-
// Clear previous image areas by overwriting with spaces.
46-
// This prevents Sixel pixels from persisting after scroll.
47-
for _, prev := range e.lastImageAreas {
48-
for r := 0; r < prev.Height; r++ {
49-
row := prev.ScreenRow + r + 1 // 1-based
50-
col := prev.ScreenCol + 1
51-
pos := fmt.Sprintf("\033[%d;%dH", row, col)
52-
_, _ = fmt.Fprint(e.ttyFile, pos)
53-
// Erase from cursor to end of line within the image width
54-
_, _ = fmt.Fprintf(e.ttyFile, "\033[%dX", prev.Width)
55-
}
56-
}
57-
58-
// Record current image positions for next clear cycle
59-
e.lastImageAreas = make([]PendingImage, len(e.pendingImages))
60-
copy(e.lastImageAreas, e.pendingImages)
45+
// Get the editor's visible area to clip images
46+
_, editorY, _, editorH := e.GetInnerRect()
47+
// Account for tab bar + breadcrumb
48+
editorContentTop := editorY + 2
49+
editorContentBottom := editorY + editorH
6150

6251
for _, img := range e.pendingImages {
6352
if img.EncodedData == "" {
6453
continue
6554
}
66-
// Skip images that would extend below the visible area
67-
_, screenH := 0, 0
68-
if e.ttyFile == os.Stdout {
69-
// Can't determine screen size easily; just render
55+
56+
// Skip images that start outside the editor content area
57+
if img.ScreenRow < editorContentTop || img.ScreenRow >= editorContentBottom {
58+
continue
59+
}
60+
61+
// Skip images that would overflow past the editor bottom into output panel
62+
if img.ScreenRow+img.Height > editorContentBottom {
63+
continue
7064
}
71-
_ = screenH
7265

7366
// ANSI cursor positioning: ESC [ row ; col H (1-based)
7467
pos := fmt.Sprintf("\033[%d;%dH", img.ScreenRow+1, img.ScreenCol+1)

0 commit comments

Comments
 (0)