Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id A2657429E5F for ; Tue, 17 Jan 2012 15:53:33 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -0.7 X-Spam-Level: X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5 tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Egu9nNRoAjY3 for ; Tue, 17 Jan 2012 15:53:32 -0800 (PST) Received: from dmz-mailsec-scanner-5.mit.edu (DMZ-MAILSEC-SCANNER-5.MIT.EDU [18.7.68.34]) by olra.theworths.org (Postfix) with ESMTP id B890A429E27 for ; Tue, 17 Jan 2012 15:53:32 -0800 (PST) X-AuditID: 12074422-b7fd66d0000008f9-ff-4f1609fc9874 Received: from mailhub-auth-2.mit.edu ( [18.7.62.36]) by dmz-mailsec-scanner-5.mit.edu (Symantec Messaging Gateway) with SMTP id 91.B6.02297.CF9061F4; Tue, 17 Jan 2012 18:53:32 -0500 (EST) Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103]) by mailhub-auth-2.mit.edu (8.13.8/8.9.2) with ESMTP id q0HNrVqE014300; Tue, 17 Jan 2012 18:53:32 -0500 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91]) (authenticated bits=0) (User authenticated as amdragon@ATHENA.MIT.EDU) by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q0HNrU9L021213 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); Tue, 17 Jan 2012 18:53:31 -0500 (EST) Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77) (envelope-from ) id 1RnIq6-0008Ki-Db; Tue, 17 Jan 2012 18:53:18 -0500 Date: Tue, 17 Jan 2012 18:53:18 -0500 From: Austin Clements To: Mark Walters Subject: Re: [PATCH v3] Make buttons for attachments allow viewing as well as saving Message-ID: <20120117235318.GZ16740@mit.edu> References: <87lip5rj43.fsf@qmul.ac.uk> <1326843886-18387-1-git-send-email-markwalters1009@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1326843886-18387-1-git-send-email-markwalters1009@gmail.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpileLIzCtJLcpLzFFi42IRYrdT0f3DKeZv8GgHp8XquTwW12/OZHZg 8tg56y67x7NVt5gDmKK4bFJSczLLUov07RK4Ms7+/8tUMNWi4nyvTwPjAt0uRk4OCQETic3d 89ghbDGJC/fWs3UxcnEICexjlPh0eycThLOBUWLZwSesEM5JJokTP+exQDhLGCV+/ZnKAtLP IqAq8eLLDWYQm01AQ2Lb/uWMILaIgI7E7UMLwHYwC0hLfPvdzARiCwuESXxt3g5WzwtU8/To WrAaIYF0iX/rz7FCxAUlTs58wgLRqyVx499LoF4OsDnL/3GAhDkFvCTeHpkLNkZUQEViyslt bBMYhWYh6Z6FpHsWQvcCRuZVjLIpuVW6uYmZOcWpybrFyYl5ealFuqZ6uZkleqkppZsYwUHt orSD8edBpUOMAhyMSjy8BZtE/YVYE8uKK3MPMUpyMCmJ8k5mF/MX4kvKT6nMSCzOiC8qzUkt PsQowcGsJMLLygyU401JrKxKLcqHSUlzsCiJ86prvfMD+jexJDU7NbUgtQgmK8PBoSTBe4QD qFGwKDU9tSItM6cEIc3EwQkynAdoeCfIYt7igsTc4sx0iPwpRkUpcV4FYNoQEgBJZJTmwfXC ks4rRnGgV4R5dUGqeIAJC677FdBgJqDBOa1CIINLEhFSUg2ME1dqVp6SfintM/OE4LMt1f7c oSd5n2tr1/PEndO9+pmtY8b21JvFWx/xt8h2bpmWcUX6YXXMBB32jqD8gB1WU2MvvKmYbPJa /LDh5gkMMYfY1rNe/FrJeEU7uOT4lmiDnY/PbGA7dPL5ssk6ElUMMzJ8w/6Y6bFnLyi9Xp2n 7PL5M4vMDzcWJZbijERDLeai4kQAtJPkvRUDAAA= Cc: notmuch@notmuchmail.org X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Jan 2012 23:53:33 -0000 Quoth Mark Walters on Jan 17 at 11:44 pm: > Define a keymap for attachment buttons to allow multiple actions. > Define 3 possible actions: > save attachment: exactly as currently, > view attachment: uses mailcap entry, > view attachment with user chosen program > > Keymap on a button is: s for save, v for view and o for view with > other program. Default (i.e. enter or mouse button) is save but this > is configurable in notmuch customize. > > One implementation detail: the view attachment function forces all > attachments to be "displayed" using mailcap even if emacs could > display them itself. Thus, for example, text/html appears in a browser > and text/plain asks whether to save (on a standard debian setup) Oof, sorry. Two more tweaks that I really should have caught in the previous version. After that this gets my automatic +1. > --- > emacs/notmuch-show.el | 106 ++++++++++++++++++++++++++++++++++++++----------- > 1 files changed, 82 insertions(+), 24 deletions(-) > > diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el > index 03c1f6b..0aaaf79 100644 > --- a/emacs/notmuch-show.el > +++ b/emacs/notmuch-show.el > @@ -281,10 +281,21 @@ message at DEPTH in the current thread." > (run-hooks 'notmuch-show-markup-headers-hook))))) > > (define-button-type 'notmuch-show-part-button-type > - 'action 'notmuch-show-part-button-action > + 'action 'notmuch-show-part-button-default > + 'keymap 'notmuch-show-part-button-map > 'follow-link t > 'face 'message-mml) > > +(defvar notmuch-show-part-button-map > + (let ((map (make-sparse-keymap))) > + (set-keymap-parent map button-map) > + (define-key map "s" 'notmuch-show-part-button-save) > + (define-key map "v" 'notmuch-show-part-button-view) > + (define-key map "o" 'notmuch-show-part-button-interactively-view) Indentation. > + map) > + "Submap for button commands") > +(fset 'notmuch-show-part-button-map notmuch-show-part-button-map) > + > (defun notmuch-show-insert-part-header (nth content-type declared-type &optional name comment) > (let ((button)) > (setq button > @@ -299,29 +310,48 @@ message at DEPTH in the current thread." > " ]") > :type 'notmuch-show-part-button-type > :notmuch-part nth > - :notmuch-filename name)) > + :notmuch-filename name > + :notmuch-content-type content-type)) > (insert "\n") > ;; return button > button)) > > ;; Functions handling particular MIME parts. > > -(defun notmuch-show-save-part (message-id nth &optional filename) > - (let ((process-crypto notmuch-show-process-crypto)) > - (with-temp-buffer > - (setq notmuch-show-process-crypto process-crypto) > - ;; Always acquires the part via `notmuch part', even if it is > - ;; available in the JSON output. > - (insert (notmuch-show-get-bodypart-internal message-id nth)) > - (let ((file (read-file-name > - "Filename to save as: " > - (or mailcap-download-directory "~/") > - nil nil > - filename))) > - ;; Don't re-compress .gz & al. Arguably we should make > - ;; `file-name-handler-alist' nil, but that would chop > - ;; ange-ftp, which is reasonable to use here. > - (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t))))) > +(defmacro notmuch-with-temp-part-buffer (message-id nth &rest body) > + (declare (indent 2)) > + (let ((process-crypto (make-symbol "process-crypto"))) > + `(let ((,process-crypto notmuch-show-process-crypto)) > + (with-temp-buffer > + (setq notmuch-show-process-crypto ,process-crypto) > + ;; Always acquires the part via `notmuch part', even if it is > + ;; available in the JSON output. > + (insert (notmuch-show-get-bodypart-internal ,message-id ,nth)) > + ,@body)))) > + > +(defun notmuch-show-save-part (message-id nth &optional filename content-type) > + (notmuch-with-temp-part-buffer message-id nth > + (let ((file (read-file-name > + "Filename to save as: " > + (or mailcap-download-directory "~/") > + nil nil > + filename))) > + ;; Don't re-compress .gz & al. Arguably we should make > + ;; `file-name-handler-alist' nil, but that would chop > + ;; ange-ftp, which is reasonable to use here. > + (mm-write-region (point-min) (point-max) file nil nil nil 'no-conversion t)))) > + > +(defun notmuch-show-view-part (message-id nth &optional filename content-type ) > + (notmuch-with-temp-part-buffer message-id nth > + ;; set mm-inlined-types to nil to force an external viewer > + (let ((handle (mm-make-handle (current-buffer) (list content-type))) > + (mm-inlined-types nil)) > + (mm-display-part handle t)))) > + > +(defun notmuch-show-interactively-view-part (message-id nth &optional filename content-type) > + (notmuch-with-temp-part-buffer message-id nth > + (let ((handle (mm-make-handle (current-buffer) (list content-type)))) > + (mm-interactively-view-part handle)))) > > (defun notmuch-show-mm-display-part-inline (msg part nth content-type) > "Use the mm-decode/mm-view functions to display a part in the > @@ -1502,12 +1532,40 @@ buffer." > > ;; Commands typically bound to buttons. > > -(defun notmuch-show-part-button-action (button) > - (let ((nth (button-get button :notmuch-part))) > - (if nth > - (notmuch-show-save-part (notmuch-show-get-message-id) nth > - (button-get button :notmuch-filename)) > - (message "Not a valid part (is it a fake part?).")))) > +(defcustom notmuch-show-part-button-default-action 'notmuch-show-save-part > + "Default part header button action (on ENTER or mouse click)." > + :group 'notmuch > + :type '(choice (const :tag "Save part" > + notmuch-show-save-part) > + (const :tag "View part" > + notmuch-show-view-part) > + (const :tag "View interactively" > + notmuch-show-interactively-view-part))) defcustoms customarily appear at the top of the file (see the rest of the defcustoms in notmuch-show.el) > + > +(defun notmuch-show-part-button-default (&optional button) > + (interactive) > + (notmuch-show-part-button-internal button notmuch-show-part-button-default-action)) > + > +(defun notmuch-show-part-button-save (&optional button) > + (interactive) > + (notmuch-show-part-button-internal button #'notmuch-show-save-part)) > + > +(defun notmuch-show-part-button-view (&optional button) > + (interactive) > + (notmuch-show-part-button-internal button #'notmuch-show-view-part)) > + > +(defun notmuch-show-part-button-interactively-view (&optional button) > + (interactive) > + (notmuch-show-part-button-internal button #'notmuch-show-interactively-view-part)) > + > +(defun notmuch-show-part-button-internal (button handler) > + (let ((button (or button (button-at (point))))) > + (if button > + (let ((nth (button-get button :notmuch-part))) > + (if nth > + (funcall handler (notmuch-show-get-message-id) nth > + (button-get button :notmuch-filename) > + (button-get button :notmuch-content-type))))))) > > ;; >