From 5044469255e5ad8a28c27178ea0f830771ffa8e1 Mon Sep 17 00:00:00 2001 From: Visuwesh Date: Thu, 13 Feb 2025 16:43:06 +0530 Subject: [PATCH] Make yank-media auto select the best mime type * lisp/yank-media.el (yank-media-preferred-types): Add new variable that holds the list of mime types in order of their preference. (yank-media-autoselect-function): Add new variable and function to choose the most preferred media type. (yank-media): Make 'yank-media' choose the most preferred mime type by default. * doc/emacs/killing.texi (Clipboard): * doc/lispref/frames.texi (Yanking Media): Document the new behaviour, and the new variables. * etc/NEWS: Announce the change. (Bug#75116) (cherry picked from commit 0ee50a3420fb8df8f3477dac610dcd53c633fff5) --- doc/emacs/killing.texi | 6 ++- doc/lispref/frames.texi | 24 ++++++++++++ lisp/yank-media.el | 85 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi index 070e15dee76..aee68608bbf 100644 --- a/doc/emacs/killing.texi +++ b/doc/emacs/killing.texi @@ -587,8 +587,10 @@ change the variable @code{select-enable-clipboard} to @code{nil}. 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 diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index bc2d6b07ae8..984f9bb597d 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -4812,6 +4812,30 @@ designating the matching selection data type, and the data returned by @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 diff --git a/lisp/yank-media.el b/lisp/yank-media.el index 2b9a0e70e45..71f617d30b2 100644 --- a/lisp/yank-media.el +++ b/lisp/yank-media.el @@ -29,19 +29,67 @@ (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)) @@ -49,18 +97,35 @@ all the different selection types." (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 -- 2.39.5