* mu4e: add support for custom matcher functions (WIP)
This commit is contained in:
@ -87,6 +87,26 @@ are of the form:
|
|||||||
* SHORTCUT is a one-character shortcut to call this action
|
* SHORTCUT is a one-character shortcut to call this action
|
||||||
* FUNC is a function which receives a message plist as an argument.")
|
* FUNC is a function which receives a message plist as an argument.")
|
||||||
|
|
||||||
|
(defvar mu4e-headers-custom-markers
|
||||||
|
'(("Older than"
|
||||||
|
(lambda (msg date) (time-less-p (mu4e-msg-field msg :date) date))
|
||||||
|
(lambda () (mu4e-get-time-date "Match messages before: ")))
|
||||||
|
("Newer than"
|
||||||
|
(lambda (msg date) (time-less-p date (mu4e-msg-field msg :date)))
|
||||||
|
(lambda () (mu4e-get-time-date "Match messages after: ")))
|
||||||
|
("Bigger than"
|
||||||
|
(lambda (msg bytes) (> (mu4e-msg-field msg :size) (* 1024 bytes)))
|
||||||
|
(lambda () (read-number "Match messages bigger than (Kbytes): "))))
|
||||||
|
"List of custom markers -- functions to mark message that match
|
||||||
|
some custom function. Each of the list members has the following format:
|
||||||
|
(NAME PREDICATE-FUNC PARAM-FUNC)
|
||||||
|
* NAME is the name of the predicate function, and the first character
|
||||||
|
is the shortcut (so keep those unique).
|
||||||
|
* PREDICATE-FUNC is a function that takes to parameters, MSG and (optionally) PARAM,
|
||||||
|
and should return non-nil when there's a match.
|
||||||
|
* PARAM-FUNC is function that is evaluated once, and its value is then passed to
|
||||||
|
PREDICATE-FUNC as PARAM. This is useful for getting user-input.")
|
||||||
|
|
||||||
(defvar mu4e-headers-sortfield 'date
|
(defvar mu4e-headers-sortfield 'date
|
||||||
"Field to sort the headers by. Field must be a symbol, one of:
|
"Field to sort the headers by. Field must be a symbol, one of:
|
||||||
date, subject, size, prio, from, to.")
|
date, subject, size, prio, from, to.")
|
||||||
@ -401,7 +421,7 @@ after the end of the search results."
|
|||||||
(define-key map (kbd "u") 'mu4e~headers-mark-unmark)
|
(define-key map (kbd "u") 'mu4e~headers-mark-unmark)
|
||||||
(define-key map (kbd "+") 'mu4e~headers-mark-flag)
|
(define-key map (kbd "+") 'mu4e~headers-mark-flag)
|
||||||
(define-key map (kbd "-") 'mu4e~headers-mark-unflag)
|
(define-key map (kbd "-") 'mu4e~headers-mark-unflag)
|
||||||
|
(define-key map (kbd "&") 'mu4e-headers-mark-custom)
|
||||||
(define-key map "m" 'mu4e-headers-mark-for-move-and-next)
|
(define-key map "m" 'mu4e-headers-mark-for-move-and-next)
|
||||||
|
|
||||||
(define-key map (kbd "*") 'mu4e~headers-mark-deferred)
|
(define-key map (kbd "*") 'mu4e~headers-mark-deferred)
|
||||||
@ -737,6 +757,16 @@ header."
|
|||||||
(defvar mu4e~headers-regexp-hist nil
|
(defvar mu4e~headers-regexp-hist nil
|
||||||
"History list of regexps used.")
|
"History list of regexps used.")
|
||||||
|
|
||||||
|
(defun mu4e~headers-mark-for-each-if (markpair mark-pred &optional param)
|
||||||
|
"Mark all headers for with predicate function MARK-PRED return
|
||||||
|
non-nil with MARKPAIR. MARK-PRED is function that takes two
|
||||||
|
arguments, MSG (the message at point) and PARAM (a user-specified
|
||||||
|
parameter). MARKPAIR is a cell (MARK . TARGET)."
|
||||||
|
(mu4e-headers-for-each
|
||||||
|
(lambda (msg)
|
||||||
|
(when (funcall mark-pred msg param)
|
||||||
|
(mu4e-mark-at-point (car markpair) (cdr markpair))))))
|
||||||
|
|
||||||
(defun mu4e-headers-mark-pattern ()
|
(defun mu4e-headers-mark-pattern ()
|
||||||
"Ask user for a kind of mark (move, delete etc.), a field to
|
"Ask user for a kind of mark (move, delete etc.), a field to
|
||||||
match and a regular expression to match with. Then, mark all
|
match and a regular expression to match with. Then, mark all
|
||||||
@ -750,8 +780,9 @@ matching messages with that mark."
|
|||||||
(pattern (read-string
|
(pattern (read-string
|
||||||
(mu4e-format "Regexp:")
|
(mu4e-format "Regexp:")
|
||||||
nil 'mu4e~headers-regexp-hist)))
|
nil 'mu4e~headers-regexp-hist)))
|
||||||
(mu4e-headers-for-each
|
(mu4e~headers-mark-for-each-if
|
||||||
(lambda (msg)
|
markpair
|
||||||
|
(lambda (msg param)
|
||||||
(let* ((do-mark) (value (mu4e-msg-field msg field)))
|
(let* ((do-mark) (value (mu4e-msg-field msg field)))
|
||||||
(setq do-mark
|
(setq do-mark
|
||||||
(if (member field '(:to :from :cc :bcc :reply-to))
|
(if (member field '(:to :from :cc :bcc :reply-to))
|
||||||
@ -759,10 +790,16 @@ matching messages with that mark."
|
|||||||
(let ((name (car contact)) (email (cdr contact)))
|
(let ((name (car contact)) (email (cdr contact)))
|
||||||
(or (and name (string-match pattern name))
|
(or (and name (string-match pattern name))
|
||||||
(and email (string-match pattern email))))) value)
|
(and email (string-match pattern email))))) value)
|
||||||
(string-match pattern (or value ""))))
|
(string-match pattern (or value "")))))))))
|
||||||
(when do-mark
|
|
||||||
(mu4e-mark-at-point (car markpair) (cdr markpair))))))))
|
|
||||||
|
|
||||||
|
(defun mu4e-headers-mark-custom ()
|
||||||
|
"Mark messages based on a user-provided predicate function."
|
||||||
|
(interactive)
|
||||||
|
(let* ((pred (mu4e-read-option "Match function: "
|
||||||
|
mu4e-headers-custom-markers))
|
||||||
|
(param (when (cdr pred) (eval (cdr pred))))
|
||||||
|
(markpair (mu4e~mark-get-markpair "Mark matched messages with: " t)))
|
||||||
|
(mu4e~headers-mark-for-each-if markpair (car pred) param)))
|
||||||
|
|
||||||
(defun mu4e~headers-get-thread-info (msg what)
|
(defun mu4e~headers-get-thread-info (msg what)
|
||||||
"Get WHAT (a symbol, either path or thread-id) for MSG."
|
"Get WHAT (a symbol, either path or thread-id) for MSG."
|
||||||
@ -863,8 +900,6 @@ to get it from; it's a symbol, either 'future or 'past."
|
|||||||
(pop mu4e~headers-query-future))))
|
(pop mu4e~headers-query-future))))
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
(defvar mu4e~headers-search-hist nil
|
(defvar mu4e~headers-search-hist nil
|
||||||
@ -1083,7 +1118,6 @@ maildir)."
|
|||||||
(mu4e-mark-handle-when-leaving)
|
(mu4e-mark-handle-when-leaving)
|
||||||
(mu4e-headers-search (concat "\"maildir:" maildir "\""))))
|
(mu4e-headers-search (concat "\"maildir:" maildir "\""))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-headers-split-view-resize (n)
|
(defun mu4e-headers-split-view-resize (n)
|
||||||
"In horizontal split-view, increase the number of lines shown by
|
"In horizontal split-view, increase the number of lines shown by
|
||||||
N; in vertical split-view, increase the number of columns shown by
|
N; in vertical split-view, increase the number of columns shown by
|
||||||
|
|||||||
@ -300,4 +300,5 @@ action', return nil means 'don't do anything'"
|
|||||||
(when (eq what 'apply)
|
(when (eq what 'apply)
|
||||||
(mu4e-mark-execute-all t))))))))
|
(mu4e-mark-execute-all t))))))))
|
||||||
|
|
||||||
|
|
||||||
(provide 'mu4e-mark)
|
(provide 'mu4e-mark)
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
(require 'html2text)
|
(require 'html2text)
|
||||||
(require 'mu4e-vars)
|
(require 'mu4e-vars)
|
||||||
(require 'doc-view)
|
(require 'doc-view)
|
||||||
|
(require 'org) ;; for org-parse-time-string
|
||||||
|
|
||||||
(defcustom mu4e-html2text-command nil
|
(defcustom mu4e-html2text-command nil
|
||||||
"Shell command that converts HTML from stdin into plain text on
|
"Shell command that converts HTML from stdin into plain text on
|
||||||
@ -104,7 +105,8 @@ User now will be presented with a list:
|
|||||||
(optionsstr
|
(optionsstr
|
||||||
(mapconcat
|
(mapconcat
|
||||||
(lambda (option)
|
(lambda (option)
|
||||||
(when (consp (cdr option))
|
;; try to detect old-style options...
|
||||||
|
(when (or (characterp (cdr option)) (null (cdr option)))
|
||||||
(error (concat "Please use the new format for options/actions; "
|
(error (concat "Please use the new format for options/actions; "
|
||||||
"see the manual")))
|
"see the manual")))
|
||||||
(let* ((kar (substring (car option) 0 1))
|
(let* ((kar (substring (car option) 0 1))
|
||||||
@ -325,8 +327,6 @@ http://cr.yp.to/proto/maildir.html "
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-display-size (size)
|
(defun mu4e-display-size (size)
|
||||||
"Get a string representation of SIZE (in bytes)."
|
"Get a string representation of SIZE (in bytes)."
|
||||||
(cond
|
(cond
|
||||||
@ -807,5 +807,12 @@ displaying it). Do _not_ bury the current buffer, though."
|
|||||||
(unless (one-window-p t)
|
(unless (one-window-p t)
|
||||||
(delete-window win)))))) nil t)))
|
(delete-window win)))))) nil t)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-get-time-date (prompt)
|
||||||
|
"Determine the emacs time value for the time/date entered by user
|
||||||
|
after PROMPT. Formats are all that are accepted by
|
||||||
|
`parse-time-string'."
|
||||||
|
(let ((timestr (read-string (mu4e-format "%s" prompt))))
|
||||||
|
(apply 'encode-time (org-parse-time-string timestr))))
|
||||||
|
|
||||||
(provide 'mu4e-utils)
|
(provide 'mu4e-utils)
|
||||||
|
|||||||
@ -423,9 +423,10 @@ is nil, and otherwise open it."
|
|||||||
|
|
||||||
(define-key map (kbd "<delete>") 'mu4e-view-mark-for-delete)
|
(define-key map (kbd "<delete>") 'mu4e-view-mark-for-delete)
|
||||||
(define-key map (kbd "<deletechar>") 'mu4e-mark-for-delete)
|
(define-key map (kbd "<deletechar>") 'mu4e-mark-for-delete)
|
||||||
(define-key map "D" 'mu4e-view-mark-for-delete)
|
(define-key map (kbd "D") 'mu4e-view-mark-for-delete)
|
||||||
(define-key map "m" 'mu4e-view-mark-for-move)
|
(define-key map (kbd "m") 'mu4e-view-mark-for-move)
|
||||||
|
(define-key map (kbd "&") 'mu4e-view-mark-custom)
|
||||||
|
|
||||||
(define-key map (kbd "+") 'mu4e-view-mark-flag)
|
(define-key map (kbd "+") 'mu4e-view-mark-flag)
|
||||||
(define-key map (kbd "-") 'mu4e-view-mark-unflag)
|
(define-key map (kbd "-") 'mu4e-view-mark-unflag)
|
||||||
|
|
||||||
@ -926,6 +927,10 @@ attachments) in response to a (mu4e~proc-extract 'temp ... )."
|
|||||||
(mu4e-mark-for-move-set)
|
(mu4e-mark-for-move-set)
|
||||||
(mu4e-mark-at-point mark)))))
|
(mu4e-mark-at-point mark)))))
|
||||||
|
|
||||||
|
(defun mu4e-view-mark-custom ()
|
||||||
|
"Run some custom mark function."
|
||||||
|
(mu4e~view-in-headers-context
|
||||||
|
(mu4e-headers-mark-custom)))
|
||||||
|
|
||||||
(defun mu4e~split-view-p ()
|
(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."
|
||||||
@ -983,8 +988,7 @@ user that unmarking only works in the header list."
|
|||||||
(mu4e~view-mark-set 'deferred)
|
(mu4e~view-mark-set 'deferred)
|
||||||
(mu4e-view-headers-next))
|
(mu4e-view-headers-next))
|
||||||
|
|
||||||
|
(defun mu4e-view-marked-execute ()
|
||||||
(defun mu4e-view-marked-execute ()
|
|
||||||
"Execute the marks."
|
"Execute the marks."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e~view-in-headers-context
|
(mu4e~view-in-headers-context
|
||||||
|
|||||||
@ -1235,6 +1235,7 @@ Marking can happen in both the @ref{Headers view} and the @ref{Message view}.
|
|||||||
* What to mark for::
|
* What to mark for::
|
||||||
* Executing the marks::
|
* Executing the marks::
|
||||||
* Leaving the headers buffer::
|
* Leaving the headers buffer::
|
||||||
|
* Custom mark functions::
|
||||||
* Some marking examples::
|
* Some marking examples::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@ -1302,6 +1303,48 @@ When you quit the buffer (for example, but doing a new search) with marks being
|
|||||||
present, @t{mu4e} asks you what to do with them, depending on the value of the
|
present, @t{mu4e} asks you what to do with them, depending on the value of the
|
||||||
variable @code{mu4e-headers-leave-behavior} -- see its documentation.
|
variable @code{mu4e-headers-leave-behavior} -- see its documentation.
|
||||||
|
|
||||||
|
@node Custom mark functions
|
||||||
|
@section Custom mark functions
|
||||||
|
|
||||||
|
Sometimes, the built-in functions to mark messages may not be sufficient for
|
||||||
|
your needs. For this, @t{mu4e} offers an easy way to define your own custom
|
||||||
|
mark functions. You can choose one of the custom marker functions using
|
||||||
|
@key{&} in @ref{Headers view} and @ref{Message view}.
|
||||||
|
|
||||||
|
Custom mark functions should be appended to the list
|
||||||
|
@code{mu4e-headers-custom-markers}. Each of the elements of this list
|
||||||
|
('markers') is a list with three (or two) elements:
|
||||||
|
@itemize
|
||||||
|
@item The name of the marker - as short string describing this marker. The
|
||||||
|
first character of this string will also be its shortcut, so these should be
|
||||||
|
unique.
|
||||||
|
@item a predicate function taking two arguments @t{msg} and @t{param}- first,
|
||||||
|
@t{msg}, which is the message
|
||||||
|
plist (see @ref{The message s-expression}); second is a parameter provided by
|
||||||
|
the third of the marker elements (next item). The predicate function should
|
||||||
|
return non-nil if the messages matches.
|
||||||
|
@item (optionally) a function that is evaluated once, and its result is passed as a
|
||||||
|
parameter to the predicate function. This is useful to ask for user-input.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
So, let's look at an example: suppose we want to match all messages that have
|
||||||
|
more than @emph{n} recipients. We could do it like this:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(add-to-list 'mu4e-headers-custom-markers
|
||||||
|
'("More than n recipients"
|
||||||
|
(lambda (msg n) (> (+ (length (mu4e-msg-field msg :to))
|
||||||
|
(length (mu4e-msg-field msg :cc))) n))
|
||||||
|
(lambda () (read-number "Match messages with more recipients than: "))) t)
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
After evaluating this, pressing @key{&} should let you choose the custom
|
||||||
|
marker function, and ask you for the parameters.
|
||||||
|
|
||||||
|
As you can see, it's not very hard to define simple functions to match
|
||||||
|
messages. There are some more examples in the defaults for
|
||||||
|
`mu4e-headers-custom-markers'; see @file{mu4e-headers.el}.
|
||||||
|
|
||||||
@node Some marking examples
|
@node Some marking examples
|
||||||
@section Some marking examples
|
@section Some marking examples
|
||||||
|
|
||||||
@ -1316,6 +1359,7 @@ press @key{% + s hello RET}. Note, the menu system helps you here; all you
|
|||||||
need to remember is @key{%} for @code{mu4e-headers-mark-pattern}.
|
need to remember is @key{%} for @code{mu4e-headers-mark-pattern}.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
@node Actions
|
@node Actions
|
||||||
@chapter Actions
|
@chapter Actions
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user