aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2021-11-06 21:59:22 +0100
committerLars Ingebrigtsen2021-11-06 21:59:27 +0100
commit48ca3c99c8121007eef38d457ddc25158118a8d3 (patch)
tree8de1fa0946eab1330e6fc494a1edd0cb989229a6
parent5a4f98b0b6d503b1ce68bb29937a84acf3ef97da (diff)
downloademacs-48ca3c99c8121007eef38d457ddc25158118a8d3.tar.gz
emacs-48ca3c99c8121007eef38d457ddc25158118a8d3.zip
Add a framework for yanking media into Emacs
* doc/emacs/killing.texi (Clipboard): Refer to it. * doc/lispref/frames.texi (Yanking Media): Document the mechanism. * lisp/yank-media.el: New file. * lisp/gnus/message.el (message-mode): Register a yank handler for images. (message-insert-screenshot): Factor out image code from here... (message--yank-media-image-handler): ... to here.
-rw-r--r--doc/emacs/killing.texi8
-rw-r--r--doc/lispref/elisp.texi1
-rw-r--r--doc/lispref/frames.texi36
-rw-r--r--etc/NEWS9
-rw-r--r--lisp/gnus/message.el41
-rw-r--r--lisp/yank-media.el95
6 files changed, 173 insertions, 17 deletions
diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi
index 76fccdbdfec..5e8b33f291b 100644
--- a/doc/emacs/killing.texi
+++ b/doc/emacs/killing.texi
@@ -562,6 +562,14 @@ new yank to the clipboard.
562 To prevent kill and yank commands from accessing the clipboard, 562 To prevent kill and yank commands from accessing the clipboard,
563change the variable @code{select-enable-clipboard} to @code{nil}. 563change the variable @code{select-enable-clipboard} to @code{nil}.
564 564
565@findex yank-media
566 Programs can put other things than plain text on the clipboard. For
567instance, a web browser will usually let you choose ``Copy Image'' on
568images, and this image will be put on the clipboard. Emacs can yank
569these objects with the @code{yank-media} command---but only in modes
570that have support for it (@pxref{Yanking Media,,, elisp, The Emacs
571Lisp Reference Manual}).
572
565@cindex clipboard manager 573@cindex clipboard manager
566@vindex x-select-enable-clipboard-manager 574@vindex x-select-enable-clipboard-manager
567 Many X desktop environments support a feature called the 575 Many X desktop environments support a feature called the
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 6057691239f..d0bfd8c9019 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -1123,6 +1123,7 @@ Frames
1123* Dialog Boxes:: Displaying a box to ask yes or no. 1123* Dialog Boxes:: Displaying a box to ask yes or no.
1124* Pointer Shape:: Specifying the shape of the mouse pointer. 1124* Pointer Shape:: Specifying the shape of the mouse pointer.
1125* Window System Selections::Transferring text to and from other X clients. 1125* Window System Selections::Transferring text to and from other X clients.
1126* Yanking Media:: Yanking things that aren't plain text.
1126* Drag and Drop:: Internals of Drag-and-Drop implementation. 1127* Drag and Drop:: Internals of Drag-and-Drop implementation.
1127* Color Names:: Getting the definitions of color names. 1128* Color Names:: Getting the definitions of color names.
1128* Text Terminal Colors:: Defining colors for text terminals. 1129* Text Terminal Colors:: Defining colors for text terminals.
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 56ac7118135..a706dc76d25 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -105,6 +105,7 @@ window of another Emacs frame. @xref{Child Frames}.
105* Dialog Boxes:: Displaying a box to ask yes or no. 105* Dialog Boxes:: Displaying a box to ask yes or no.
106* Pointer Shape:: Specifying the shape of the mouse pointer. 106* Pointer Shape:: Specifying the shape of the mouse pointer.
107* Window System Selections:: Transferring text to and from other X clients. 107* Window System Selections:: Transferring text to and from other X clients.
108* Yanking Media:: Yanking things that aren't plain text.
108* Drag and Drop:: Internals of Drag-and-Drop implementation. 109* Drag and Drop:: Internals of Drag-and-Drop implementation.
109* Color Names:: Getting the definitions of color names. 110* Color Names:: Getting the definitions of color names.
110* Text Terminal Colors:: Defining colors for text terminals. 111* Text Terminal Colors:: Defining colors for text terminals.
@@ -3923,6 +3924,41 @@ For backward compatibility, there are obsolete aliases
3923names of @code{gui-get-selection} and @code{gui-set-selection} before 3924names of @code{gui-get-selection} and @code{gui-set-selection} before
3924Emacs 25.1. 3925Emacs 25.1.
3925 3926
3927@node Yanking Media
3928@subsection Yanking Media
3929
3930 If you choose, for instance, ``Copy Image'' in a web browser, that
3931image is put onto the clipboard, and Emacs can access it via
3932@code{gui-get-selection}. But in general, inserting image data into
3933an arbitrary buffer isn't very useful---you can't really do much with
3934it by default.
3935
3936 So Emacs has a system to let modes register handlers for these
3937``complicated'' selections.
3938
3939@defun register-yank-media-handler types handler
3940@var{types} can be a @acronym{MIME} media type symbol, a regexp to
3941match these, or a list of these symbols and regexps. For instance:
3942
3943@example
3944(register-yank-media-handler 'text/html #'my-html-handler)
3945(register-yank-media-handler "image/.*" #'my-image-handler)
3946@end example
3947
3948A mode can register as many handlers as required.
3949
3950 The @var{handler} function is called with two parameters: The
3951@acronym{MIME} media type symbol and the data (as a string). The
3952handler should then insert the object into the buffer, or save it, or
3953do whatever is appropriate for the mode.
3954@end defun
3955
3956 The @code{yank-media} command will consult the registered handlers in
3957the current buffer, compare that with the available media types on the
3958clipboard, and then pass on the matching selection to the handler (if
3959any). If there's more than one matching selection, the user is
3960queried first.
3961
3926@node Drag and Drop 3962@node Drag and Drop
3927@section Drag and Drop 3963@section Drag and Drop
3928@cindex drag and drop 3964@cindex drag and drop
diff --git a/etc/NEWS b/etc/NEWS
index 8aba24ac5ee..c9133195e9d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -216,6 +216,9 @@ consistent with 'vc-responsible-backend'.
216*** New user option 'mml-attach-file-at-the-end'. 216*** New user option 'mml-attach-file-at-the-end'.
217If non-nil, 'C-c C-a' will put attached files at the end of the message. 217If non-nil, 'C-c C-a' will put attached files at the end of the message.
218 218
219---
220*** Message Mode now supports image yanking.
221
219** Gnus 222** Gnus
220 223
221+++ 224+++
@@ -553,12 +556,18 @@ Use 'exif-parse-file' and 'exif-field' instead.
553 556
554* Lisp Changes in Emacs 29.1 557* Lisp Changes in Emacs 29.1
555 558
559*** New command 'yank-media'.
560This command supports yanking non-plain-text media like images and
561HTML from other applications into Emacs. It is only supported in
562modes that have registered support for it.
563
556+++ 564+++
557*** New text property 'inhibit-isearch'. 565*** New text property 'inhibit-isearch'.
558If set, 'isearch' will skip these areas, which can be useful (for 566If set, 'isearch' will skip these areas, which can be useful (for
559instance) when covering huge amounts of data (that has no meaningful 567instance) when covering huge amounts of data (that has no meaningful
560searchable data, like image data) with a 'display' text property. 568searchable data, like image data) with a 'display' text property.
561 569
570+++
562*** 'insert-image' now takes an INHIBIT-ISEARCH optional parameter. 571*** 'insert-image' now takes an INHIBIT-ISEARCH optional parameter.
563It marks the image with the 'inhibit-isearch' text parameter, which 572It marks the image with the 'inhibit-isearch' text parameter, which
564inhibits 'isearch' matching the STRING parameter. 573inhibits 'isearch' matching the STRING parameter.
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 133f8424aea..b7d98d52de5 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -48,6 +48,8 @@
48(require 'puny) 48(require 'puny)
49(require 'rmc) ; read-multiple-choice 49(require 'rmc) ; read-multiple-choice
50(require 'subr-x) 50(require 'subr-x)
51(require 'yank-media)
52(require 'mailcap)
51 53
52(autoload 'mailclient-send-it "mailclient") 54(autoload 'mailclient-send-it "mailclient")
53 55
@@ -3155,6 +3157,7 @@ Like `text-mode', but with these additional commands:
3155 (setq-local message-checksum nil) 3157 (setq-local message-checksum nil)
3156 (setq-local message-mime-part 0) 3158 (setq-local message-mime-part 0)
3157 (message-setup-fill-variables) 3159 (message-setup-fill-variables)
3160 (register-yank-media-handler "image/.*" #'message--yank-media-image-handler)
3158 (when message-fill-column 3161 (when message-fill-column
3159 (setq fill-column message-fill-column) 3162 (setq fill-column message-fill-column)
3160 (turn-on-auto-fill)) 3163 (turn-on-auto-fill))
@@ -8873,25 +8876,29 @@ used to take the screenshot."
8873 (car message-screenshot-command) nil (current-buffer) nil 8876 (car message-screenshot-command) nil (current-buffer) nil
8874 (cdr message-screenshot-command)) 8877 (cdr message-screenshot-command))
8875 (buffer-string)))) 8878 (buffer-string))))
8876 (set-mark (point)) 8879 (message--yank-media-image-handler 'image/png image)
8877 (insert-image
8878 (create-image image 'png t
8879 :max-width (truncate (* (frame-pixel-width) 0.8))
8880 :max-height (truncate (* (frame-pixel-height) 0.8))
8881 :scale 1)
8882 (format "<#part type=\"image/png\" disposition=inline data-encoding=base64 raw=t>\n%s\n<#/part>"
8883 ;; Get a base64 version of the image -- this avoids later
8884 ;; complications if we're auto-saving the buffer and
8885 ;; restoring from a file.
8886 (with-temp-buffer
8887 (set-buffer-multibyte nil)
8888 (insert image)
8889 (base64-encode-region (point-min) (point-max) t)
8890 (buffer-string)))
8891 nil nil t)
8892 (insert "\n\n")
8893 (message ""))) 8880 (message "")))
8894 8881
8882(defun message--yank-media-image-handler (type image)
8883 (set-mark (point))
8884 (insert-image
8885 (create-image image (mailcap-mime-type-to-extension type) t
8886 :max-width (truncate (* (frame-pixel-width) 0.8))
8887 :max-height (truncate (* (frame-pixel-height) 0.8))
8888 :scale 1)
8889 (format "<#part type=\"%s\" disposition=inline data-encoding=base64 raw=t>\n%s\n<#/part>"
8890 type
8891 ;; Get a base64 version of the image -- this avoids later
8892 ;; complications if we're auto-saving the buffer and
8893 ;; restoring from a file.
8894 (with-temp-buffer
8895 (set-buffer-multibyte nil)
8896 (insert image)
8897 (base64-encode-region (point-min) (point-max) t)
8898 (buffer-string)))
8899 nil nil t)
8900 (insert "\n\n"))
8901
8895(declare-function gnus-url-unhex-string "gnus-util") 8902(declare-function gnus-url-unhex-string "gnus-util")
8896 8903
8897(defun message-parse-mailto-url (url) 8904(defun message-parse-mailto-url (url)
diff --git a/lisp/yank-media.el b/lisp/yank-media.el
new file mode 100644
index 00000000000..5cc5e366e9c
--- /dev/null
+++ b/lisp/yank-media.el
@@ -0,0 +1,95 @@
1;;; yank-media.el --- Yanking images and HTML -*- lexical-binding:t -*-
2
3;; Copyright (C) 2021 Free Software Foundation, Inc.
4
5;; Author: Lars Ingebrigtsen <larsi@gnus.org>
6;; Keywords: utility
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;;; Code:
26
27(require 'cl-lib)
28
29(defvar yank-media--registered-handlers nil)
30
31;;;###autoload
32(defun yank-media ()
33 "Yank media (images, HTML and the like) from the clipboard.
34This command depends on the current major mode having support for
35accepting the media type. The mode has to register itself using
36the `register-yank-media-handler' mechanism."
37 (interactive)
38 (unless yank-media--registered-handlers
39 (user-error "The `%s' mode hasn't registered any handlers" major-mode))
40 (catch 'found
41 (pcase-dolist (`(,handled-type . ,handler)
42 yank-media--registered-handlers)
43 (when-let ((types (yank-media--find-matching-media handled-type)))
44 ;; We have a handler in the current buffer; if there's just
45 ;; matching type, just call the handler.
46 (if (length= types 1)
47 (funcall handler (car types)
48 (yank-media--get-selection (car types)))
49 ;; More than one type the user for what type to insert.
50 (let ((type
51 (intern
52 (completing-read "Several types available, choose one: "
53 types nil t))))
54 (funcall handler type (yank-media--get-selection type))))
55 (throw 'found nil)))
56 (user-error
57 "No handler in the current buffer for anything on the clipboard")))
58
59(defun yank-media--find-matching-media (handled-type)
60 (seq-filter
61 (lambda (type)
62 (pcase-let ((`(,major ,minor) (split-string (symbol-name type) "/")))
63 (if (and (equal major "image")
64 (not (image-type-available-p (intern minor))))
65 ;; Just filter out all the image types that Emacs doesn't
66 ;; support, because the clipboard is full of things like
67 ;; `image/x-win-bitmap'.
68 nil
69 ;; Check that the handler wants this type.
70 (and (if (symbolp handled-type)
71 (eq handled-type type)
72 (string-match-p handled-type (symbol-name type)))
73 ;; An element may be in TARGETS but be empty.
74 (yank-media--get-selection type)))))
75 (gui-get-selection 'CLIPBOARD 'TARGETS)))
76
77(defun yank-media--get-selection (type)
78 (when-let ((data (gui-get-selection 'CLIPBOARD type)))
79 (if-let ((charset (get-text-property 0 'charset data)))
80 (encode-coding-string data charset)
81 data)))
82
83;;;###autoload
84(defun register-yank-media-handler (types handler)
85 "Register HANDLER for dealing with `yank-media' actions for TYPES.
86TYPES should be a MIME media type symbol, a regexp, or a list
87that can contain both symbols and regexps."
88 (make-local-variable 'yank-media--registered-handlers)
89 (dolist (type (ensure-list types))
90 (setf (alist-get type yank-media--registered-handlers nil nil #'equal)
91 handler)))
92
93(provide 'yank-media)
94
95;;; yank-media.el ends here