mirror of https://github.com/djcb/mu.git
* new feature: deferred marking, i.e. mark now, decide what for later (WIP)
This commit is contained in:
parent
6c61b44a87
commit
0d913c1a1f
8
TODO
8
TODO
|
@ -18,13 +18,14 @@
|
|||
- contact completion (see Jacek's 'mu4e: using' mail)
|
||||
- actions for /all/ headers, actions for /all/ attachment
|
||||
- custom header fields in headers-view, message-view
|
||||
- custom predicate functions for marking
|
||||
- guile integration
|
||||
- check if we can speed up mu4e-proc parsing by using search rather than
|
||||
regexp search
|
||||
- show maildirs as a tree, not a list in speed bar
|
||||
- mark message, decide what to do with them later
|
||||
- make killing all windows (i.e.. 'fullscreen mode' optional)
|
||||
- improve fringe marks (see https://github.com/djcb/mu/issues/21)
|
||||
- better naming for draft buffers
|
||||
- review emacs menus
|
||||
|
||||
** Done
|
||||
|
||||
|
@ -50,7 +51,8 @@
|
|||
https://github.com/djcb/mu/issues/26)
|
||||
- *FIX* don't remove unknown message flags when moving
|
||||
- make guile/gtk/webkit dependency optional
|
||||
|
||||
- improve fringe marks (see https://github.com/djcb/mu/issues/21)
|
||||
- mark message, decide what to do with them later (i.e.. 'deferred marking')
|
||||
|
||||
|
||||
# Local Variables:
|
||||
|
|
|
@ -30,7 +30,9 @@
|
|||
(eval-when-compile (byte-compile-disable-warning 'cl-functions))
|
||||
(require 'cl)
|
||||
|
||||
(require 'fringe)
|
||||
(require 'hl-line)
|
||||
|
||||
(require 'mu4e-utils) ;; utility functions
|
||||
(require 'mu4e-proc)
|
||||
(require 'mu4e-vars)
|
||||
|
@ -310,24 +312,34 @@ after the end of the search results."
|
|||
;; highlight the first message
|
||||
(mu4e~headers-highlight (mu4e~headers-docid-at-point (point-min)))))))))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(defmacro mu4e~headers-defun-mark-func (mark)
|
||||
"Define a function mu4e~headers-mark-MARK."
|
||||
(let ((funcname (intern (concat "mu4e~headers-mark-" (symbol-name mark))))
|
||||
(docstring (concat "Mark header at point with " (symbol-name mark) ".")))
|
||||
`(defun ,funcname () ,docstring
|
||||
(interactive)
|
||||
(mu4e-headers-mark-and-next (quote ,mark)))))
|
||||
|
||||
;; define our mark functions; there must be some way to do this in a loop but
|
||||
;; since `mu4e~headers-defun-mark-func' is a macro, the argument must be a
|
||||
;; literal value.
|
||||
(mu4e~headers-defun-mark-func trash)
|
||||
(mu4e~headers-defun-mark-func delete)
|
||||
(mu4e~headers-defun-mark-func read)
|
||||
(mu4e~headers-defun-mark-func unread)
|
||||
(mu4e~headers-defun-mark-func flag)
|
||||
(mu4e~headers-defun-mark-func unflag)
|
||||
(mu4e~headers-defun-mark-func deferred)
|
||||
(mu4e~headers-defun-mark-func unmark)
|
||||
|
||||
|
||||
;;; headers-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(defvar mu4e-headers-mode-map nil
|
||||
"Keymap for *mu4e-headers* buffers.")
|
||||
(unless mu4e-headers-mode-map
|
||||
;; add some quick funcs so our key descriptions below are shorter
|
||||
;; TODO: defmacro this
|
||||
(defun mu4e~headers-mark-trash()(interactive)(mu4e-headers-mark-and-next 'trash))
|
||||
(defun mu4e~headers-mark-delete()(interactive)(mu4e-headers-mark-and-next 'delete))
|
||||
(defun mu4e~headers-mark-unmark()(interactive)(mu4e-headers-mark-and-next 'unmark))
|
||||
(defun mu4e~headers-mark-read()(interactive)(mu4e-headers-mark-and-next 'read))
|
||||
(defun mu4e~headers-mark-unread()(interactive)(mu4e-headers-mark-and-next 'unread))
|
||||
(defun mu4e~headers-mark-flag()(interactive)(mu4e-headers-mark-and-next 'flag))
|
||||
(defun mu4e~headers-mark-unflag()(interactive)(mu4e-headers-mark-and-next 'unflag))
|
||||
|
||||
|
||||
(setq mu4e-headers-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
|
||||
|
@ -391,7 +403,11 @@ after the end of the search results."
|
|||
(define-key map (kbd "-") 'mu4e~headers-mark-unflag)
|
||||
|
||||
(define-key map "m" 'mu4e-headers-mark-for-move-and-next)
|
||||
|
||||
|
||||
(define-key map (kbd "*") 'mu4e~headers-mark-deferred)
|
||||
(define-key map (kbd "<kp-multiply>") 'mu4e~headers-mark-deferred)
|
||||
(define-key map (kbd "#") 'mu4e-mark-resolve-deferred-marks)
|
||||
|
||||
(define-key map "U" 'mu4e-mark-unmark-all)
|
||||
(define-key map "x" 'mu4e-mark-execute-all)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -718,25 +734,7 @@ header."
|
|||
(when msg
|
||||
(funcall func msg))))))
|
||||
|
||||
|
||||
(defun mu4e~headers-get-markpair ()
|
||||
"Ask user for a mark; return (MARK . TARGET)."
|
||||
(let* ((mark
|
||||
(mu4e-read-option "Mark to set: "
|
||||
'( ("move" . move)
|
||||
("dtrash" . trash)
|
||||
("Delete" . delete)
|
||||
("ounread" . unread)
|
||||
("read" . read)
|
||||
("+flag" . flag)
|
||||
("-unflag" . unflag)
|
||||
("unmark" . unmark))))
|
||||
(target
|
||||
(when (eq mark 'move)
|
||||
(mu4e-ask-maildir-check-exists "Move message to: "))))
|
||||
(cons mark target)))
|
||||
|
||||
(defvar mu4e~headers-regexp-hist nil
|
||||
(defvar mu4e~headers-regexp-hist nil
|
||||
"History list of regexps used.")
|
||||
|
||||
(defun mu4e-headers-mark-pattern ()
|
||||
|
@ -744,7 +742,7 @@ header."
|
|||
match and a regular expression to match with. Then, mark all
|
||||
matching messages with that mark."
|
||||
(interactive)
|
||||
(let ((markpair (mu4e~headers-get-markpair))
|
||||
(let ((markpair (mu4e~mark-get-markpair "Mark matched messages with: " t))
|
||||
(field (mu4e-read-option "Field to match: "
|
||||
'( ("subject" . :subject)
|
||||
("from" . :from)
|
||||
|
@ -789,7 +787,10 @@ limited to the message at point and its descendants."
|
|||
(mu4e-message-at-point t) 'thread-id))
|
||||
(path (mu4e~headers-get-thread-info
|
||||
(mu4e-message-at-point t) 'path))
|
||||
(markpair (mu4e~headers-get-markpair))
|
||||
(markpair
|
||||
(mu4e~mark-get-markpair
|
||||
(if subthread "Mark subthread with: " "Mark whole thread with: ")
|
||||
t))
|
||||
(last-marked-point))
|
||||
(mu4e-headers-for-each
|
||||
(lambda (msg)
|
||||
|
|
|
@ -52,8 +52,8 @@ particularly fast).")
|
|||
"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)
|
||||
markinfo is a cons cell consisting of the following:
|
||||
\(mark . target)
|
||||
where
|
||||
MARK is the type of mark (move, trash, delete)
|
||||
TARGET (optional) is the target directory (for 'move')")
|
||||
|
@ -99,6 +99,7 @@ The following marks are available, and the corresponding props:
|
|||
`unread' n mark the message as unread
|
||||
`flag' n mark this message for flagging
|
||||
`unflag' n mark this message for unflagging
|
||||
`deferred' n mark this message for *something* (decided later)
|
||||
`unmark' n unmark this message"
|
||||
(interactive)
|
||||
(let* ((docid (mu4e~headers-docid-at-point))
|
||||
|
@ -106,16 +107,17 @@ The following marks are available, and the corresponding props:
|
|||
;; target (the target folder) the other ones get a pseudo "target", as
|
||||
;; info for the user.
|
||||
(markcell
|
||||
(case mark ;; the visual mark
|
||||
('move `("m" . ,target))
|
||||
('trash '("d" . "trash"))
|
||||
('delete '("D" . "delete"))
|
||||
('unread '("o" . "unread"))
|
||||
('read '("r" . "read"))
|
||||
('flag '("+" . "flag"))
|
||||
('unflag '("-" . "unflag"))
|
||||
('unmark '(" " . nil))
|
||||
(t (error "Invalid mark %S" mark))))
|
||||
(case mark
|
||||
(move `("m" . ,target))
|
||||
(trash '("d" . "trash"))
|
||||
(delete '("D" . "delete"))
|
||||
(unread '("o" . "unread"))
|
||||
(read '("r" . "read"))
|
||||
(flag '("+" . "flag"))
|
||||
(unflag '("-" . "unflag"))
|
||||
(deferred '("*" . "deferred"))
|
||||
(unmark '(" " . nil))
|
||||
(otherwise (error "Invalid mark %S" mark))))
|
||||
(markkar (car markcell))
|
||||
(target (cdr markcell)))
|
||||
(unless docid (error "No message on this line"))
|
||||
|
@ -128,7 +130,7 @@ The following marks are available, and the corresponding props:
|
|||
(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)
|
||||
(puthash docid (cons mark target) mu4e~mark-map)
|
||||
;; when we have a target (ie., when moving), show the target folder in
|
||||
;; an overlay
|
||||
(when (and target mu4e-headers-show-target)
|
||||
|
@ -178,6 +180,45 @@ provided, function asks for it."
|
|||
(mu4e-mark-set 'move target))))
|
||||
|
||||
|
||||
(defun mu4e~mark-get-markpair (prompt &optional allow-deferred)
|
||||
"Ask user for a mark; return (MARK . TARGET). If ALLOW-DEFERRED
|
||||
is non-nil, allow the 'deferred' pseudo mark as well."
|
||||
(let* ((marks '(("move" . move)
|
||||
("dtrash" . trash)
|
||||
("Delete" . delete)
|
||||
("ounread" . unread)
|
||||
("read" . read)
|
||||
("+flag" . flag)
|
||||
("-unflag" . unflag)
|
||||
("unmark" . unmark)))
|
||||
(marks
|
||||
(if allow-deferred
|
||||
(append marks (list '("*deferred" . deferred)))
|
||||
marks))
|
||||
(mark (mu4e-read-option prompt marks))
|
||||
(target
|
||||
(when (eq mark 'move)
|
||||
(mu4e-ask-maildir-check-exists "Move message to: "))))
|
||||
(cons mark target)))
|
||||
|
||||
|
||||
(defun mu4e-mark-resolve-deferred-marks ()
|
||||
"Check if there are any deferred marks. If there are such marks,
|
||||
replace them with a _real_ mark (ask the user which one)."
|
||||
(interactive)
|
||||
(let ((markpair))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let ((mark (car val)) (target (cdr val)))
|
||||
(when (eql mark 'deferred)
|
||||
(unless markpair
|
||||
(setq markpair
|
||||
(mu4e~mark-get-markpair "Set deferred mark to: " nil)))
|
||||
(save-excursion
|
||||
(when (mu4e~headers-goto-docid docid)
|
||||
(mu4e-mark-set (car markpair) (cdr markpair)))))))
|
||||
mu4e~mark-map)))
|
||||
|
||||
(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
|
||||
|
@ -194,13 +235,14 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
|||
(let ((marknum (hash-table-count mu4e~mark-map)))
|
||||
(if (zerop marknum)
|
||||
(message "Nothing is marked")
|
||||
(mu4e-mark-resolve-deferred-marks)
|
||||
(when (or no-confirmation
|
||||
(y-or-n-p
|
||||
(format "Are you sure you want to execute %d mark%s?"
|
||||
marknum (if (> marknum 1) "s" ""))))
|
||||
(maphash
|
||||
(lambda (docid val)
|
||||
(let ((mark (nth 0 val)) (target (nth 1 val)))
|
||||
(let ((mark (car val)) (target (cdr val)))
|
||||
(case mark
|
||||
(move (mu4e~proc-move docid target))
|
||||
(read (mu4e~proc-move docid nil "+S-u-N"))
|
||||
|
@ -211,7 +253,8 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
|||
(unless mu4e-trash-folder
|
||||
(error "`mu4e-trash-folder' not set"))
|
||||
(mu4e~proc-move docid mu4e-trash-folder "+T"))
|
||||
(delete (mu4e~proc-remove docid)))))
|
||||
(delete (mu4e~proc-remove docid))
|
||||
(otherwise (error "Unrecognized mark %S" mark)))))
|
||||
mu4e~mark-map))
|
||||
(mu4e-mark-unmark-all)
|
||||
(message nil))))
|
||||
|
|
|
@ -428,7 +428,11 @@ is nil, and otherwise open it."
|
|||
|
||||
(define-key map (kbd "+") 'mu4e-view-mark-flag)
|
||||
(define-key map (kbd "-") 'mu4e-view-mark-unflag)
|
||||
|
||||
|
||||
(define-key map (kbd "*") 'mu4e-view-mark-deferred)
|
||||
(define-key map (kbd "<kp-multiply>") 'mu4e-view-mark-deferred)
|
||||
(define-key map (kbd "#") 'mu4e-mark-resolve-deferred-marks)
|
||||
|
||||
;; misc
|
||||
(define-key map "w" 'mu4e-view-toggle-wrap-lines)
|
||||
(define-key map "h" 'mu4e-view-toggle-hide-cited)
|
||||
|
@ -973,6 +977,13 @@ user that unmarking only works in the header list."
|
|||
(mu4e~view-mark-set 'unflag)
|
||||
(mu4e-view-headers-next))
|
||||
|
||||
(defun mu4e-view-mark-deferred ()
|
||||
"Mark the current message for unflagging."
|
||||
(interactive)
|
||||
(mu4e~view-mark-set 'deferred)
|
||||
(mu4e-view-headers-next))
|
||||
|
||||
|
||||
(defun mu4e-view-marked-execute ()
|
||||
"Execute the marks."
|
||||
(interactive)
|
||||
|
|
|
@ -561,6 +561,9 @@ U unmark *all* messages
|
|||
% mark based on a regular expression
|
||||
T,t mark whole thread, subthread
|
||||
|
||||
SPC deferred mark (decide what to mark for later)
|
||||
* resolve deferred marks
|
||||
|
||||
x execute actions for the marked messages
|
||||
|
||||
composition
|
||||
|
@ -646,7 +649,6 @@ include the previously captured message as an attachment, using
|
|||
|
||||
The file @file{mu4e-actions.el} in the @t{mu4e} source distribution contains a
|
||||
number of example actions.
|
||||
|
||||
|
||||
@subsection Split view
|
||||
|
||||
|
@ -738,10 +740,12 @@ or by using the keyboard; the default bindings are:
|
|||
|
||||
@verbatim
|
||||
key description
|
||||
--- -----------
|
||||
==============================================================
|
||||
n,p go to next, previous message
|
||||
y select the headers view (if it's visible)
|
||||
|
||||
searching
|
||||
---------
|
||||
s search
|
||||
e edit last query
|
||||
/ narrow the search
|
||||
|
@ -752,23 +756,32 @@ j jump to maildir
|
|||
M-left previous query
|
||||
M-right next query
|
||||
|
||||
C-+,C-- increase / decrease the number of headers shown
|
||||
|
||||
a execute some action on the message
|
||||
|
||||
marking
|
||||
-------
|
||||
d mark for moving to the trash folder
|
||||
DEL,D mark for immediate deletion
|
||||
m mark for moving to another maildir folder
|
||||
+,- mark for flagging/unflagging
|
||||
o,r mark message as unread, read
|
||||
|
||||
u unmark message at point
|
||||
U unmark *all* messages
|
||||
|
||||
% mark based on a regular expression
|
||||
T,t mark whole thread, subthread
|
||||
|
||||
SPC deferred mark (decide what to mark for later)
|
||||
* resolve deferred marks
|
||||
|
||||
x execute actions for the marked messages
|
||||
|
||||
composition
|
||||
-----------
|
||||
R,F,C reply/forward/compose
|
||||
E edit (only allowed for draft messages)
|
||||
|
||||
. show the raw message view. 'q' takes you back.
|
||||
|
||||
actions
|
||||
-------
|
||||
g go to (visit) numbered URL (using `browse-url')
|
||||
(or: <mouse-2> or RET with point on url)
|
||||
e extract (save) attachment (asks for number)
|
||||
|
@ -776,10 +789,17 @@ e extract (save) attachment (asks for number)
|
|||
C-u e will extract multiple attachments
|
||||
o open attachment (asks for number)
|
||||
(or: <S-mouse-2> or S-RET with point on attachment)
|
||||
A execute some action on an attachment
|
||||
|
||||
a execute some custom action on the message
|
||||
A execute some custom action on an attachment
|
||||
|
||||
misc
|
||||
----
|
||||
w toggle line wrapping
|
||||
h toggle showing cited parts
|
||||
|
||||
. show the raw message view. 'q' takes you back.
|
||||
C-+,C-- increase / decrease the number of headers shown
|
||||
H get help
|
||||
q,z leave the message view
|
||||
@end verbatim
|
||||
|
@ -1251,18 +1271,23 @@ apply to messages:
|
|||
| unflag | - | remove 'flagged' mark |
|
||||
| read | r | mark as read |
|
||||
| unread | o | marks as unread |
|
||||
| deferred | * | mark now, decide later |
|
||||
| unmark | u | remove mark at point |
|
||||
| remove all | U | remove all marks |
|
||||
| unmark all | U | remove all marks |
|
||||
@end verbatim
|
||||
|
||||
After marking a header for something, the leftmost columns shows a character
|
||||
(same as the keybinding) to remind you what you marked it with. Next to that,
|
||||
@t{mu4e} displays the name of the mark, on top of the beginning of the header
|
||||
line. This latter display is informative, but if you often mark many
|
||||
(thousands) messages, this may slow down things significantly@footnote{this
|
||||
uses an emacs feature called @emph{overlays}, which are slow when used a lot
|
||||
in a buffer}. For this reason, you can disable this by setting
|
||||
@code{mu4e-headers-show-target} to @code{nil}.
|
||||
After marking a header for something, the left-most columns shows a character
|
||||
to remind you what you marked it with. Next to that, @t{mu4e} displays the
|
||||
name of the mark, on top of the beginning of the header line. This latter
|
||||
display is informative, but if you often mark many (thousands) messages, this
|
||||
may slow down things significantly@footnote{this uses an emacs feature called
|
||||
@emph{overlays}, which are slow when used a lot in a buffer}. For this reason,
|
||||
you can disable this by setting @code{mu4e-headers-show-target} to @code{nil}.
|
||||
|
||||
@t{deferred} is a special kind of mark; you can use it to mark some messages,
|
||||
and then decide later what mark to use for them. At any time, you can set the
|
||||
actual mark with @code{mu4e-mark-resolve-deferred-marks} (@key{#}), or
|
||||
@t{mu4e} will ask you for it when you execute the marks (@key{x}).
|
||||
|
||||
@node Executing the marks
|
||||
@section Executing the marks
|
||||
|
@ -1304,12 +1329,14 @@ You can invoke the actions with @key{a} for actions on messages, and @key{A}
|
|||
for actions on attachments. In the following, we'll gives some examples of
|
||||
defining actions.
|
||||
|
||||
Note, the format of the actions has changed slightly since version 0.9.8.4;
|
||||
@t{mu4e} warns you if you use the old format still. The older format was:
|
||||
@code{(DESCRIPTION SHORTCUT [VALUE])}, while the new format is a cons-cell,
|
||||
@code{(DESCRIPTION . VALUE)}; see below for some examples. If your shortcut is
|
||||
not also the first character of the description, simply prefix the description
|
||||
with that character.
|
||||
Note, the format of the actions has changed since version 0.9.8.4, and you
|
||||
must change your configuration to use the new format; @t{mu4e} warns you when
|
||||
you are using the old format.
|
||||
|
||||
The older format was: @code{(DESCRIPTION SHORTCUT [VALUE])}, while the new
|
||||
format is a cons-cell, @code{(DESCRIPTION . VALUE)}; see below for some
|
||||
examples. If your shortcut is not also the first character of the description,
|
||||
simply prefix the description with that character.
|
||||
|
||||
@subsection Functions for actions
|
||||
|
||||
|
@ -1334,7 +1361,7 @@ After you have defined your function, you can add it to the list of actions,
|
|||
either @code{mu4e-headers-actions}, @code{mu4e-view-actions} or
|
||||
@code{mu4e-view-attachment-actions}.
|
||||
|
||||
Let's now look at some simple examples.
|
||||
Let's take a at some simple examples.
|
||||
|
||||
@subsection Example: adding an action in the headers view
|
||||
|
||||
|
@ -1398,9 +1425,9 @@ To help a bit with this, all functions and variables in @t{mu4e} marked for
|
|||
letters, so they will only appear at the end of completion buffers and the
|
||||
like.
|
||||
|
||||
Functions that start with @t{mu4e-view-} and @t{mu4e-headers-} should be called
|
||||
only from that particular context (the message view and the headers view,
|
||||
respectively).
|
||||
Functions that start with @t{mu4e-view-} and @t{mu4e-headers-} should be
|
||||
called only from that particular context (the message view and the headers
|
||||
view, respectively).
|
||||
|
||||
@subsection Example actions
|
||||
|
||||
|
@ -1918,7 +1945,7 @@ can also use functions like @code{mu4e-headers-mark-thread} (@key{T}),
|
|||
time, and @code{mu4e-headers-mark-pattern} (@key{%}) to mark all messages
|
||||
matching a certain regular expression.
|
||||
@item @emph{How can I use @t{BBDB}?} Currently, there is no built-in for
|
||||
address management with @t{BBDB}; instead, we recommend @xref{Maintaining an
|
||||
address management with @t{BBDB}; instead, we recommend @ref{Maintaining an
|
||||
address-book with org-contacts} for now.
|
||||
@item @emph{mu4e seems to return a mere subset of all matches - how can I get
|
||||
all?}. Indeed, for speed reasons (and because, if you are like the author, you
|
||||
|
|
Loading…
Reference in New Issue