instance, a web browser will usually let you choose ``Copy Image'' on
images, and this image will be put on the clipboard. On capable
platforms, Emacs can yank these objects with the @code{yank-media}
-command---but only in modes that have support for it (@pxref{Yanking
-Media,,, elisp, The Emacs Lisp Reference Manual}).
+command---but only in modes that have support for it. By default, it
+auto-selects the preferred media type available in the clipboard but
+this can be overriden by giving the prefix argument to the command
+(@pxref{Yanking Media,,, elisp, The Emacs Lisp Reference Manual}).
@cindex clipboard manager
@vindex x-select-enable-clipboard-manager
@code{gui-get-selection}.
@end defun
+The @code{yank-media} command auto selects the preferred @sc{mime} type
+by default. The rules used for the selection can be controlled through
+the variables @code{yank-media-autoselect-function} and
+@code{yank-media-preferred-types}.
+
+@defvar yank-media-autoselect-function
+This variable should specify a function that will be called with the
+list of @sc{mime} types available for the current major mode, and should
+return a list of preferred @sc{mime} types to use. The first @sc{mime}
+type in the list will always be used by the @code{yank-media} command
+when auto selection is requested.
+@end defvar
+
+@defvar yank-media-preferred-types
+This variable changes the default selection process of
+@code{yank-media-autoselect-function}. It is a list that should contain
+the sole @sc{mime} type to choose in the order of their preference. It
+can also contain a function in which case it is called with the list of
+available @sc{mime} types and must return a list of preferred @sc{mime}
+types in order of their preference. This list is passed onto the
+@code{yank-media} command so the first element of the returned list is
+chosen when auto selection is requested.
+@end defvar
+
The @code{yank-media-types} command presents a list of selection data
types that are currently available, which is useful when implementing
yank-media handlers; for programs generally offer an eclectic and
(defvar yank-media--registered-handlers nil)
+(defvar yank-media-autoselect-function #'yank-media-autoselect-function
+ "Function to auto select the best MIME types when many are available.
+The function is called with a list of MIME types that have handler in
+the current buffer, and should return the list of MIME types to use in
+order of their priority. When `yank-media' auto-selects the MIME type,
+it will always choose the first one of the returned list.
+Major-mode authors can change this variable to influence the selection
+process.")
+
+(defvar yank-media-preferred-types
+ `(;; Check first since LibreOffice also puts a PNG image in the
+ ;; clipboard when a table cell is copied.
+ application/x-libreoffice-tsvc
+ ;; Give PNG more priority.
+ image/png
+ image/jpeg
+ ;; These are files copied/cut to the clipboard from a file manager
+ ;; in a GNU/Linux and/or BSD environment.
+ ,@(when (memq window-system '(x pgtk))
+ (list (lambda (mimetypes)
+ (ensure-list
+ (seq-find (lambda (type)
+ (string-match-p "x-special/\\(gnome\\|KDE\\|mate\\)-copied-files"
+ (symbol-name type)))
+ mimetypes)))))
+ ;; FIXME: We should have a way to handle text/rtf.
+ text/html)
+ "List of MIME types in the order of preference.
+Each element in the list should be a symbol to choose that MIME type
+exclusively, or a function of one argument and should return the list of
+MIME types to use in order of their priority or nil if no preferred type
+is found.
+Major-mode authors can change this variable to influence the selection
+process, or by directly changing the variable
+`yank-media-autoselect-function'.")
+
+(defun yank-media-autoselect-function (mimetypes)
+ (catch 'preferred
+ (dolist (typ yank-media-preferred-types)
+ (let ((ret (if (functionp typ)
+ (funcall typ mimetypes)
+ (and (memq typ mimetypes) (list typ)))))
+ (when ret (throw 'preferred ret))))))
+
;;;###autoload
-(defun yank-media ()
+(defun yank-media (&optional noselect)
"Yank media (images, HTML and the like) from the clipboard.
This command depends on the current major mode having support for
accepting the media type. The mode has to register itself using
the `yank-media-handler' mechanism.
+Optional argument NOSELECT non-nil (interactively, with a prefix
+argument) means to skip auto-selecting the best MIME type and ask for
+the MIME type to use.
Also see `yank-media-types' for a command that lets you explore
all the different selection types."
- (interactive)
+ (interactive "P")
(unless yank-media--registered-handlers
(user-error "The `%s' mode hasn't registered any handlers" major-mode))
- (let ((all-types nil))
+ (let ((all-types nil)
+ pref-type)
(pcase-dolist (`(,handled-type . ,handler)
yank-media--registered-handlers)
(dolist (type (yank-media--find-matching-media handled-type))
(unless all-types
(user-error
"No handler in the current buffer for anything on the clipboard"))
- ;; We have a handler in the current buffer; if there's just
- ;; matching type, just call the handler.
- (if (length= all-types 1)
+ (setq pref-type (and (null noselect)
+ (funcall yank-media-autoselect-function
+ (mapcar #'car all-types))))
+ (cond
+ ;; We are asked to autoselect and have a preferred MIME type.
+ ((and (null noselect) pref-type)
+ (funcall (cdr (assq (car pref-type) all-types))
+ (car pref-type)
+ (yank-media--get-selection (car pref-type))))
+ ;; We are asked to autoselect and no preferred MIME type.
+ ((and (null noselect) (null pref-type))
+ (message
+ (substitute-command-keys
+ "No preferred MIME type to yank, try \\[universal-argument] \\[yank-media]")))
+ ;; No autoselection and there's only one media type available.
+ ((and noselect (length= all-types 1))
+ (when (y-or-n-p (format "Yank the `%s' clipboard item?"
+ (caar all-types)))
(funcall (cdar all-types) (caar all-types)
- (yank-media--get-selection (caar all-types)))
- ;; More than one type the user for what type to insert.
+ (yank-media--get-selection (caar all-types)))))
+ ;; No autoselection and multiple media types available.
+ ((and noselect (length> all-types 1))
(let ((type
(intern
(completing-read "Several types available, choose one: "
- (mapcar #'car all-types) nil t))))
+ (or pref-type (mapcar #'car all-types))
+ nil t))))
(funcall (alist-get type all-types)
- type (yank-media--get-selection type))))))
+ type (yank-media--get-selection type)))))))
(defun yank-media--find-matching-media (handled-type)
(seq-filter