fix(composite): async image decode, skip dead pager, prevent UI freeze

- Decode images in background goroutine, not in Draw()
- Show [loading image...] placeholder until decode completes
- Skip pv.term.Draw() when composite is active (pager got no input)
- Thread-safe access to decoded image cache via sync.Mutex
- Invalidate callback triggers redraw when images finish decoding
This commit is contained in:
Mortdecai
2026-04-07 21:11:44 -04:00
parent 20161fedeb
commit 046ff03f8b
2 changed files with 91 additions and 71 deletions
+6 -4
View File
@@ -636,7 +636,8 @@ func (pv *PartViewer) attemptCopy() {
if len(images) > 0 {
pv.imageRefs = images
pv.composite = newCompositeContent(
string(cleanedBytes), images, 80)
string(cleanedBytes), images, 80,
pv.Invalidate)
pv.Invalidate()
} else {
// No images — forward to pager as normal
@@ -835,10 +836,8 @@ func (pv *PartViewer) Draw(ctx *ui.Context) {
ctx.Printf(0, 0, style, "%s", pv.err.Error())
return
}
if pv.term != nil {
pv.term.Draw(ctx)
}
// Composite mode: text + inline images from filter output
// Skip term.Draw() — pager got no input in composite mode
if pv.composite != nil {
pv.composite.width = ctx.Width()
style := pv.uiConfig.GetStyle(config.STYLE_DEFAULT)
@@ -846,6 +845,9 @@ func (pv *PartViewer) Draw(ctx *ui.Context) {
pv.composite.Draw(ctx, pv.scroll, style)
return
}
if pv.term != nil {
pv.term.Draw(ctx)
}
if pv.image != nil && (pv.resized(ctx) || pv.graphic == nil) {
// This path should only occur on resizes or the first pass
// after the image is downloaded and could be slow due to