Skip to content

fix(paste): attach clipboard image when paste content is empty - #3490

Open
joestump wants to merge 1 commit into
charmbracelet:mainfrom
joestump:fix/paste-empty-image-clipboard
Open

fix(paste): attach clipboard image when paste content is empty#3490
joestump wants to merge 1 commit into
charmbracelet:mainfrom
joestump:fix/paste-empty-image-clipboard

Conversation

@joestump

@joestump joestump commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Problem

On macOS, copying an image (e.g. from Preview) and pressing CMD+V in the chat editor does nothing. Terminal emulators intercept CMD+V and deliver the clipboard's text via bracketed paste; when the clipboard holds an image instead of text, the resulting tea.PasteMsg is strictly empty, and handlePasteMsg fell through the text-paste path and silently inserted nothing. The image-only clipboard is never checked.

Fix

Two changes in internal/ui/model/ui.go:

  1. Empty-paste fallback: when the pasted content is strictly empty, handlePasteMsg now delegates to pasteImageFromClipboard (the same path as the ctrl+v PasteImage binding), so image data on the native clipboard is attached as a pending attachment. The check is a strict == "" rather than TrimSpace, so genuine whitespace-only pastes still insert as text. Like the key-bound path, the fallback is gated to image-capable models.

  2. Warn on image-incapable models: both paste-image entry points (the key binding and the new fallback) previously returned nil silently when the current model didn't support images — a paste vanished with zero feedback, which made the macOS bug undiagnosable from the UX. They now surface a warning naming the current model ("gpt-4o-mini doesn't support images").

Tests

New internal/ui/model/paste_image_test.go covers:

  • empty paste → routes to the clipboard-image fallback (asserted via function-pointer identity, without touching the real system clipboard)
  • empty paste on an image-incapable model → warning, not the fallback
  • ctrl+v on an image-incapable model → warning
  • whitespace-only paste → still inserts as text (not swallowed by the fallback)
  • non-empty paste → unchanged text insertion path

Verification

  • go test ./internal/ui/... — all pass
  • go vet ./internal/ui/... — clean
  • gofumpt -l internal/ui/ — clean
  • golangci-lint run ./internal/ui/... — 0 issues
  • This fix has been running in a downstream fork for a few days; the empty-paste routing tests pin the mechanism without depending on host clipboard state.

On macOS, terminal emulators intercept CMD+V and deliver the clipboard's
text via bracketed paste. When the clipboard holds an image instead of
text, the resulting tea.PasteMsg is strictly empty, and handlePasteMsg
fell through the text-paste path and silently did nothing.

Add a fallback in handlePasteMsg: when pasted content is strictly empty,
delegate to pasteImageFromClipboard (mirroring the key-bound ctrl+v
path) so image data on the clipboard is attached. The check is a strict
== "" rather than TrimSpace so genuine whitespace-only pastes still
insert as text. Like the key-bound path, the fallback is gated to
image-capable models.

Also surface a warning naming the current model when either paste-image
entry point (the key binding or the new fallback) is used on a model
that doesn't support images. Both paths previously returned nil
silently, so a paste vanished with zero feedback and the failure was
undiagnosable from the UX.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant