@@ -68,6 +68,13 @@ var (
cachedMutex sync.RWMutex
)
+// ResetCache clears the image cache, freeing all cached decoded images.
+func ResetCache() {
+ cachedMutex.Lock()
+ clear(cachedImages)
+ cachedMutex.Unlock()
+}
+
// fitImage resizes the image to fit within the specified dimensions in
// terminal cells, maintaining the aspect ratio.
func fitImage(id string, img image.Image, cs CellSize, cols, rows int) image.Image {
@@ -0,0 +1,46 @@
+package image
+
+import (
+ "image"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestResetCache(t *testing.T) {
+ t.Parallel()
+
+ cachedMutex.Lock()
+ cachedImages[imageKey{id: "a", cols: 10, rows: 10}] = cachedImage{
+ img: image.NewRGBA(image.Rect(0, 0, 1, 1)),
+ cols: 10,
+ rows: 10,
+ }
+ cachedImages[imageKey{id: "b", cols: 20, rows: 20}] = cachedImage{
+ img: image.NewRGBA(image.Rect(0, 0, 1, 1)),
+ cols: 20,
+ rows: 20,
+ }
+ cachedMutex.Unlock()
+
+ ResetCache()
+
+ cachedMutex.RLock()
+ length := len(cachedImages)
+ cachedMutex.RUnlock()
+
+ require.Equal(t, 0, length)
+}
+
+func TestResetIdempotent(t *testing.T) {
+ t.Parallel()
+
+ // Calling Reset on an empty cache should not panic.
+ ResetCache()
+
+ cachedMutex.RLock()
+ length := len(cachedImages)
+ cachedMutex.RUnlock()
+
+ require.Equal(t, 0, length)
+}
@@ -41,6 +41,7 @@ import (
"github.com/charmbracelet/crush/internal/ui/common"
"github.com/charmbracelet/crush/internal/ui/completions"
"github.com/charmbracelet/crush/internal/ui/dialog"
+ fimage "github.com/charmbracelet/crush/internal/ui/image"
"github.com/charmbracelet/crush/internal/ui/logo"
"github.com/charmbracelet/crush/internal/ui/styles"
"github.com/charmbracelet/crush/internal/ui/util"
@@ -1137,6 +1138,10 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
break
}
+ if m.dialog.ContainsDialog(dialog.FilePickerID) {
+ defer fimage.ResetCache()
+ }
+
m.dialog.CloseFrontDialog()
if isOnboarding {
@@ -1351,6 +1356,10 @@ func (m *UI) handleDialogMsg(msg tea.Msg) tea.Cmd {
m.dialog.CloseDialog(dialog.FilePickerID)
return nil
},
+ func() tea.Msg {
+ fimage.ResetCache()
+ return nil
+ },
))
case dialog.ActionRunCustomCommand: