mirror of https://github.com/djcb/mu.git
* factor out marking code to mu4e-mark.el
This commit is contained in:
parent
9dd3224986
commit
2f2853c0dd
|
@ -27,6 +27,7 @@ dist_lisp_LISP= \
|
||||||
mu4e-compose.el \
|
mu4e-compose.el \
|
||||||
mu4e-hdrs.el \
|
mu4e-hdrs.el \
|
||||||
mu4e-main.el \
|
mu4e-main.el \
|
||||||
|
mu4e-mark.el \
|
||||||
mu4e-meta.el \
|
mu4e-meta.el \
|
||||||
mu4e-proc.el \
|
mu4e-proc.el \
|
||||||
mu4e-speedbar.el \
|
mu4e-speedbar.el \
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
(require 'mu4e-proc)
|
(require 'mu4e-proc)
|
||||||
(require 'mu4e-utils) ;; utility functions
|
(require 'mu4e-utils) ;; utility functions
|
||||||
(require 'mu4e-vars)
|
(require 'mu4e-vars)
|
||||||
|
(require 'mu4e-mark)
|
||||||
|
|
||||||
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(defconst mu4e-hdrs-fringe " " "*internal* The space on the left of
|
(defconst mu4e-hdrs-fringe " " "*internal* The space on the left of
|
||||||
|
@ -43,7 +44,7 @@ message headers to put marks.")
|
||||||
(let ((inhibit-read-only t))
|
(let ((inhibit-read-only t))
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
(with-current-buffer mu4e-hdrs-buffer
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(when mu4e-marks-map (clrhash mu4e-marks-map))))))
|
(mu4e--mark-clear)))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-search (expr &optional full-search)
|
(defun mu4e-hdrs-search (expr &optional full-search)
|
||||||
|
@ -90,8 +91,8 @@ headers."
|
||||||
(when point ;; is the message present in this list?
|
(when point ;; is the message present in this list?
|
||||||
|
|
||||||
;; if it's marked, unmark it now
|
;; if it's marked, unmark it now
|
||||||
(when (mu4e-hdrs-docid-is-marked docid)
|
(when (mu4e-mark-docid-marked-p docid)
|
||||||
(mu4e-hdrs-mark 'unmark))
|
(mu4e-mark-set 'unmark))
|
||||||
|
|
||||||
;; re-use the thread info from the old one; this is needed because
|
;; re-use the thread info from the old one; this is needed because
|
||||||
;; *update* message don't have thread info by themselves (unlike
|
;; *update* message don't have thread info by themselves (unlike
|
||||||
|
@ -232,10 +233,19 @@ after the end of the search results."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; hdrs-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; hdrs-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(defvar mu4e-hdrs-mode-map nil
|
(defvar mu4e-hdrs-mode-map nil
|
||||||
"Keymap for *mu4e-headers* buffers.")
|
"Keymap for *mu4e-headers* buffers.")
|
||||||
(unless mu4e-hdrs-mode-map
|
(unless mu4e-hdrs-mode-map
|
||||||
|
;; add some quick funcs so our key descriptions below are shorter
|
||||||
|
(defun mu4e--hdrs-mark-trash()(interactive)(mu4e-hdrs-mark-and-next 'trash))
|
||||||
|
(defun mu4e--hdrs-mark-delete()(interactive)(mu4e-hdrs-mark-and-next 'delete))
|
||||||
|
(defun mu4e--hdrs-mark-unmark()(interactive)(mu4e-hdrs-mark-and-next 'unmark))
|
||||||
|
(defun mu4e--hdrs-mark-read()(interactive)(mu4e-hdrs-mark-and-next 'read))
|
||||||
|
(defun mu4e--hdrs-mark-unread()(interactive)(mu4e-hdrs-mark-and-next 'unread))
|
||||||
|
|
||||||
(setq mu4e-hdrs-mode-map
|
(setq mu4e-hdrs-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
|
|
||||||
|
@ -260,24 +270,26 @@ after the end of the search results."
|
||||||
;; switching to view mode (if it's visible)
|
;; switching to view mode (if it's visible)
|
||||||
(define-key map "y" 'mu4e-select-other-view)
|
(define-key map "y" 'mu4e-select-other-view)
|
||||||
|
|
||||||
;; marking/unmarking/executing
|
;; marking/unmarking ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(define-key map (kbd "<backspace>") 'mu4e-mark-for-trash)
|
(define-key map (kbd "<backspace>") 'mu4e--hdrs-mark-trash)
|
||||||
(define-key map "d" 'mu4e-mark-for-trash)
|
(define-key map (kbd "d") 'mu4e--hdrs-mark-trash)
|
||||||
|
|
||||||
(define-key map (kbd "<delete>") 'mu4e-mark-for-delete)
|
(define-key map (kbd "<delete>") 'mu4e--hdrs-mark-delete)
|
||||||
(define-key map (kbd "<deletechar>") 'mu4e-mark-for-delete)
|
(define-key map (kbd "<deletechar>") 'mu4e--hdrs-mark-delete)
|
||||||
(define-key map "D" 'mu4e-mark-for-delete)
|
(define-key map (kbd "D") 'mu4e--hdrs-mark-delete)
|
||||||
|
|
||||||
(define-key map "o" 'mu4e-mark-as-unread)
|
(define-key map (kbd "o") 'mu4e--hdrs-mark-unread)
|
||||||
(define-key map "r" 'mu4e-mark-as-read)
|
(define-key map (kbd "r") 'mu4e--hdrs-mark-read)
|
||||||
|
(define-key map (kbd "u") 'mu4e--hdrs-mark-unmark)
|
||||||
|
|
||||||
|
(define-key map "m" 'mu4e-hdrs-mark-for-move-and-next)
|
||||||
|
|
||||||
|
(define-key map "U" 'mu4e-mark-unmark-all)
|
||||||
|
(define-key map "x" 'mu4e-mark-execute-all)
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|
||||||
(define-key map "j" 'mu4e-jump-to-maildir)
|
(define-key map "j" 'mu4e-jump-to-maildir)
|
||||||
(define-key map "m" 'mu4e-mark-for-move)
|
|
||||||
|
|
||||||
(define-key map "u" 'mu4e-unmark)
|
|
||||||
(define-key map "U" 'mu4e-unmark-all)
|
|
||||||
(define-key map "x" 'mu4e-execute-marks)
|
|
||||||
|
|
||||||
(define-key map "a" 'mu4e-hdrs-action)
|
(define-key map "a" 'mu4e-hdrs-action)
|
||||||
|
|
||||||
;; message composition
|
;; message composition
|
||||||
|
@ -302,19 +314,22 @@ after the end of the search results."
|
||||||
(define-key menumap [display-help] '("Help" . mu4e-display-manual))
|
(define-key menumap [display-help] '("Help" . mu4e-display-manual))
|
||||||
|
|
||||||
(define-key menumap [sepa0] '("--"))
|
(define-key menumap [sepa0] '("--"))
|
||||||
|
|
||||||
|
(define-key menumap [execute-marks] '("Execute marks"
|
||||||
|
. mu4e-mark-execute-all))
|
||||||
|
(define-key menumap [unmark-all] '("Unmark all" . mu4e-mark-unmark-all))
|
||||||
|
(define-key menumap [unmark] '("Unmark" . mu4e--hdrs-mark-unmark))
|
||||||
|
|
||||||
(define-key menumap [execute-marks] '("Execute marks" . mu4e-execute-marks))
|
(define-key menumap [mark-as-read] '("Mark as read" . mu4e--hdrs-mark-read))
|
||||||
(define-key menumap [unmark-all] '("Unmark all" . mu4e-unmark-all))
|
|
||||||
(define-key menumap [unmark] '("Unmark" . mu4e-unmark))
|
|
||||||
|
|
||||||
(define-key menumap [mark-as-read] '("Mark as read" . mu4e-mark-as-read))
|
|
||||||
(define-key menumap [mark-as-unread]
|
(define-key menumap [mark-as-unread]
|
||||||
'("Mark as unread" . mu4e-mark-as-unread))
|
'("Mark as unread" . mu4e--hdrs-mark-unread))
|
||||||
|
|
||||||
(define-key menumap [mark-delete]
|
(define-key menumap [mark-delete]
|
||||||
'("Mark for deletion" . mu4e-mark-for-delete))
|
'("Mark for deletion" . mu4e--hdrs-mark-delete))
|
||||||
(define-key menumap [mark-trash] '("Mark for trash" . mu4e-mark-for-trash))
|
(define-key menumap [mark-trash]
|
||||||
(define-key menumap [mark-move] '("Mark for move" . mu4e-mark-for-move))
|
'("Mark for trash" . mu4e--hdrs-mark-trash))
|
||||||
|
(define-key menumap [mark-move]
|
||||||
|
'("Mark for move" . mu4e-hdrs-mark-for-move-and-next))
|
||||||
(define-key menumap [sepa1] '("--"))
|
(define-key menumap [sepa1] '("--"))
|
||||||
|
|
||||||
(define-key menumap [compose-new] '("Compose new" . mu4e-compose-new))
|
(define-key menumap [compose-new] '("Compose new" . mu4e-compose-new))
|
||||||
|
@ -345,19 +360,17 @@ after the end of the search results."
|
||||||
|
|
||||||
(make-local-variable 'mu4e-last-expr)
|
(make-local-variable 'mu4e-last-expr)
|
||||||
(make-local-variable 'mu4e-hdrs-proc)
|
(make-local-variable 'mu4e-hdrs-proc)
|
||||||
(make-local-variable 'mu4e-marks-map)
|
|
||||||
(make-local-variable 'mu4e--highlighted-docid)
|
(make-local-variable 'mu4e--highlighted-docid)
|
||||||
|
|
||||||
(make-local-variable 'global-mode-string)
|
(make-local-variable 'global-mode-string)
|
||||||
(make-local-variable 'hl-line-face)
|
(make-local-variable 'hl-line-face)
|
||||||
|
|
||||||
(setq
|
(setq
|
||||||
mu4e-marks-map (make-hash-table :size 16 :rehash-size 2)
|
|
||||||
truncate-lines t
|
truncate-lines t
|
||||||
buffer-undo-list t ;; don't record undo information
|
buffer-undo-list t ;; don't record undo information
|
||||||
overwrite-mode 'overwrite-mode-binary
|
overwrite-mode 'overwrite-mode-binary
|
||||||
hl-line-face 'mu4e-header-highlight-face)
|
hl-line-face 'mu4e-header-highlight-face)
|
||||||
|
(mu4e--mark-initialize) ;; initialize the marking subsystem
|
||||||
(hl-line-mode 1)
|
(hl-line-mode 1)
|
||||||
|
|
||||||
(setq header-line-format
|
(setq header-line-format
|
||||||
|
@ -502,195 +515,6 @@ at (point-max) otherwise. If MSG is not nil, add it as the text-property `msg'."
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; marks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
(defvar mu4e-marks-map nil
|
|
||||||
"Map (hash) of docid->markinfo; when a message is marked, the
|
|
||||||
information is added here.
|
|
||||||
|
|
||||||
markinfo is a list consisting of the following:
|
|
||||||
\(marker mark target)
|
|
||||||
where
|
|
||||||
MARKER is an emacs-textmarker pointing to the beginning of the header line
|
|
||||||
MARK is the type of mark (move, trash, delete)
|
|
||||||
TARGET (optional) is the target directory (for 'move')")
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-mark-message (mark &optional target)
|
|
||||||
"Mark (or unmark) message at point. MARK specifies the
|
|
||||||
mark-type. For `move'-marks there is also the TARGET argument,
|
|
||||||
which specifies to which maildir the message is to be moved.
|
|
||||||
|
|
||||||
The following marks are available, and the corresponding props:
|
|
||||||
|
|
||||||
MARK TARGET description
|
|
||||||
----------------------------------------------------------
|
|
||||||
`move' y move the message to some folder
|
|
||||||
`trash' n move the message to `mu4e-trash-folder'
|
|
||||||
`delete' n remove the message
|
|
||||||
`read' n mark the message as read
|
|
||||||
`unread' n mark the message as unread
|
|
||||||
`unmark' n unmark this message"
|
|
||||||
(let* ((docid (mu4e--docid-at-point))
|
|
||||||
(markkar
|
|
||||||
(case mark ;; the visual mark
|
|
||||||
('move "m")
|
|
||||||
('trash "d")
|
|
||||||
('delete "D")
|
|
||||||
('unread "U")
|
|
||||||
('read "R")
|
|
||||||
('unmark " ")
|
|
||||||
(t (error "Invalid mark %S" mark)))))
|
|
||||||
(unless docid (error "No message on this line"))
|
|
||||||
(save-excursion
|
|
||||||
(when (mu4e--mark-header docid markkar))
|
|
||||||
;; update the hash -- remove everything current, and if add the new stuff,
|
|
||||||
;; unless we're unmarking
|
|
||||||
(remhash docid mu4e-marks-map)
|
|
||||||
;; remove possible overlays
|
|
||||||
(remove-overlays (line-beginning-position) (line-end-position))
|
|
||||||
|
|
||||||
;; now, let's set a mark (unless we were unmarking)
|
|
||||||
(unless (eql mark 'unmark)
|
|
||||||
(puthash docid (list (point-marker) mark target) mu4e-marks-map)
|
|
||||||
;; when we have a target (ie., when moving), show the target folder in
|
|
||||||
;; an overlay
|
|
||||||
(when target
|
|
||||||
(let* ((targetstr (propertize (concat "-> " target " ")
|
|
||||||
'face 'mu4e-system-face))
|
|
||||||
;; mu4e-goto-docid docid t will take us just after the docid cookie
|
|
||||||
;; and then we skip the mu4e-hdrs-fringe
|
|
||||||
(start (+ (length mu4e-hdrs-fringe)
|
|
||||||
(mu4e--goto-docid docid t)))
|
|
||||||
(overlay (make-overlay start (+ start (length targetstr)))))
|
|
||||||
(overlay-put overlay 'display targetstr)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-mark (mark &optional target)
|
|
||||||
"Mark the header at point, or, if
|
|
||||||
region is active, mark all headers in the region. Als see
|
|
||||||
`mu4e-hdrs-mark-message'."
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(if (use-region-p)
|
|
||||||
;; mark all messages in the region.
|
|
||||||
(save-excursion
|
|
||||||
(let ((b (region-beginning)) (e (region-end)))
|
|
||||||
(goto-char b)
|
|
||||||
(while (<= (line-beginning-position) e)
|
|
||||||
(mu4e-hdrs-mark-message mark target)
|
|
||||||
(forward-line 1))))
|
|
||||||
;; just a single message
|
|
||||||
(mu4e-hdrs-mark-message mark target))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-marks-execute ()
|
|
||||||
"Execute the actions for all marked messages in this
|
|
||||||
buffer. After the actions have been executed succesfully, the
|
|
||||||
affected messages are *hidden* from the current header list. Since
|
|
||||||
the headers are the result of a search, we cannot be certain that
|
|
||||||
the messages no longer matches the current one - to get that
|
|
||||||
certainty, we need to rerun the search, but we don't want to do
|
|
||||||
that automatically, as it may be too slow and/or break the users
|
|
||||||
flow. Therefore, we hide the message, which in practice seems to
|
|
||||||
work well."
|
|
||||||
(if (= 0 (hash-table-count mu4e-marks-map))
|
|
||||||
(message "Nothing is marked")
|
|
||||||
(maphash
|
|
||||||
(lambda (docid val)
|
|
||||||
(let ((marker (nth 0 val)) (mark (nth 1 val)) (target (nth 2 val)))
|
|
||||||
(case mark
|
|
||||||
(move (mu4e-proc-move docid target))
|
|
||||||
(read (mu4e-proc-move docid nil "+S-u-N"))
|
|
||||||
(unread (mu4e-proc-move docid nil "-S+u"))
|
|
||||||
(trash
|
|
||||||
(unless mu4e-trash-folder
|
|
||||||
(error "`mu4e-trash-folder' not set"))
|
|
||||||
(mu4e-proc-move docid mu4e-trash-folder "+T"))
|
|
||||||
(delete (mu4e-proc-remove docid)))))
|
|
||||||
mu4e-marks-map)
|
|
||||||
(mu4e-hdrs-unmark-all)))
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-unmark-all ()
|
|
||||||
"Unmark all marked messages."
|
|
||||||
(unless (/= 0 (hash-table-count mu4e-marks-map))
|
|
||||||
(error "Nothing is marked"))
|
|
||||||
(maphash
|
|
||||||
(lambda (docid val)
|
|
||||||
(save-excursion
|
|
||||||
(goto-char (marker-position (nth 0 val)))
|
|
||||||
(mu4e-hdrs-mark 'unmark)))
|
|
||||||
mu4e-marks-map)
|
|
||||||
;; in any case, clear the marks map
|
|
||||||
(clrhash mu4e-marks-map))
|
|
||||||
|
|
||||||
(defun mu4e-view-message ()
|
|
||||||
"View message at point. If there's an existing window for the
|
|
||||||
view, re-use that one. If not, create a new one, depending on the
|
|
||||||
value of `mu4e-split-view': if it's a symbol `horizontal' or
|
|
||||||
`vertical', split the window accordingly; if it is nil, replace the
|
|
||||||
current window. "
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(let* ((docid (mu4e--docid-at-point))
|
|
||||||
(viewwin (and mu4e-view-buffer
|
|
||||||
(get-buffer-window mu4e-view-buffer))))
|
|
||||||
(unless docid (error "No message at point."))
|
|
||||||
;; is there a window already for the message view?
|
|
||||||
(unless (window-live-p viewwin)
|
|
||||||
;; no view window yet; create one, based on the split settings etc.
|
|
||||||
;; emacs' use of the terms "horizontally" and "vertically"
|
|
||||||
;; are... suprising. There's a clearer `split-window' in emacs24, but
|
|
||||||
;; it's not compatible with emacs 23
|
|
||||||
(setq viewwin
|
|
||||||
(cond ;; is there are live window for the message view?
|
|
||||||
((eq mu4e-split-view 'horizontal) ;; split horizontally
|
|
||||||
(split-window-vertically mu4e-headers-visible-lines))
|
|
||||||
((eq mu4e-split-view 'vertical) ;; split vertically
|
|
||||||
(split-window-horizontally mu4e-headers-visible-columns))
|
|
||||||
(t ;; no splitting; just use the currently selected one
|
|
||||||
(selected-window)))))
|
|
||||||
;; okay, now we should have a window for the message view
|
|
||||||
;; we select it, and show the messages there.
|
|
||||||
(select-window viewwin)
|
|
||||||
(switch-to-buffer (get-buffer-create mu4e-view-buffer-name))
|
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
(erase-buffer)
|
|
||||||
(insert (propertize "Waiting for message..."
|
|
||||||
'face 'mu4e-system-face 'intangible t)))
|
|
||||||
(mu4e-proc-view docid))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-hdrs-docid-is-marked (docid)
|
|
||||||
"Is the given docid marked?"
|
|
||||||
(when (gethash docid mu4e-marks-map) t))
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(defun mu4e-handle-marks ()
|
|
||||||
"If there are any marks in the current buffer, handle those
|
|
||||||
according to the value of `mu4e-headers-leave-behavior'. This
|
|
||||||
function is to be called before any further action (like searching,
|
|
||||||
quiting the buffer) is taken; returning t means 'take the following
|
|
||||||
action', return nil means 'don't do anything'"
|
|
||||||
(let ((marknum
|
|
||||||
(if mu4e-marks-map (hash-table-count mu4e-marks-map) 0))
|
|
||||||
(what mu4e-headers-leave-behavior))
|
|
||||||
(unless (or (= marknum 0) (eq what 'ignore) (eq what 'apply))
|
|
||||||
;; if `mu4e-headers-leave-behavior' is not apply or ignore, ask the user
|
|
||||||
(setq what
|
|
||||||
(let ((kar (mu4e-read-option
|
|
||||||
"There are existing marks; should we: "
|
|
||||||
'(("apply marks") ("ignore marks?")))))
|
|
||||||
(cond
|
|
||||||
((= kar ?a) 'apply)
|
|
||||||
((= kar ?i) 'ignore)
|
|
||||||
(t nil))))) ;; cancel
|
|
||||||
;; we determined what to do... now do it
|
|
||||||
(cond
|
|
||||||
((= 0 marknum) t) ;; no marks, just go ahead
|
|
||||||
((eq what 'ignore) t) ;; ignore the marks, go ahead
|
|
||||||
((eq what 'apply)
|
|
||||||
(progn (mu4e-execute-marks t) t) t) ;; execute marks, go ahead
|
|
||||||
(t nil)))) ;; otherwise, don't do anything
|
|
||||||
|
|
||||||
|
|
||||||
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -700,7 +524,7 @@ results to `mu4e-search-results-limit', otherwise show all. In
|
||||||
other words, use the C-u prefix to get /all/ results, otherwise get
|
other words, use the C-u prefix to get /all/ results, otherwise get
|
||||||
up to `mu4e-search-results-limit' much quicker."
|
up to `mu4e-search-results-limit' much quicker."
|
||||||
(interactive "s[mu] search for: ")
|
(interactive "s[mu] search for: ")
|
||||||
(when (mu4e-handle-marks)
|
(when (mu4e-mark-handle-when-leaving)
|
||||||
(mu4e-hdrs-search expr current-prefix-arg)))
|
(mu4e-hdrs-search expr current-prefix-arg)))
|
||||||
|
|
||||||
(defun mu4e-search-bookmark ()
|
(defun mu4e-search-bookmark ()
|
||||||
|
@ -708,7 +532,7 @@ up to `mu4e-search-results-limit' much quicker."
|
||||||
otherwise, limit to up to `mu4e-search-results-limit'."
|
otherwise, limit to up to `mu4e-search-results-limit'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((query (mu4e-ask-bookmark "Bookmark: ")))
|
(let ((query (mu4e-ask-bookmark "Bookmark: ")))
|
||||||
(when (and query (mu4e-handle-marks))
|
(when (and query (mu4e-mark-handle-when-leaving))
|
||||||
(mu4e-hdrs-search query current-prefix-arg))))
|
(mu4e-hdrs-search query current-prefix-arg))))
|
||||||
|
|
||||||
(defun mu4e-search-bookmark-edit-first (expr)
|
(defun mu4e-search-bookmark-edit-first (expr)
|
||||||
|
@ -718,13 +542,51 @@ otherwise, limit to up to `mu4e-search-results-limit'."
|
||||||
(interactive
|
(interactive
|
||||||
(list (read-string "[mu] search for: "
|
(list (read-string "[mu] search for: "
|
||||||
(concat (or (mu4e-ask-bookmark "Edit bookmark: ") "") " "))))
|
(concat (or (mu4e-ask-bookmark "Edit bookmark: ") "") " "))))
|
||||||
(when (and expr (mu4e-handle-marks))
|
(when (and expr (mu4e-mark-handle-when-leaving))
|
||||||
(mu4e-hdrs-search expr current-prefix-arg)))
|
(mu4e-hdrs-search expr current-prefix-arg)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-view-message ()
|
||||||
|
"View message at point. If there's an existing window for the
|
||||||
|
view, re-use that one. If not, create a new one, depending on the
|
||||||
|
value of `mu4e-split-view': if it's a symbol `horizontal' or
|
||||||
|
`vertical', split the window accordingly; if it is nil, replace the
|
||||||
|
current window. "
|
||||||
|
(interactive)
|
||||||
|
(unless (eq major-mode 'mu4e-hdrs-mode)
|
||||||
|
(error "Must be in mu4e-hdrs-mode (%S)" major-mode))
|
||||||
|
(let* ((docid (mu4e--docid-at-point))
|
||||||
|
(viewwin (and mu4e-view-buffer
|
||||||
|
(get-buffer-window mu4e-view-buffer))))
|
||||||
|
(unless docid (error "No message at point."))
|
||||||
|
;; is there a window already for the message view?
|
||||||
|
(unless (window-live-p viewwin)
|
||||||
|
;; no view window yet; create one, based on the split settings etc.
|
||||||
|
;; emacs' use of the terms "horizontally" and "vertically"
|
||||||
|
;; are... suprising. There's a clearer `split-window' in emacs24, but
|
||||||
|
;; it's not compatible with emacs 23
|
||||||
|
(setq viewwin
|
||||||
|
(cond ;; is there are live window for the message view?
|
||||||
|
((eq mu4e-split-view 'horizontal) ;; split horizontally
|
||||||
|
(split-window-vertically mu4e-headers-visible-lines))
|
||||||
|
((eq mu4e-split-view 'vertical) ;; split vertically
|
||||||
|
(split-window-horizontally mu4e-headers-visible-columns))
|
||||||
|
(t ;; no splitting; just use the currently selected one
|
||||||
|
(selected-window)))))
|
||||||
|
;; okay, now we should have a window for the message view
|
||||||
|
;; we select it, and show the messages there.
|
||||||
|
(select-window viewwin)
|
||||||
|
(switch-to-buffer (get-buffer-create mu4e-view-buffer-name))
|
||||||
|
(let ((inhibit-read-only t))
|
||||||
|
(erase-buffer)
|
||||||
|
(insert (propertize "Waiting for message..."
|
||||||
|
'face 'mu4e-system-face 'intangible t)))
|
||||||
|
(mu4e-proc-view docid)))
|
||||||
|
|
||||||
(defun mu4e-hdrs-kill-buffer-and-window ()
|
(defun mu4e-hdrs-kill-buffer-and-window ()
|
||||||
"Quit the message view and return to the main view."
|
"Quit the message view and return to the main view."
|
||||||
(interactive)
|
(interactive)
|
||||||
(when (mu4e-handle-marks)
|
(when (mu4e-mark-handle-when-leaving)
|
||||||
(mu4e-kill-buffer-and-window mu4e-hdrs-buffer)
|
(mu4e-kill-buffer-and-window mu4e-hdrs-buffer)
|
||||||
(mu4e-main-view)))
|
(mu4e-main-view)))
|
||||||
|
|
||||||
|
@ -732,7 +594,7 @@ otherwise, limit to up to `mu4e-search-results-limit'."
|
||||||
"Rerun the search for the last search expression; if none exists,
|
"Rerun the search for the last search expression; if none exists,
|
||||||
do a new search."
|
do a new search."
|
||||||
(interactive)
|
(interactive)
|
||||||
(when (mu4e-handle-marks)
|
(when (mu4e-mark-handle-when-leaving)
|
||||||
(if mu4e-last-expr
|
(if mu4e-last-expr
|
||||||
(mu4e-hdrs-search mu4e-last-expr)
|
(mu4e-hdrs-search mu4e-last-expr)
|
||||||
(call-interactively 'mu4e-search))))
|
(call-interactively 'mu4e-search))))
|
||||||
|
@ -741,23 +603,22 @@ do a new search."
|
||||||
"Move point LINES lines forward (if LINES is positive) or
|
"Move point LINES lines forward (if LINES is positive) or
|
||||||
backward (if LINES is negative). If this succeeds, return the new
|
backward (if LINES is negative). If this succeeds, return the new
|
||||||
docid. Otherwise, return nil."
|
docid. Otherwise, return nil."
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
(unless (eq major-mode 'mu4e-hdrs-mode)
|
||||||
(unless (buffer-live-p mu4e-hdrs-buffer)
|
(error "Must be in mu4e-hdrs-mode (%S)" major-mode))
|
||||||
(error "Headers buffer is not alive %S" (current-buffer)))
|
(let ((succeeded (= 0 (forward-line lines)))
|
||||||
(let ((succeeded (= 0 (forward-line lines)))
|
(docid (mu4e--docid-at-point)))
|
||||||
(docid (mu4e--docid-at-point)))
|
;; trick to move point, even if this function is called when this window
|
||||||
;; trick to move point, even if this function is called when this window
|
;; is not visible
|
||||||
;; is not visible
|
(when docid
|
||||||
(when docid
|
(set-window-point (get-buffer-window mu4e-hdrs-buffer) (point))
|
||||||
(set-window-point (get-buffer-window mu4e-hdrs-buffer) (point))
|
;; attempt to highlight the new line, display the message
|
||||||
;; attempt to highlight the new line, display the message
|
(mu4e-hdrs-highlight docid)
|
||||||
(mu4e-hdrs-highlight docid)
|
;; if there already is a visible message view, show the message
|
||||||
;; if there already is a visible message view, show the message
|
(when (and (buffer-live-p mu4e-view-buffer)
|
||||||
(when (and (buffer-live-p mu4e-view-buffer)
|
(window-live-p (get-buffer-window mu4e-view-buffer)))
|
||||||
(window-live-p (get-buffer-window mu4e-view-buffer)))
|
(mu4e-view-message)))
|
||||||
(mu4e-view-message)))
|
;; return the docid only if the move succeeded
|
||||||
;; return the docid only if the move succeeded
|
(when succeeded docid)))
|
||||||
(when succeeded docid))))
|
|
||||||
|
|
||||||
(defun mu4e-next-header ()
|
(defun mu4e-next-header ()
|
||||||
"Move point to the next message header. If this succeeds, return
|
"Move point to the next message header. If this succeeds, return
|
||||||
|
@ -778,85 +639,10 @@ maildir). With C-u prefix, show /all/ results, otherwise, limit to
|
||||||
up to `mu4e-search-results-limit'."
|
up to `mu4e-search-results-limit'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((fld (mu4e-ask-maildir "Jump to maildir: ")))
|
(let ((fld (mu4e-ask-maildir "Jump to maildir: ")))
|
||||||
(when (and fld (mu4e-handle-marks))
|
(when (and fld (mu4e-mark-handle-when-leaving))
|
||||||
(mu4e-hdrs-search (concat "\"maildir:" fld "\"")
|
(mu4e-hdrs-search (concat "\"maildir:" fld "\"")
|
||||||
current-prefix-arg))))
|
current-prefix-arg))))
|
||||||
|
|
||||||
(defun mu4e-mark-for-move (&optional target)
|
|
||||||
"Mark message at point for moving to maildir TARGET. If target is
|
|
||||||
not provided, function asks for it."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(unless (mu4e--docid-at-point)
|
|
||||||
(error "No message at point."))
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(let* ((target (or target (mu4e-ask-maildir "Move message to: ")))
|
|
||||||
(target (if (string= (substring target 0 1) "/")
|
|
||||||
target
|
|
||||||
(concat "/" target)))
|
|
||||||
(fulltarget (concat mu4e-maildir target)))
|
|
||||||
(when (or (file-directory-p fulltarget)
|
|
||||||
(and (yes-or-no-p
|
|
||||||
(format "%s does not exist. Create now?" fulltarget))
|
|
||||||
(mu4e-proc-mkdir fulltarget)))
|
|
||||||
(mu4e-hdrs-mark 'move target)
|
|
||||||
(mu4e-next-header))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-mark (mark)
|
|
||||||
"Mark message for MARK (trash, delete, read, unread, unmark)."
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(mu4e-hdrs-mark mark)
|
|
||||||
(mu4e-next-header)))
|
|
||||||
|
|
||||||
(defun mu4e-mark-for-trash ()
|
|
||||||
"Mark message at point for moving to the trash
|
|
||||||
folder (`mu4e-trash-folder')."
|
|
||||||
(interactive)
|
|
||||||
(mu4e-mark 'trash))
|
|
||||||
|
|
||||||
(defun mu4e-mark-for-delete ()
|
|
||||||
"Mark message at point for direct deletion."
|
|
||||||
(interactive)
|
|
||||||
(mu4e-mark 'delete))
|
|
||||||
|
|
||||||
(defun mu4e-mark-as-read ()
|
|
||||||
"Mark message at point as unread."
|
|
||||||
(interactive)
|
|
||||||
(mu4e-mark 'read))
|
|
||||||
|
|
||||||
(defun mu4e-mark-as-unread ()
|
|
||||||
"Mark message at point as read."
|
|
||||||
(interactive)
|
|
||||||
(mu4e-mark 'unread))
|
|
||||||
|
|
||||||
(defun mu4e-unmark ()
|
|
||||||
"Unmark message at point."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(mu4e-mark 'unmark)))
|
|
||||||
|
|
||||||
(defun mu4e-unmark-all ()
|
|
||||||
"Unmark all messages."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(if (= 0 (hash-table-count mu4e-marks-map))
|
|
||||||
(message "Nothing is marked")
|
|
||||||
(mu4e-hdrs-unmark-all))))
|
|
||||||
|
|
||||||
(defun mu4e-execute-marks (&optional no-confirmation)
|
|
||||||
"Execute the actions for the marked messages. If optional
|
|
||||||
parameter NO-CONFIRMATION is is t, don't ask for confirmation."
|
|
||||||
(interactive)
|
|
||||||
(with-current-buffer mu4e-hdrs-buffer
|
|
||||||
(if (= 0 (hash-table-count mu4e-marks-map))
|
|
||||||
(message "Nothing is marked")
|
|
||||||
(when (or no-confirmation
|
|
||||||
(y-or-n-p (format "Sure you want to execute marks on %d message(s)?"
|
|
||||||
(hash-table-count mu4e-marks-map))))
|
|
||||||
(mu4e-hdrs-marks-execute)
|
|
||||||
(message nil)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-compose (compose-type)
|
(defun mu4e-compose (compose-type)
|
||||||
"Start composing a message of COMPOSE-TYPE, where COMPOSE-TYPE is
|
"Start composing a message of COMPOSE-TYPE, where COMPOSE-TYPE is
|
||||||
|
@ -918,6 +704,21 @@ actions are specified in `mu4e-headers-actions'."
|
||||||
(actionfunc (mu4e-choose-action "Action: " mu4e-headers-actions)))
|
(actionfunc (mu4e-choose-action "Action: " mu4e-headers-actions)))
|
||||||
(funcall actionfunc msg)))
|
(funcall actionfunc msg)))
|
||||||
|
|
||||||
|
(defun mu4e-hdrs-mark-and-next (mark)
|
||||||
|
"Set mark MARK on the message at point or on all messages in the
|
||||||
|
region if there is a region, then move to the next message."
|
||||||
|
(interactive)
|
||||||
|
(mu4e-mark-set mark)
|
||||||
|
(mu4e-next-header))
|
||||||
|
|
||||||
|
(defun mu4e-hdrs-mark-for-move-and-next ()
|
||||||
|
"Set mark MARK on the message at point or on all messages in the
|
||||||
|
region if there is a region, then move to the next message."
|
||||||
|
(interactive)
|
||||||
|
(mu4e-mark-for-move-set)
|
||||||
|
(mu4e-next-header))
|
||||||
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(provide 'mu4e-hdrs)
|
(provide 'mu4e-hdrs)
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
;;; mu4e-mark.el -- part of mu4e, the mu mail user agent
|
||||||
|
;;
|
||||||
|
;; Copyright (C) 2011-2012 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
;; (at your option) any later version.
|
||||||
|
|
||||||
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; In this file are function related to marking messages; they assume we are
|
||||||
|
;; currently in the headers buffer.
|
||||||
|
|
||||||
|
;; Code:
|
||||||
|
(require 'mu4e-proc)
|
||||||
|
(require 'mu4e-utils)
|
||||||
|
|
||||||
|
;;; marks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
(defvar mu4e--mark-map nil
|
||||||
|
"Map (hash) of docid->markinfo; when a message is marked, the
|
||||||
|
information is added here.
|
||||||
|
|
||||||
|
markinfo is a list consisting of the following:
|
||||||
|
\(mark target)
|
||||||
|
where
|
||||||
|
MARK is the type of mark (move, trash, delete)
|
||||||
|
TARGET (optional) is the target directory (for 'move')")
|
||||||
|
|
||||||
|
;; the mark-map is specific for the current header buffer
|
||||||
|
;; currently, there can't be more than one, but we never know what will
|
||||||
|
;; happen in the future
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e--mark-initialize ()
|
||||||
|
"Initialize the marks subsystem."
|
||||||
|
(make-local-variable 'mu4e--mark-map)
|
||||||
|
(setq mu4e--mark-map (make-hash-table :size 16 :rehash-size 2)))
|
||||||
|
|
||||||
|
(defun mu4e--mark-clear ()
|
||||||
|
"Clear the marks subsystem."
|
||||||
|
(clrhash mu4e--mark-map))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-at-point (mark &optional target)
|
||||||
|
"Mark (or unmark) message at point. MARK specifies the
|
||||||
|
mark-type. For `move'-marks there is also the TARGET argument,
|
||||||
|
which specifies to which maildir the message is to be moved. The
|
||||||
|
functipn works in both headers buffers and message buffers.
|
||||||
|
|
||||||
|
The following marks are available, and the corresponding props:
|
||||||
|
|
||||||
|
MARK TARGET description
|
||||||
|
----------------------------------------------------------
|
||||||
|
`move' y move the message to some folder
|
||||||
|
`trash' n move the message to `mu4e-trash-folder'
|
||||||
|
`delete' n remove the message
|
||||||
|
`read' n mark the message as read
|
||||||
|
`unread' n mark the message as unread
|
||||||
|
`unmark' n unmark this message"
|
||||||
|
(interactive)
|
||||||
|
(let* ((docid (mu4e--docid-at-point))
|
||||||
|
(markkar
|
||||||
|
(case mark ;; the visual mark
|
||||||
|
('move "m")
|
||||||
|
('trash "d")
|
||||||
|
('delete "D")
|
||||||
|
('unread "U")
|
||||||
|
('read "R")
|
||||||
|
('unmark " ")
|
||||||
|
(t (error "Invalid mark %S" mark)))))
|
||||||
|
(unless docid (error "No message on this line"))
|
||||||
|
(save-excursion
|
||||||
|
(when (mu4e--mark-header docid markkar))
|
||||||
|
;; update the hash -- remove everything current, and if add the new stuff,
|
||||||
|
;; unless we're unmarking
|
||||||
|
(remhash docid mu4e--mark-map)
|
||||||
|
;; remove possible overlays
|
||||||
|
(remove-overlays (line-beginning-position) (line-end-position))
|
||||||
|
|
||||||
|
;; now, let's set a mark (unless we were unmarking)
|
||||||
|
(unless (eql mark 'unmark)
|
||||||
|
(puthash docid (list mark target) mu4e--mark-map)
|
||||||
|
;; when we have a target (ie., when moving), show the target folder in
|
||||||
|
;; an overlay
|
||||||
|
(when target
|
||||||
|
(let* ((targetstr (propertize (concat "-> " target " ")
|
||||||
|
'face 'mu4e-system-face))
|
||||||
|
;; mu4e-goto-docid docid t will take us just after the docid cookie
|
||||||
|
;; and then we skip the mu4e-hdrs-fringe
|
||||||
|
(start (+ (length mu4e-hdrs-fringe)
|
||||||
|
(mu4e--goto-docid docid t)))
|
||||||
|
(overlay (make-overlay start (+ start (length targetstr)))))
|
||||||
|
(overlay-put overlay 'display targetstr)
|
||||||
|
docid))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-set (mark &optional target)
|
||||||
|
"Mark the header at point, or, if region is active, mark all
|
||||||
|
headers in the region."
|
||||||
|
(interactive)
|
||||||
|
(if (use-region-p)
|
||||||
|
;; mark all messages in the region.
|
||||||
|
(save-excursion
|
||||||
|
(let ((b (region-beginning)) (e (region-end)))
|
||||||
|
(goto-char b)
|
||||||
|
(while (<= (line-beginning-position) e)
|
||||||
|
(mu4e-mark-at-point mark target)
|
||||||
|
(forward-line 1))))
|
||||||
|
;; just a single message
|
||||||
|
(mu4e-mark-at-point mark target)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-for-move-set (&optional target)
|
||||||
|
"Mark message at point or, if region is active, all messages in
|
||||||
|
the region, for moving to maildir TARGET. If target is not
|
||||||
|
provided, function asks for it."
|
||||||
|
(interactive)
|
||||||
|
(unless (mu4e--docid-at-point)
|
||||||
|
(error "No message at point."))
|
||||||
|
(let* ((target (or target (mu4e-ask-maildir "Move message to: ")))
|
||||||
|
(target (if (string= (substring target 0 1) "/")
|
||||||
|
target
|
||||||
|
(concat "/" target)))
|
||||||
|
(fulltarget (concat mu4e-maildir target)))
|
||||||
|
(when (or (file-directory-p fulltarget)
|
||||||
|
(and (yes-or-no-p
|
||||||
|
(format "%s does not exist. Create now?" fulltarget))
|
||||||
|
(mu4e-proc-mkdir fulltarget)))
|
||||||
|
(mu4e-mark-set 'move target))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-execute-all (&optional no-confirmation)
|
||||||
|
"Execute the actions for all marked messages in this
|
||||||
|
buffer. After the actions have been executed succesfully, the
|
||||||
|
affected messages are *hidden* from the current header list. Since
|
||||||
|
the headers are the result of a search, we cannot be certain that
|
||||||
|
the messages no longer matches the current one - to get that
|
||||||
|
certainty, we need to rerun the search, but we don't want to do
|
||||||
|
that automatically, as it may be too slow and/or break the users
|
||||||
|
flow. Therefore, we hide the message, which in practice seems to
|
||||||
|
work well.
|
||||||
|
|
||||||
|
If NO-CONFIRMATION is non-nil, do not ask the user for
|
||||||
|
confirmation."
|
||||||
|
(interactive)
|
||||||
|
(if (zerop (hash-table-count mu4e--mark-map))
|
||||||
|
(message "Nothing is marked")
|
||||||
|
(when (or no-confirmation
|
||||||
|
(y-or-n-p (format "Sure you want to execute marks on %d message(s)?"
|
||||||
|
(hash-table-count mu4e--mark-map))))
|
||||||
|
(maphash
|
||||||
|
(lambda (docid val)
|
||||||
|
(let ((mark (nth 0 val)) (target (nth 1 val)))
|
||||||
|
(case mark
|
||||||
|
(move (mu4e-proc-move docid target))
|
||||||
|
(read (mu4e-proc-move docid nil "+S-u-N"))
|
||||||
|
(unread (mu4e-proc-move docid nil "-S+u"))
|
||||||
|
(trash
|
||||||
|
(unless mu4e-trash-folder
|
||||||
|
(error "`mu4e-trash-folder' not set"))
|
||||||
|
(mu4e-proc-move docid mu4e-trash-folder "+T"))
|
||||||
|
(delete (mu4e-proc-remove docid)))))
|
||||||
|
mu4e--mark-map)
|
||||||
|
(mu4e-mark-unmark-all)
|
||||||
|
(message nil))))
|
||||||
|
|
||||||
|
(defun mu4e-mark-unmark-all ()
|
||||||
|
"Unmark all marked messages."
|
||||||
|
(interactive)
|
||||||
|
(when (zerop (hash-table-count mu4e--mark-map))
|
||||||
|
(error "Nothing is marked"))
|
||||||
|
(maphash
|
||||||
|
(lambda (docid val)
|
||||||
|
(save-excursion
|
||||||
|
(when (mu4e--goto-docid docid)
|
||||||
|
(mu4e-mark-set 'unmark))))
|
||||||
|
mu4e--mark-map)
|
||||||
|
;; in any case, clear the marks map
|
||||||
|
(mu4e--mark-clear))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-docid-marked-p (docid)
|
||||||
|
"Is the given docid marked?"
|
||||||
|
(when (gethash docid mu4e--mark-map) t))
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-mark-handle-when-leaving ()
|
||||||
|
"If there are any marks in the current buffer, handle those
|
||||||
|
according to the value of `mu4e-headers-leave-behavior'. This
|
||||||
|
function is to be called before any further action (like searching,
|
||||||
|
quiting the buffer) is taken; returning t means 'take the following
|
||||||
|
action', return nil means 'don't do anything'"
|
||||||
|
(let ((marknum
|
||||||
|
(if mu4e--mark-map (hash-table-count mu4e--mark-map) 0))
|
||||||
|
(what mu4e-headers-leave-behavior))
|
||||||
|
(unless (or (= marknum 0) (eq what 'ignore) (eq what 'apply))
|
||||||
|
;; if `mu4e-headers-leave-behavior' is not apply or ignore, ask the user
|
||||||
|
(setq what
|
||||||
|
(let ((kar (mu4e-read-option
|
||||||
|
"There are existing marks; should we: "
|
||||||
|
'(("apply marks") ("ignore marks?")))))
|
||||||
|
(cond
|
||||||
|
((= kar ?a) 'apply)
|
||||||
|
((= kar ?i) 'ignore)
|
||||||
|
(t nil))))) ;; cancel
|
||||||
|
;; we determined what to do... now do it
|
||||||
|
(cond
|
||||||
|
((= 0 marknum) t) ;; no marks, just go ahead
|
||||||
|
((eq what 'ignore) t) ;; ignore the marks, go ahead
|
||||||
|
((eq what 'apply)
|
||||||
|
(progn (mu4e-mark-execute-all t) t) t) ;; execute marks, go ahead
|
||||||
|
(t nil)))) ;; otherwise, don't do anything
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'mu4e-mark)
|
|
@ -28,18 +28,16 @@
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'mu4e-utils) ;; utility functions
|
(require 'mu4e-utils) ;; utility functions
|
||||||
(require 'mu4e-vars)
|
(require 'mu4e-vars)
|
||||||
|
(require 'mu4e-mark)
|
||||||
|
|
||||||
;; we prefer the improved fill-region
|
;; we prefer the improved fill-region
|
||||||
(require 'filladapt nil 'noerror)
|
(require 'filladapt nil 'noerror)
|
||||||
(require 'comint)
|
(require 'comint)
|
||||||
|
|
||||||
;; some buffer-local variables
|
;; some buffer-local variables
|
||||||
(defvar mu4e-hdrs-buffer nil
|
(defvar mu4e--view-hdrs-buffer nil
|
||||||
"*internal* Headers buffer connected to this view.")
|
"*internal* Headers buffer connected to this view.")
|
||||||
|
|
||||||
(defconst mu4e-view-raw-buffer-name "*mu4e-raw-view*"
|
|
||||||
"*internal* Name for the raw message view buffer")
|
|
||||||
|
|
||||||
(defun mu4e-view-message-with-msgid (msgid)
|
(defun mu4e-view-message-with-msgid (msgid)
|
||||||
"View message with MSGID. This is meant for external programs
|
"View message with MSGID. This is meant for external programs
|
||||||
wanting to show specific messages - for example, `mu4e-org'."
|
wanting to show specific messages - for example, `mu4e-org'."
|
||||||
|
@ -114,7 +112,7 @@ marking if it still had that."
|
||||||
(setq ;; these are buffer-local
|
(setq ;; these are buffer-local
|
||||||
buffer-read-only t
|
buffer-read-only t
|
||||||
mu4e-current-msg msg
|
mu4e-current-msg msg
|
||||||
mu4e-hdrs-buffer hdrsbuf
|
mu4e--view-hdrs-buffer hdrsbuf
|
||||||
mu4e-link-map (make-hash-table :size 32 :rehash-size 2 :weakness nil))
|
mu4e-link-map (make-hash-table :size 32 :rehash-size 2 :weakness nil))
|
||||||
|
|
||||||
(switch-to-buffer buf)
|
(switch-to-buffer buf)
|
||||||
|
@ -225,6 +223,7 @@ is nil, and otherwise open it."
|
||||||
(defvar mu4e-view-mode-map nil
|
(defvar mu4e-view-mode-map nil
|
||||||
"Keymap for \"*mu4e-view*\" buffers.")
|
"Keymap for \"*mu4e-view*\" buffers.")
|
||||||
(unless mu4e-view-mode-map
|
(unless mu4e-view-mode-map
|
||||||
|
|
||||||
(setq mu4e-view-mode-map
|
(setq mu4e-view-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
|
|
||||||
|
@ -264,11 +263,11 @@ is nil, and otherwise open it."
|
||||||
#'(lambda () (interactive) (scroll-up -1)))
|
#'(lambda () (interactive) (scroll-up -1)))
|
||||||
|
|
||||||
;; navigation between messages
|
;; navigation between messages
|
||||||
(define-key map "p" 'mu4e-view-prev-header)
|
(define-key map "p" 'mu4e--view-prev-header)
|
||||||
(define-key map "n" 'mu4e-view-next-header)
|
(define-key map "n" 'mu4e--view-next-header)
|
||||||
;; the same
|
;; the same
|
||||||
(define-key map (kbd "<M-down>") 'mu4e-view-next-header)
|
(define-key map (kbd "<M-down>") 'mu4e--view-next-header)
|
||||||
(define-key map (kbd "<M-up>") 'mu4e-view-prev-header)
|
(define-key map (kbd "<M-up>") 'mu4e--view-prev-header)
|
||||||
|
|
||||||
;; switching to view mode (if it's visible)
|
;; switching to view mode (if it's visible)
|
||||||
(define-key map "y" 'mu4e-select-other-view)
|
(define-key map "y" 'mu4e-select-other-view)
|
||||||
|
@ -348,8 +347,8 @@ is nil, and otherwise open it."
|
||||||
(define-key menumap [jump] '("Jump to maildir" . mu4e-jump-to-maildir))
|
(define-key menumap [jump] '("Jump to maildir" . mu4e-jump-to-maildir))
|
||||||
|
|
||||||
(define-key menumap [sepa4] '("--"))
|
(define-key menumap [sepa4] '("--"))
|
||||||
(define-key menumap [next] '("Next" . mu4e-view-next-header))
|
(define-key menumap [next] '("Next" . mu4e--view-next-header))
|
||||||
(define-key menumap [previous] '("Previous" . mu4e-view-prev-header)))
|
(define-key menumap [previous] '("Previous" . mu4e--view-prev-header)))
|
||||||
map)))
|
map)))
|
||||||
|
|
||||||
(fset 'mu4e-view-mode-map mu4e-view-mode-map)
|
(fset 'mu4e-view-mode-map mu4e-view-mode-map)
|
||||||
|
@ -363,7 +362,7 @@ is nil, and otherwise open it."
|
||||||
\\{mu4e-view-mode-map}."
|
\\{mu4e-view-mode-map}."
|
||||||
(use-local-map mu4e-view-mode-map)
|
(use-local-map mu4e-view-mode-map)
|
||||||
|
|
||||||
(make-local-variable 'mu4e-hdrs-buffer)
|
(make-local-variable 'mu4e--view-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)
|
||||||
|
|
||||||
|
@ -545,7 +544,7 @@ See the `org-contacts' documentation for more details."
|
||||||
"Redisplay the current message, without wrapped lines or hidden
|
"Redisplay the current message, without wrapped lines or hidden
|
||||||
citations."
|
citations."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e-view mu4e-current-msg mu4e-hdrs-buffer t)
|
(mu4e-view mu4e-current-msg mu4e--view-hdrs-buffer t)
|
||||||
(setq
|
(setq
|
||||||
mu4e-lines-wrapped nil
|
mu4e-lines-wrapped nil
|
||||||
mu4e-cited-hidden nil))
|
mu4e-cited-hidden nil))
|
||||||
|
@ -559,35 +558,16 @@ citations."
|
||||||
(kill-buffer-and-window)
|
(kill-buffer-and-window)
|
||||||
(kill-buffer)))))
|
(kill-buffer)))))
|
||||||
|
|
||||||
(defun mu4e-view-next-header ()
|
(defun mu4e--view-hdrs-move (lines)
|
||||||
"View the next header."
|
"Move point LINES lines forward (if LINES is positive) or
|
||||||
(interactive)
|
backward (if LINES is negative). If this succeeds, return the new
|
||||||
(when (mu4e-next-header)
|
docid. Otherwise, return nil."
|
||||||
(mu4e-view-message)))
|
(when (buffer-live-p mu4e--view-hdrs-buffer)
|
||||||
|
(with-current-buffer mu4e--view-hdrs-buffer
|
||||||
|
(mu4e--hdrs-move lines))))
|
||||||
|
|
||||||
(defun mu4e-view-prev-header ()
|
(defun mu4e--view-next-header()(interactive)(mu4e--view-hdrs-move 1))
|
||||||
"View the previous header."
|
(defun mu4e--view-prev-header()(interactive)(mu4e--view-hdrs-move -1))
|
||||||
(interactive)
|
|
||||||
(when (mu4e-prev-header)
|
|
||||||
(mu4e-view-message)))
|
|
||||||
|
|
||||||
(defun mu4e-view-mark-for-move ()
|
|
||||||
"Mark the current message for moving."
|
|
||||||
(interactive)
|
|
||||||
(when (mu4e-mark-for-move)
|
|
||||||
(mu4e-view-message)))
|
|
||||||
|
|
||||||
(defun mu4e-view-mark-for-trash ()
|
|
||||||
"Mark the current message for moving to the trash folder."
|
|
||||||
(interactive)
|
|
||||||
(when (mu4e-mark-for-trash)
|
|
||||||
(mu4e-view-message)))
|
|
||||||
|
|
||||||
(defun mu4e-view-mark-for-delete ()
|
|
||||||
"Mark the current message for deletion."
|
|
||||||
(interactive)
|
|
||||||
(when (mu4e-mark-for-delete)
|
|
||||||
(mu4e-view-message)))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-view-action (&optional msg)
|
(defun mu4e-view-action (&optional msg)
|
||||||
|
@ -684,6 +664,7 @@ PIPECMD is nil, ask user for it."
|
||||||
(index (plist-get att :index)))
|
(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-attachment-action (&optional msg)
|
(defun mu4e-view-attachment-action (&optional msg)
|
||||||
"Ask user what to do with attachments in MSG (or nil to use
|
"Ask user what to do with attachments in MSG (or nil to use
|
||||||
message-at-point, then do it. The actions are specified in
|
message-at-point, then do it. The actions are specified in
|
||||||
|
@ -697,6 +678,7 @@ message-at-point, then do it. The actions are specified in
|
||||||
(when (and actionfunc attnum)
|
(when (and actionfunc attnum)
|
||||||
(funcall actionfunc msg 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.
|
||||||
(defun mu4e-view-temp-handler (path what param)
|
(defun mu4e-view-temp-handler (path what param)
|
||||||
|
@ -718,7 +700,22 @@ attachments) in response to a (mu4e-proc-extract 'temp ... )."
|
||||||
(t (error "Unsupported action %S" what))))
|
(t (error "Unsupported action %S" what))))
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defun mu4e--in-split-view ()
|
;;; marking
|
||||||
|
(defun mu4e--view-mark-set (mark)
|
||||||
|
"Set mark on the current messages."
|
||||||
|
(unless (buffer-live-p mu4e--view-hdrs-buffer)
|
||||||
|
(error "No headers buffer available"))
|
||||||
|
(let ((docid (mu4e-msg-field mu4e-current-msg :docid)))
|
||||||
|
(with-current-buffer mu4e--view-hdrs-buffer
|
||||||
|
(if (eq mark 'move)
|
||||||
|
(mu4e-mark-for-move-set)
|
||||||
|
(mu4e-mark-at-point mark)))))
|
||||||
|
;; (when (not (eq mark 'unmark))
|
||||||
|
;; (mu4e--view-next-header)
|
||||||
|
;; (mu4e-view-message)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e--split-view-p ()
|
||||||
"Return t if we're in split-view, nil otherwise."
|
"Return t if we're in split-view, nil otherwise."
|
||||||
(member mu4e-split-view '(horizontal vertical)))
|
(member mu4e-split-view '(horizontal vertical)))
|
||||||
|
|
||||||
|
@ -726,24 +723,43 @@ attachments) in response to a (mu4e-proc-extract 'temp ... )."
|
||||||
"If we're in split-view, unmark all messages. Otherwise, warn
|
"If we're in split-view, unmark all messages. Otherwise, warn
|
||||||
user that unmarking only works in the header list."
|
user that unmarking only works in the header list."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if (mu4e--in-split-view)
|
(if (mu4e--split-view-p)
|
||||||
(mu4e-unmark-all)
|
(mu4e-mark-unmark-all)
|
||||||
(message "Unmarking needs to be done in the header list view")))
|
(message "Unmarking needs to be done in the header list view")))
|
||||||
|
|
||||||
(defun mu4e-view-unmark ()
|
(defun mu4e-view-unmark ()
|
||||||
"If we're in split-view, unmark message at point. Otherwise, warn
|
"If we're in split-view, unmark message at point. Otherwise, warn
|
||||||
user that unmarking only works in the header list."
|
user that unmarking only works in the header list."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if (mu4e--in-split-view)
|
(if (mu4e--split-view-p)
|
||||||
(mu4e-unmark)
|
(mu4e--view-mark-set 'unmark)
|
||||||
(message "Unmarking needs to be done in the header list view")))
|
(message "Unmarking needs to be done in the header list view")))
|
||||||
|
|
||||||
|
(defun mu4e-view-mark-for-move ()
|
||||||
|
"Mark the current message for moving."
|
||||||
|
(interactive)
|
||||||
|
(mu4e--view-mark-set 'move)
|
||||||
|
(mu4e--view-next-header))
|
||||||
|
|
||||||
|
(defun mu4e-view-mark-for-trash ()
|
||||||
|
"Mark the current message for moving to the trash folder."
|
||||||
|
(interactive)
|
||||||
|
(mu4e--view-mark-set 'trash)
|
||||||
|
(mu4e--view-next-header))
|
||||||
|
|
||||||
|
(defun mu4e-view-mark-for-delete ()
|
||||||
|
"Mark the current message for deletion."
|
||||||
|
(interactive)
|
||||||
|
(mu4e--view-mark-set 'delete)
|
||||||
|
(mu4e--view-next-header))
|
||||||
|
|
||||||
(defun mu4e-view-marked-execute ()
|
(defun mu4e-view-marked-execute ()
|
||||||
"If we're in split-view, execute the marks. Otherwise, warn user
|
"If we're in split-view, execute the marks. Otherwise, warn user
|
||||||
that execution can only take place in n the header list."
|
that execution can only take place in n the header list."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if (mu4e--in-split-view)
|
(if (mu4e--split-view-p)
|
||||||
(mu4e-execute-marks)
|
(with-current-buffer mu4e--view-hdrs-buffer
|
||||||
|
(mu4e-mark-execute-all))
|
||||||
(message "Execution needs to be done in the header list view")))
|
(message "Execution needs to be done in the header list view")))
|
||||||
|
|
||||||
(defun mu4e-view-go-to-url (num)
|
(defun mu4e-view-go-to-url (num)
|
||||||
|
@ -753,6 +769,9 @@ that execution can only take place in n the header list."
|
||||||
(unless url (error "Invalid number for URL"))
|
(unless url (error "Invalid number for URL"))
|
||||||
(browse-url url)))
|
(browse-url url)))
|
||||||
|
|
||||||
|
(defconst mu4e-view-raw-buffer-name "*mu4e-raw-view*"
|
||||||
|
"*internal* Name for the raw message view buffer")
|
||||||
|
|
||||||
(defun mu4e-view-raw-message ()
|
(defun mu4e-view-raw-message ()
|
||||||
"Display the raw contents of message at point in a new buffer."
|
"Display the raw contents of message at point in a new buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
|
Loading…
Reference in New Issue