@@ -186,6 +186,12 @@ Must be a positive integer."
186186 :type 'integer
187187 :group 'eca )
188188
189+ (defcustom eca-chat-yank-image-context-location 'system
190+ " Where to paste images from clipboard."
191+ :type '(choice (const :tag " System context area" system)
192+ (const :tag " user context area" user))
193+ :group 'eca )
194+
189195(defvar-local eca-chat--tool-call-prepare-counters (make-hash-table :test 'equal )
190196 " Hash table mapping toolCall ID to message count." )
191197
@@ -442,7 +448,6 @@ Must be a positive integer."
442448 (define-key map (kbd " C-c <up>" ) #'eca-chat-go-to-prev-expandable-block )
443449 (define-key map (kbd " C-c <down>" ) #'eca-chat-go-to-next-expandable-block )
444450 (define-key map (kbd " C-c <tab>" ) #'eca-chat-toggle-expandable-block )
445- (define-key map (kbd " C-c C-y" ) #'eca-chat-media-yank-screenshot )
446451 map)
447452 " Keymap used by `eca-chat-mode' ." )
448453
@@ -1707,7 +1712,7 @@ TYPE can be a string or symbol."
17071712 subtype)))
17081713 " png" )))
17091714
1710- (defun eca-chat-media- -yank-image-handler (type data )
1715+ (defun eca-chat--yank-image-handler (type data )
17111716 " Handler for `yank-media' to insert images from clipboard.
17121717TYPE is the MIME type (e.g., image/png).
17131718DATA is the binary image data as a string."
@@ -1722,15 +1727,31 @@ DATA is the binary image data as a string."
17221727 (insert data))
17231728 (when (f-exists? output-path)
17241729 (eca-chat--with-current-buffer chat-buffer
1725- (let ((context (list :type " file" :path output-path)))
1726- (eca-chat--insert-prompt ( concat (eca-chat--context->str context 'static ) " " ))
1730+ (let ((context (list :type " file" :path output-path))
1731+ (file-size ( file-size-human-readable ( file-attribute-size ( file-attributes output-path))) ))
17271732 (eca-chat--select-window)
1728- (goto-char (line-end-position )))
1729- (eca-info " Image yanked and added to prompt: %s"
1730- (file-size-human-readable (file-attribute-size (file-attributes output-path)))))))
1733+ (if (eq 'system eca-chat-yank-image-context-location)
1734+ (eca-chat--add-context context)
1735+ (eca-chat--insert-prompt (concat (eca-chat--context->str context 'static ) " " )))
1736+ (eca-info " Image added, size: %s" file-size)))))
17311737 (error
17321738 (eca-error " Failed to save yanked image: %s" (error-message-string err))))))
17331739
1740+ (defun eca-chat--yank-considering-image (orig-fun &rest args )
1741+ " Around advice for paste commands to use `yank-media' for images.
1742+ Call ORIG-FUN with ARGS if not media."
1743+ (if (and (derived-mode-p 'eca-chat-mode )
1744+ (fboundp 'yank-media )
1745+ (boundp 'yank-media--registered-handlers )
1746+ yank-media--registered-handlers
1747+ (when-let* ((targets (gui-get-selection 'CLIPBOARD 'TARGETS )))
1748+ (seq-some (lambda (type )
1749+ (and (symbolp type)
1750+ (string-match-p " ^image/" (symbol-name type))))
1751+ (if (vectorp targets) (append targets nil ) targets))))
1752+ (call-interactively #'yank-media )
1753+ (apply orig-fun args)))
1754+
17341755; ; Public
17351756
17361757(eca-chat-define-derived-mode eca-chat-mode " eca-chat"
@@ -1740,11 +1761,9 @@ DATA is the binary image data as a string."
17401761 (visual-line-mode )
17411762 (hl-line-mode -1 )
17421763 (setq-local eca-chat--history '())
1743- (setq-local eca-chat--history-index -1 )
1764+ (setq-local eca-chat--history-index -1 )
17441765
17451766 ; ; Show diff blocks in markdown-mode with colors.
1746- (when (fboundp 'yank-media-handler )
1747- (yank-media-handler " image/.*" #'eca-chat-media--yank-image-handler ))
17481767 (setq-local markdown-fontify-code-blocks-natively t )
17491768 ; ; Enable gfm-view-mode-like rendering without read-only
17501769 (setq-local markdown-hide-markup t )
@@ -1786,6 +1805,18 @@ DATA is the binary image data as a string."
17861805
17871806 (add-hook 'kill-buffer-hook #'eca-chat--delete-chat nil t )
17881807
1808+ ; ; Paste image from clipboard support
1809+ (when (fboundp 'yank-media-handler )
1810+ (yank-media-handler " image/png" #'eca-chat--yank-image-handler )
1811+ (yank-media-handler " image/jpeg" #'eca-chat--yank-image-handler )
1812+ (yank-media-handler " image/jpg" #'eca-chat--yank-image-handler )
1813+ (yank-media-handler " image/gif" #'eca-chat--yank-image-handler )
1814+ (yank-media-handler " image/webp" #'eca-chat--yank-image-handler )
1815+ (advice-add 'yank :around #'eca-chat--yank-considering-image )
1816+ (when (featurep 'evil )
1817+ (advice-add 'evil-paste-after :around #'eca-chat--yank-considering-image )
1818+ (advice-add 'evil-paste-before :around #'eca-chat--yank-considering-image )))
1819+
17891820 (let ((chat-buffer (current-buffer )))
17901821 (run-with-timer
17911822 0.05
@@ -2792,20 +2823,5 @@ Returns selected message plist or nil if no messages or cancelled."
27922823 (save-buffer ))
27932824 (eca-info (format " Saved chat to '%s ' " file)))))
27942825
2795- ;;;### autoload
2796- (defun eca-chat-media-yank-screenshot ()
2797- " Yank image from clipboard and add to context.
2798- Uses native `yank-media' . Requires Emacs 29+."
2799- (interactive )
2800- (unless (fboundp 'yank-media )
2801- (user-error " Screenshot yanking requires Emacs 29+ with yank-media support" ))
2802- (let* ((session (eca-session))
2803- (chat-buffer (eca-chat--get-last-buffer session)))
2804- (eca-assert-session-running session)
2805- (unless chat-buffer
2806- (user-error " Open an ECA chat buffer before yanking a screenshot" ))
2807- (eca-chat--select-window)
2808- (yank-media)))
2809-
28102826(provide 'eca-chat )
28112827; ;; eca-chat.el ends here
0 commit comments