* 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.
This commit is contained in:
djcb
2012-04-20 17:53:41 +03:00
parent e0db2dcfb2
commit fbf9c70cbb
2 changed files with 73 additions and 68 deletions

View File

@ -392,18 +392,18 @@ there is no message at point."
"Get FIELD (a symbol, see `mu4e-header-names') for the message at "Get FIELD (a symbol, see `mu4e-header-names') for the message at
point in eiter the headers buffer or the view buffer." point in eiter the headers buffer or the view buffer."
(plist-get (mu4e-message-at-point t) field)) (plist-get (mu4e-message-at-point t) field))
(defun mu4e-choose-action (prompt actions) (defun mu4e-choose-action (prompt actions)
"Ask user with PROMPT to choose some action from ACTIONS. ACTIONS "Ask user with PROMPT to choose some action from ACTIONS. ACTIONS
is a list of actions like `mu4e-view-attachments-actions', is a list of actions like `mu4e-view-attachments-actions',
`mu4e-view-actions', `mu4e-header-actions'. Then, call the function `mu4e-view-actions', `mu4e-header-actions'. Returns the
action (function) to invoke, or nil. " action (function) to invoke, or nil. "
(if (null actions) (if (null actions)
(message "No actions of this type defined") (message "No actions of this type defined")
(let ((kar (mu4e-read-option prompt actions))) (let* ((kar (mu4e-read-option prompt actions))
(dolist (action actions) (action ;; find the action for this kar
(let ((shortcut (cadr action)) (func (nth 2 action))) (find-if (lambda (ac) (eq kar (cadr ac))) actions)))
(when (eq kar shortcut) (when action
(nth 2 action))))) ;; return func (nth 2 action))))) ;; return func
(defun mu4e-capture-message () (defun mu4e-capture-message ()

View File

@ -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 "Return a function that offers to save attachment NUM. If IS-OPEN
is nil, and otherwise open it." 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 () (lambda ()
(interactive) (interactive)
(if is-open (if is-open
(mu4e-view-open-attachment num) (mu4e-view-open-attachment msg attachnum)
(mu4e-view-save-attachment num))))) (mu4e-view-save-attachment msg attachnum)))))
;; note -- attachments have an index which is needed for the backend, which does ;; note -- attachments have an index which is needed for the backend, which does
;; not necessarily follow 1,2,3,4 etc. ;; not necessarily follow 1,2,3,4 etc.
@ -204,11 +204,11 @@ is nil, and otherwise open it."
(size (plist-get att :size)) (size (plist-get att :size))
(map (make-sparse-keymap))) (map (make-sparse-keymap)))
(incf id) (incf id)
(define-key map [mouse-2] (mu4e-open-save-attach-func id nil)) (define-key map [mouse-2] (mu4e-open-save-attach-func msg id nil))
(define-key map [?\r] (mu4e-open-save-attach-func 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 id t)) (define-key map [S-mouse-2](mu4e-open-save-attach-func msg id t))
(define-key map (kbd "<S-return>") (define-key map (kbd "<S-return>")
(mu4e-open-save-attach-func id t)) (mu4e-open-save-attach-func msg id t))
(concat (concat
(propertize (format "[%d]" id) 'face 'mu4e-view-attach-number-face) (propertize (format "[%d]" id) 'face 'mu4e-view-attach-number-face)
(propertize name 'face 'mu4e-view-link-face (propertize name 'face 'mu4e-view-link-face
@ -218,7 +218,8 @@ is nil, and otherwise open it."
(propertize (mu4e-display-size size) (propertize (mu4e-display-size size)
'face 'mu4e-view-header-key-face))))))) 'face 'mu4e-view-header-key-face)))))))
(plist-get msg :attachments) ", "))) (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 (defvar mu4e-view-mode-map nil
@ -363,7 +364,7 @@ is nil, and otherwise open it."
(use-local-map mu4e-view-mode-map) (use-local-map mu4e-view-mode-map)
(make-local-variable 'mu4e-hdrs-buffer) (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-link-map)
(make-local-variable 'mu4e-lines-wrapped) (make-local-variable 'mu4e-lines-wrapped)
@ -488,9 +489,8 @@ You can use this with e.g. org-contact with a template like:
:END:\"))) :END:\")))
See the `org-contacts' documentation for more details." See the `org-contacts' documentation for more details."
;; FIXME: we need to explictly go to some (hopefully the right!) view buffer, ;; FIXME: we need to explictly go to some view buffer, since when using this
;; since when using this from org-capture, we'll be taken to the capture ;; from org-capture, we'll be taken to the capture buffer instead.
;; buffer instead.
(with-current-buffer mu4e-view-buffer-name (with-current-buffer mu4e-view-buffer-name
(unless (eq major-mode 'mu4e-view-mode) (unless (eq major-mode 'mu4e-view-mode)
(error "Not in mu4e-view mode.")) (error "Not in mu4e-view mode."))
@ -591,35 +591,34 @@ citations."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; attachment handling ;; attachment handling
(defun mu4e--get-valid-attach (prompt msg &optional attachnum) (defun mu4e--get-attach-num (prompt msg)
"Find an attachment sexp in MSG by asking tne user with "Ask the user with PROMPT for an attachment number for MSG, and
PROMPT. Return the sexp when it is present in the message, nil ensure it is valid. The number is [1..n] for attachments
otherwise. If (optional) ATTACHNUM is provided, don't ask user but [0..(n-1)] in the message."
just return the corresponding attachment sexp or mil."
(let* ((attlist (plist-get msg :attachments)) (let* ((attlist (plist-get msg :attachments))
(count (length attlist))) (count (length attlist)))
(when (zerop count) (when (zerop count) (error "No attachments for this message"))
(error "No attachments for this message")) (if (= count 1)
(let* ((attnum (read-number (format "%s (1): " prompt) 1)
(or attachnum (read-number (format "%s (1-%d): " prompt count)))))
(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)))
(defun mu4e-view-save-attachment (&optional msg attachnum) (defun mu4e--get-attach (msg attnum)
"Save some attachment (ask user which)." "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) (interactive)
(unless mu4e-attachment-dir (unless mu4e-attachment-dir
(error "`mu4e-attachment-dir' is not set")) (error "`mu4e-attachment-dir' is not set"))
(let* ((msg (or msg (mu4e-message-at-point))) (let* ((msg (or msg (mu4e-message-at-point)))
(att (mu4e--get-valid-attach "Attachment to save" (attnum (or attnum
msg attachnum)) (mu4e--get-attach-num "Attachment to save" msg)))
(path (concat mu4e-attachment-dir (att (mu4e--get-attach msg attnum))
"/" (plist-get att :name))) (path (concat mu4e-attachment-dir "/" (plist-get att :name)))
(index (plist-get att :index)) (index (plist-get att :index))
(retry t)) (retry t))
(while retry (while retry
@ -630,54 +629,60 @@ just return the corresponding attachment sexp or mil."
(mu4e-proc-extract (mu4e-proc-extract
'save (plist-get msg :docid) index path))) '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) (interactive)
(let* ((msg (or msg (mu4e-message-at-point))) (let* ((msg (or msg (mu4e-message-at-point)))
(att (mu4e--get-valid-attach "Attachment to open" (attnum (or attnum
msg attachnum)) (mu4e--get-attach-num "Attachment to open" msg)))
(att (mu4e--get-attach msg attnum))
(index (plist-get att :index))) (index (plist-get att :index)))
(mu4e-proc-extract 'open (plist-get msg :docid) index))) (mu4e-proc-extract 'open (plist-get msg :docid) index)))
(defun mu4e--temp-action (docid index what &optional param) (defun mu4e--temp-action (docid index what &optional param)
"Open attachment INDEX for message with DOCID, and invoke "Open attachment INDEX for message with DOCID, and invoke
ACTION." ACTION."
(interactive) (interactive)
(mu4e-proc-extract 'temp docid index nil what param)) (mu4e-proc-extract 'temp docid index nil what param))
(defun mu4e-view-open-attachment-with (msg) (defun mu4e-view-open-attachment-with (msg attachnum &optional cmd)
"Open some attachment with some program (ask user which)." "Open MSG's attachment ATTACHNUM with CMD; if CMD is nil, ask
user for it."
(interactive) (interactive)
(let* ((att (mu4e--get-valid-attach "Attachment to open" msg)) (let* ((att (mu4e--get-attach msg attachnum))
(cmd (read-string "Shell command to open it with: ")) (cmd (or cmd (read-string "Shell command to open it with: ")))
(index (plist-get att :index))) (index (plist-get att :index)))
(mu4e--temp-action (plist-get msg :docid) index (mu4e--temp-action (plist-get msg :docid) index "open-with" cmd)))
"open-with" cmd)))
(defun mu4e-view-pipe-attachment (msg) (defun mu4e-view-pipe-attachment (msg attachnum &optional pipecmd)
"Open some attachment with some program (ask user which)." "Feed MSG's attachment ATTACHNUM throught pipe PIPECMD; if
PIPECMD is nil, ask user for it."
(interactive) (interactive)
(let* ((att (mu4e--get-valid-attach "Attachment to process" msg)) (let* ((att (mu4e--get-attach msg attachnum))
(cmd (read-string "Pipe: ")) (pipecmd (or pipecmd (read-string "Pipe: ")))
(index (plist-get att :index))) (index (plist-get att :index)))
(mu4e--temp-action (plist-get msg :docid) index (mu4e--temp-action (plist-get msg :docid) index "pipe" pipecmd)))
"pipe" cmd)))
(defun mu4e-view-open-attachment-emacs (msg) (defun mu4e-view-open-attachment-emacs (msg attachnum)
"Open some attachment in the current emacs instance." "Open MSG's attachment ATTACHNUM in the current emacs instance."
(interactive) (interactive)
(let* ((att (mu4e--get-valid-attach (let* ((att (mu4e--get-attach msg attachnum))
"Attachment to open in current emacs" msg))
(index (plist-get att :index))) (index (plist-get att :index)))
(mu4e--temp-action (plist-get msg :docid) index (mu4e--temp-action (plist-get msg :docid) index "emacs")))
"emacs")))
(defun mu4e-view-handle-attachment (&optional msg) (defun mu4e-view-handle-attachment (&optional msg)
"Ask user what to do with attachments, then do it." "Ask user what to do with attachments, then do it."
(interactive) (interactive)
(mu4e-offer-actions "Attachment action: " (let* ((msg (or msg (mu4e-message-at-point t)))
mu4e-view-attachments-actions (actionfunc (mu4e-choose-action
(or msg (mu4e-message-at-point t)))) "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 ;; handler-function to handle the response we get from the server when we
;; want to do something with one of the attachments. ;; want to do something with one of the attachments.