From fbf9c70cbbea5c46d4609395554cb897bf0ac86b Mon Sep 17 00:00:00 2001 From: djcb Date: Fri, 20 Apr 2012 17:53:41 +0300 Subject: [PATCH] * unified the action / attachment handling - mu4e-utils.el: s/mu4e-offer-action/mu4e-choose-action/, and return a function now, rather than executing it directly - mu4e-view.el: implement the attachment handling function in terms of mu4e-choose-action, and each other. also fix some small issues. --- emacs/mu4e-utils.el | 16 +++--- emacs/mu4e-view.el | 125 +++++++++++++++++++++++--------------------- 2 files changed, 73 insertions(+), 68 deletions(-) diff --git a/emacs/mu4e-utils.el b/emacs/mu4e-utils.el index 531c10be..4904133a 100644 --- a/emacs/mu4e-utils.el +++ b/emacs/mu4e-utils.el @@ -392,18 +392,18 @@ there is no message at point." point in eiter the headers buffer or the view buffer." (plist-get (mu4e-message-at-point t) field)) -(defun mu4e-offer-actions (prompt actions msg) +(defun mu4e-choose-action (prompt actions) "Ask user with PROMPT to choose some action from ACTIONS. ACTIONS is a list of actions like `mu4e-view-attachments-actions', -`mu4e-view-actions', `mu4e-header-actions'. Then, call the function -for this action, with the currrent message plist as the argument." +`mu4e-view-actions', `mu4e-header-actions'. Returns the +action (function) to invoke, or nil. " (if (null actions) (message "No actions of this type defined") - (let ((kar (mu4e-read-option prompt actions))) - (dolist (action actions) - (let ((shortcut (cadr action)) (func (nth 2 action))) - (when (eq kar shortcut) - (funcall func msg))))))) + (let* ((kar (mu4e-read-option prompt actions)) + (action ;; find the action for this kar + (find-if (lambda (ac) (eq kar (cadr ac))) actions))) + (when action + (nth 2 action))))) ;; return func (defun mu4e-capture-message () "Capture the path of the message at point." diff --git a/emacs/mu4e-view.el b/emacs/mu4e-view.el index b14723c2..a59b4ce7 100644 --- a/emacs/mu4e-view.el +++ b/emacs/mu4e-view.el @@ -179,15 +179,15 @@ DONT-PROPERTIZE-VAL is non-nil, do not add text-properties to VAL." ""))) -(defun mu4e-open-save-attach-func (num is-open) +(defun mu4e-open-save-attach-func (msg attachnum is-open) "Return a function that offers to save attachment NUM. If IS-OPEN is nil, and otherwise open it." - (lexical-let ((num num) (is-open is-open)) + (lexical-let ((msg msg) (attachnum attachnum) (is-open is-open)) (lambda () (interactive) (if is-open - (mu4e-view-open-attachment num) - (mu4e-view-save-attachment num))))) + (mu4e-view-open-attachment msg attachnum) + (mu4e-view-save-attachment msg attachnum))))) ;; note -- attachments have an index which is needed for the backend, which does ;; not necessarily follow 1,2,3,4 etc. @@ -204,11 +204,11 @@ is nil, and otherwise open it." (size (plist-get att :size)) (map (make-sparse-keymap))) (incf id) - (define-key map [mouse-2] (mu4e-open-save-attach-func id nil)) - (define-key map [?\r] (mu4e-open-save-attach-func id nil)) - (define-key map [S-mouse-2](mu4e-open-save-attach-func id t)) + (define-key map [mouse-2] (mu4e-open-save-attach-func msg id nil)) + (define-key map [?\r] (mu4e-open-save-attach-func msg id nil)) + (define-key map [S-mouse-2](mu4e-open-save-attach-func msg id t)) (define-key map (kbd "") - (mu4e-open-save-attach-func id t)) + (mu4e-open-save-attach-func msg id t)) (concat (propertize (format "[%d]" id) 'face 'mu4e-view-attach-number-face) (propertize name 'face 'mu4e-view-link-face @@ -218,7 +218,8 @@ is nil, and otherwise open it." (propertize (mu4e-display-size size) 'face 'mu4e-view-header-key-face))))))) (plist-get msg :attachments) ", "))) - (mu4e-view-header (format "Attachments(%d)" id) attstr t))) + (unless (zerop id) + (mu4e-view-header (format "Attachments(%d)" id) attstr t)))) (defvar mu4e-view-mode-map nil @@ -363,7 +364,7 @@ is nil, and otherwise open it." (use-local-map mu4e-view-mode-map) (make-local-variable 'mu4e-hdrs-buffer) - ;;(make-local-variable 'mu4e-current-msg) + (make-local-variable 'mu4e-current-msg) (make-local-variable 'mu4e-link-map) (make-local-variable 'mu4e-lines-wrapped) @@ -488,9 +489,8 @@ You can use this with e.g. org-contact with a template like: :END:\"))) See the `org-contacts' documentation for more details." - ;; FIXME: we need to explictly go to some (hopefully the right!) view buffer, - ;; since when using this from org-capture, we'll be taken to the capture - ;; buffer instead. + ;; FIXME: we need to explictly go to some view buffer, since when using this + ;; from org-capture, we'll be taken to the capture buffer instead. (with-current-buffer mu4e-view-buffer-name (unless (eq major-mode 'mu4e-view-mode) (error "Not in mu4e-view mode.")) @@ -591,35 +591,34 @@ citations." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; attachment handling - (defun mu4e--get-valid-attach (prompt msg &optional attachnum) - "Find an attachment sexp in MSG by asking tne user with -PROMPT. Return the sexp when it is present in the message, nil -otherwise. If (optional) ATTACHNUM is provided, don't ask user but -just return the corresponding attachment sexp or mil." +(defun mu4e--get-attach-num (prompt msg) + "Ask the user with PROMPT for an attachment number for MSG, and + ensure it is valid. The number is [1..n] for attachments + [0..(n-1)] in the message." (let* ((attlist (plist-get msg :attachments)) (count (length attlist))) - (when (zerop count) - (error "No attachments for this message")) - (let* ((attnum - (or attachnum - (if (= count 1) - (read-number (format "%s (1): " prompt) 1) - (read-number (format "%s (1-%d): " prompt count))))) - (att (nth (- attnum 1) attlist))) - (unless att - (error "Not a valid attachment number")) - att))) + (when (zerop count) (error "No attachments for this message")) + (if (= count 1) + (read-number (format "%s (1): " prompt) 1) + (read-number (format "%s (1-%d): " prompt count))))) -(defun mu4e-view-save-attachment (&optional msg attachnum) - "Save some attachment (ask user which)." +(defun mu4e--get-attach (msg attnum) + "Return the attachment plist in MSG corresponding to attachment +number ATTNUM." + (let ((attlist (plist-get msg :attachments))) + (nth (- attnum 1) attlist))) + +(defun mu4e-view-save-attachment (&optional msg attnum) + "Save attachment number ATTNUM (or ask if nil) from MSG (or +message-at-point if nil) to disk." (interactive) (unless mu4e-attachment-dir (error "`mu4e-attachment-dir' is not set")) (let* ((msg (or msg (mu4e-message-at-point))) - (att (mu4e--get-valid-attach "Attachment to save" - msg attachnum)) - (path (concat mu4e-attachment-dir - "/" (plist-get att :name))) + (attnum (or attnum + (mu4e--get-attach-num "Attachment to save" msg))) + (att (mu4e--get-attach msg attnum)) + (path (concat mu4e-attachment-dir "/" (plist-get att :name))) (index (plist-get att :index)) (retry t)) (while retry @@ -630,54 +629,60 @@ just return the corresponding attachment sexp or mil." (mu4e-proc-extract 'save (plist-get msg :docid) index path))) -(defun mu4e-view-open-attachment (&optional msg attachnum) - "Open some attachment (ask user which)." + +(defun mu4e-view-open-attachment (&optional msg attnum) + "Open attachment number ATTNUM (or ask if nil) from MSG (or +message-at-point if nil)." (interactive) (let* ((msg (or msg (mu4e-message-at-point))) - (att (mu4e--get-valid-attach "Attachment to open" - msg attachnum)) + (attnum (or attnum + (mu4e--get-attach-num "Attachment to open" msg))) + (att (mu4e--get-attach msg attnum)) (index (plist-get att :index))) (mu4e-proc-extract 'open (plist-get msg :docid) index))) + (defun mu4e--temp-action (docid index what &optional param) "Open attachment INDEX for message with DOCID, and invoke ACTION." (interactive) (mu4e-proc-extract 'temp docid index nil what param)) -(defun mu4e-view-open-attachment-with (msg) - "Open some attachment with some program (ask user which)." +(defun mu4e-view-open-attachment-with (msg attachnum &optional cmd) + "Open MSG's attachment ATTACHNUM with CMD; if CMD is nil, ask +user for it." (interactive) - (let* ((att (mu4e--get-valid-attach "Attachment to open" msg)) - (cmd (read-string "Shell command to open it with: ")) + (let* ((att (mu4e--get-attach msg attachnum)) + (cmd (or cmd (read-string "Shell command to open it with: "))) (index (plist-get att :index))) - (mu4e--temp-action (plist-get msg :docid) index - "open-with" cmd))) + (mu4e--temp-action (plist-get msg :docid) index "open-with" cmd))) -(defun mu4e-view-pipe-attachment (msg) - "Open some attachment with some program (ask user which)." +(defun mu4e-view-pipe-attachment (msg attachnum &optional pipecmd) + "Feed MSG's attachment ATTACHNUM throught pipe PIPECMD; if +PIPECMD is nil, ask user for it." (interactive) - (let* ((att (mu4e--get-valid-attach "Attachment to process" msg)) - (cmd (read-string "Pipe: ")) + (let* ((att (mu4e--get-attach msg attachnum)) + (pipecmd (or pipecmd (read-string "Pipe: "))) (index (plist-get att :index))) - (mu4e--temp-action (plist-get msg :docid) index - "pipe" cmd))) + (mu4e--temp-action (plist-get msg :docid) index "pipe" pipecmd))) -(defun mu4e-view-open-attachment-emacs (msg) - "Open some attachment in the current emacs instance." +(defun mu4e-view-open-attachment-emacs (msg attachnum) + "Open MSG's attachment ATTACHNUM in the current emacs instance." (interactive) - (let* ((att (mu4e--get-valid-attach - "Attachment to open in current emacs" msg)) + (let* ((att (mu4e--get-attach msg attachnum)) (index (plist-get att :index))) - (mu4e--temp-action (plist-get msg :docid) index - "emacs"))) + (mu4e--temp-action (plist-get msg :docid) index "emacs"))) (defun mu4e-view-handle-attachment (&optional msg) "Ask user what to do with attachments, then do it." (interactive) - (mu4e-offer-actions "Attachment action: " - mu4e-view-attachments-actions - (or msg (mu4e-message-at-point t)))) + (let* ((msg (or msg (mu4e-message-at-point t))) + (actionfunc (mu4e-choose-action + "Action on attachment: " + mu4e-view-attachments-actions)) + (attnum (mu4e--get-attach-num "Which attachment" msg))) + (when (and actionfunc attnum) + (funcall actionfunc msg attnum)))) ;; handler-function to handle the response we get from the server when we ;; want to do something with one of the attachments.