mu4e: implement label updating through marks
Add support for updating label, using the marking interface. Add some helpers for dealing with (delta) labels Add keybindings to headers / views Update docs
This commit is contained in:
@ -52,6 +52,7 @@ mu4e_srcs=[
|
|||||||
'mu4e-headers.el',
|
'mu4e-headers.el',
|
||||||
'mu4e-helpers.el',
|
'mu4e-helpers.el',
|
||||||
'mu4e-icalendar.el',
|
'mu4e-icalendar.el',
|
||||||
|
'mu4e-labels.el',
|
||||||
'mu4e-lists.el',
|
'mu4e-lists.el',
|
||||||
'mu4e-main.el',
|
'mu4e-main.el',
|
||||||
'mu4e-mark.el',
|
'mu4e-mark.el',
|
||||||
@ -115,7 +116,6 @@ foreach src : mu4e_srcs
|
|||||||
'--eval', '(setq byte-compile-warnings \'(not obsolete))',
|
'--eval', '(setq byte-compile-warnings \'(not obsolete))',
|
||||||
'--eval', target_func,
|
'--eval', target_func,
|
||||||
'--funcall', 'batch-byte-compile', '@INPUT@'])
|
'--funcall', 'batch-byte-compile', '@INPUT@'])
|
||||||
|
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
# this depends on the above hack: all mu4e elisp files needs to be in builddir
|
# this depends on the above hack: all mu4e elisp files needs to be in builddir
|
||||||
|
|||||||
@ -913,6 +913,8 @@ COUNT is the number of messages found."
|
|||||||
(mu4e~headers-defun-mark-for untrash)
|
(mu4e~headers-defun-mark-for untrash)
|
||||||
(mu4e~headers-defun-mark-for unmark)
|
(mu4e~headers-defun-mark-for unmark)
|
||||||
(mu4e~headers-defun-mark-for unread)
|
(mu4e~headers-defun-mark-for unread)
|
||||||
|
(mu4e~headers-defun-mark-for label)
|
||||||
|
(mu4e~headers-defun-mark-for unlabel)
|
||||||
(mu4e~headers-defun-mark-for action)
|
(mu4e~headers-defun-mark-for action)
|
||||||
|
|
||||||
(declare-function mu4e-view-pipe "mu4e-view")
|
(declare-function mu4e-view-pipe "mu4e-view")
|
||||||
@ -964,6 +966,9 @@ COUNT is the number of messages found."
|
|||||||
|
|
||||||
(define-key map (kbd "?") #'mu4e-headers-mark-for-unread)
|
(define-key map (kbd "?") #'mu4e-headers-mark-for-unread)
|
||||||
(define-key map (kbd "!") #'mu4e-headers-mark-for-read)
|
(define-key map (kbd "!") #'mu4e-headers-mark-for-read)
|
||||||
|
(define-key map (kbd "l") #'mu4e-headers-mark-for-label)
|
||||||
|
(define-key map (kbd "L") #'mu4e-headers-mark-for-unlabel)
|
||||||
|
|
||||||
(define-key map (kbd "A") #'mu4e-headers-mark-for-action)
|
(define-key map (kbd "A") #'mu4e-headers-mark-for-action)
|
||||||
|
|
||||||
(define-key map (kbd "u") #'mu4e-headers-mark-for-unmark)
|
(define-key map (kbd "u") #'mu4e-headers-mark-for-unmark)
|
||||||
|
|||||||
153
mu4e/mu4e-labels.el
Normal file
153
mu4e/mu4e-labels.el
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
;;; mu4e-labels.el --- Dealing with labels -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2025 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.
|
||||||
|
|
||||||
|
;; mu4e 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.
|
||||||
|
|
||||||
|
;; mu4e 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 mu4e. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; In this file, add some helpers for dealing with message labels
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
(require 'mu4e-message)
|
||||||
|
(require 'mu4e-server)
|
||||||
|
(require 'mu4e-helpers)
|
||||||
|
|
||||||
|
(defconst mu4e-label-regex
|
||||||
|
(rx-let ((taboo (any cntrl blank "\"'\\/`$"))
|
||||||
|
(taboo1-extra (any "-+")))
|
||||||
|
(rx (seq
|
||||||
|
;; First character: base forbidden + extra chars
|
||||||
|
(not (or taboo taboo1-extra))
|
||||||
|
;; Rest: just base forbidden chars
|
||||||
|
(zero-or-more (not taboo)))))
|
||||||
|
"Unanchored regular expression matching a valid label.
|
||||||
|
|
||||||
|
Any character is allowed that is not a control-character, a
|
||||||
|
blank, or ASCII single/double quotes,backtick or
|
||||||
|
forward/backward slash; additionally, the first character cannot
|
||||||
|
be a \"+\" or \"-\", \"$\" either.")
|
||||||
|
|
||||||
|
(defun mu4e-label-validate (str)
|
||||||
|
"Validate label STR.
|
||||||
|
|
||||||
|
If STR is a valid label, return STR. Otherwise, raise an warning.
|
||||||
|
This function attempts to be a bit more informative than simply
|
||||||
|
checking a regular expression.
|
||||||
|
|
||||||
|
See `mu4e-label-regex' for the definition of the valid format."
|
||||||
|
(when (string-empty-p str) ;; i. must not be empty
|
||||||
|
(mu4e-warn "invalid: empty string"))
|
||||||
|
(let ((first (aref str 0)))
|
||||||
|
;; ii. must not start with + or -
|
||||||
|
(when (or (char-equal first ?+) (char-equal first ?-))
|
||||||
|
(mu4e-warn "invalid: starts with '%c'" first))
|
||||||
|
;; iii. check all characters a valid:
|
||||||
|
(seq-do (lambda (kar)
|
||||||
|
(unless (string-match-p mu4e-label-regex
|
||||||
|
(string ?_ kar))
|
||||||
|
(mu4e-warn "invalid: character '%c'" kar)))
|
||||||
|
str))
|
||||||
|
str)
|
||||||
|
|
||||||
|
(defun mu4e-label-parse-expr (expr)
|
||||||
|
"Parse a single delta expression EXPR.
|
||||||
|
|
||||||
|
If EXPR is non-empty, raises an error if EXPR is not a valid
|
||||||
|
delta. Otherwise, returns EXPR with extra whitespace removed.
|
||||||
|
|
||||||
|
If STR is empty, return nil."
|
||||||
|
(let ((op (aref expr 0))
|
||||||
|
(label (substring expr 1)))
|
||||||
|
(unless (or (char-equal op ?+) (char-equal op ?-))
|
||||||
|
(mu4e-warn "invalid: delta-expression must start with '+' or '-'"))
|
||||||
|
(concat (char-to-string op)
|
||||||
|
(mu4e-label-validate label))))
|
||||||
|
|
||||||
|
(defun mu4e-label-parse-exprs (exprs)
|
||||||
|
"Parse a string EXPRS with deltas to a string.
|
||||||
|
|
||||||
|
If EXPRS is non-empty, raises an error if EXPRS is invalid.
|
||||||
|
Otherwise, return EXPRS with extra whitespace removed.
|
||||||
|
|
||||||
|
If EXPRS is empty, return nil."
|
||||||
|
(mapconcat #'mu4e-label-parse-expr (split-string exprs) " "))
|
||||||
|
|
||||||
|
(defvar mu4e-labels-list nil "Cached list of labels.")
|
||||||
|
|
||||||
|
(defun mu4e--labels-completion-at-point ()
|
||||||
|
"Provide completion when entering a label delta expressions."
|
||||||
|
(cond
|
||||||
|
((not (looking-back "[^ \t]*" nil))
|
||||||
|
(let ((bounds (bounds-of-thing-at-point 'word)))
|
||||||
|
(list (or (car bounds) (point))
|
||||||
|
(or (cdr bounds) (point)))))
|
||||||
|
((looking-back
|
||||||
|
(rx (any "+" "-")
|
||||||
|
(group
|
||||||
|
(opt (regex mu4e-label-regex)))) nil)
|
||||||
|
(list (match-beginning 1)
|
||||||
|
(match-end 1)
|
||||||
|
mu4e-labels-list))))
|
||||||
|
|
||||||
|
(defvar mu4e-minibuffer-label-expr-map
|
||||||
|
(let ((map (copy-keymap minibuffer-local-map)))
|
||||||
|
(define-key map (kbd "TAB") #'completion-at-point)
|
||||||
|
map)
|
||||||
|
"The keymap for reading label delta expression.")
|
||||||
|
|
||||||
|
(defun mu4e-labels-delta-read ()
|
||||||
|
"Ask for a labels delta expression."
|
||||||
|
(minibuffer-with-setup-hook
|
||||||
|
(lambda ()
|
||||||
|
(setq-local completion-at-point-functions
|
||||||
|
#'mu4e--labels-completion-at-point)
|
||||||
|
(use-local-map mu4e-minibuffer-label-expr-map))
|
||||||
|
(mu4e-label-parse-exprs
|
||||||
|
(read-string "Label delta expression: "))))
|
||||||
|
|
||||||
|
(defun mu4e--labels-update-server (docid expr)
|
||||||
|
"Tell the server to update message with DOCID with EXPR.
|
||||||
|
EXPR is a label delta-expression, such as \"+foo -bar\".
|
||||||
|
|
||||||
|
Update the label cache while doing so."
|
||||||
|
;; update the cache
|
||||||
|
(let ((expr (mu4e-label-parse-exprs expr))
|
||||||
|
(labels ;; the list of labels without +/- prefix
|
||||||
|
(seq-map (lambda (pmlabel)
|
||||||
|
(substring pmlabel 1))
|
||||||
|
(split-string expr " "))))
|
||||||
|
;; don't care about dups etc.; the list
|
||||||
|
;; will be replaced by a fresh server-side one, after
|
||||||
|
;; update / restart
|
||||||
|
(setq mu4e-labels-list
|
||||||
|
(append labels mu4e-labels-list))
|
||||||
|
;; update the server
|
||||||
|
(mu4e--server-label docid expr)))
|
||||||
|
|
||||||
|
(defun mu4e--labels-clear-server (docid)
|
||||||
|
"Clear all labels from message with DOCID."
|
||||||
|
;; update the server
|
||||||
|
;; '-*' is not a valid label, but special-cased
|
||||||
|
;; on the server-side
|
||||||
|
(mu4e--server-label docid "-*"))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'mu4e-labels)
|
||||||
|
;;; mu4e-labels.el ends here
|
||||||
@ -1,6 +1,6 @@
|
|||||||
;;; mu4e-mark.el --- Marking messages -*- lexical-binding: t -*-
|
;;; mu4e-mark.el --- Marking messages -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2011-2024 Dirk-Jan C. Binnema
|
;; Copyright (C) 2011-2025 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
@ -30,6 +30,7 @@
|
|||||||
(require 'mu4e-server)
|
(require 'mu4e-server)
|
||||||
(require 'mu4e-message)
|
(require 'mu4e-message)
|
||||||
(require 'mu4e-folders)
|
(require 'mu4e-folders)
|
||||||
|
(require 'mu4e-labels)
|
||||||
|
|
||||||
;; keep byte-compiler happy
|
;; keep byte-compiler happy
|
||||||
(declare-function mu4e~headers-mark "mu4e-headers")
|
(declare-function mu4e~headers-mark "mu4e-headers")
|
||||||
@ -155,6 +156,11 @@ The current buffer must be either a headers or view buffer."
|
|||||||
:show-target (lambda (target) "flag")
|
:show-target (lambda (target) "flag")
|
||||||
:action (lambda (docid msg target)
|
:action (lambda (docid msg target)
|
||||||
(mu4e--server-move docid nil "+F-u-N")))
|
(mu4e--server-move docid nil "+F-u-N")))
|
||||||
|
(unflag
|
||||||
|
:char ("-" . "➖")
|
||||||
|
:prompt "-unflag"
|
||||||
|
:show-target (lambda (target) "unflag")
|
||||||
|
:action (lambda (docid msg target) (mu4e--server-move docid nil "-F-N")))
|
||||||
(move
|
(move
|
||||||
:char ("m" . "▷")
|
:char ("m" . "▷")
|
||||||
:prompt "move"
|
:prompt "move"
|
||||||
@ -166,6 +172,12 @@ The current buffer must be either a headers or view buffer."
|
|||||||
:prompt "!read"
|
:prompt "!read"
|
||||||
:show-target (lambda (target) "read")
|
:show-target (lambda (target) "read")
|
||||||
:action (lambda (docid msg target) (mu4e--server-move docid nil "+S-u-N")))
|
:action (lambda (docid msg target) (mu4e--server-move docid nil "+S-u-N")))
|
||||||
|
(unread
|
||||||
|
:char ("?" . "◻")
|
||||||
|
:prompt "?unread"
|
||||||
|
:show-target (lambda (target) "unread")
|
||||||
|
:action (lambda (docid msg target) (mu4e--server-move docid nil "-S+u-N")))
|
||||||
|
|
||||||
(trash
|
(trash
|
||||||
:char ("d" . "▼")
|
:char ("d" . "▼")
|
||||||
:prompt "dtrash"
|
:prompt "dtrash"
|
||||||
@ -174,25 +186,29 @@ The current buffer must be either a headers or view buffer."
|
|||||||
(mu4e--server-move docid
|
(mu4e--server-move docid
|
||||||
(mu4e--mark-check-target target)
|
(mu4e--mark-check-target target)
|
||||||
(if mu4e-trash-without-flag "-N" "+T-N"))))
|
(if mu4e-trash-without-flag "-N" "+T-N"))))
|
||||||
(unflag
|
|
||||||
:char ("-" . "➖")
|
|
||||||
:prompt "-unflag"
|
|
||||||
:show-target (lambda (target) "unflag")
|
|
||||||
:action (lambda (docid msg target) (mu4e--server-move docid nil "-F-N")))
|
|
||||||
(untrash
|
(untrash
|
||||||
:char ("=" . "▲")
|
:char ("=" . "▲")
|
||||||
:prompt "=untrash"
|
:prompt "=untrash"
|
||||||
:show-target (lambda (target) "untrash")
|
:show-target (lambda (target) "untrash")
|
||||||
:action (lambda (docid msg target) (mu4e--server-move docid nil "-T")))
|
:action (lambda (docid msg target) (mu4e--server-move docid nil "-T")))
|
||||||
(unread
|
|
||||||
:char ("?" . "◻")
|
(label
|
||||||
:prompt "?unread"
|
:char ("l" . "🏷")
|
||||||
:show-target (lambda (target) "unread")
|
:prompt "label"
|
||||||
:action (lambda (docid msg target) (mu4e--server-move docid nil "-S+u-N")))
|
:ask-target mu4e-labels-delta-read
|
||||||
|
:action (lambda (docid msg expr)
|
||||||
|
(mu4e--labels-update-server docid expr)))
|
||||||
|
(unlabel
|
||||||
|
:char ("L" . "∅")
|
||||||
|
:prompt "unlabel"
|
||||||
|
:show-target (lambda (target) "clear labels")
|
||||||
|
:action (lambda (docid msg expr)
|
||||||
|
(mu4e--labels-clear-server docid)))
|
||||||
(unmark
|
(unmark
|
||||||
:char " "
|
:char " "
|
||||||
:prompt "unmark"
|
:prompt "unmark"
|
||||||
:action (mu4e-error "No action for unmarking"))
|
:action (mu4e-error "No action for unmarking"))
|
||||||
|
|
||||||
(action
|
(action
|
||||||
:char ( "a" . "◯")
|
:char ( "a" . "◯")
|
||||||
:prompt "action"
|
:prompt "action"
|
||||||
@ -251,6 +267,8 @@ The following marks are available, and the corresponding props:
|
|||||||
`untrash' n remove the `trashed' flag from a message
|
`untrash' n remove the `trashed' flag from a message
|
||||||
`unmark' n unmark this message
|
`unmark' n unmark this message
|
||||||
`unread' n mark the message as unread
|
`unread' n mark the message as unread
|
||||||
|
`label' y (re)label the message
|
||||||
|
`unlabel' n clear all labels
|
||||||
`action' y mark the message for some action."
|
`action' y mark the message for some action."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((msg (mu4e-message-at-point))
|
(let* ((msg (mu4e-message-at-point))
|
||||||
@ -311,6 +329,11 @@ The following marks are available, and the corresponding props:
|
|||||||
(when (mu4e-create-maildir-maybe fulltarget)
|
(when (mu4e-create-maildir-maybe fulltarget)
|
||||||
target)))
|
target)))
|
||||||
|
|
||||||
|
(defun mu4e--mark-get-labels-target ()
|
||||||
|
"Ask for a labels expression."
|
||||||
|
(let* ((exprs (read-from-minibuffer "Label expression: ")))
|
||||||
|
(mu4e-label-parse-exprs exprs)))
|
||||||
|
|
||||||
(defun mu4e--mark-ask-target (mark)
|
(defun mu4e--mark-ask-target (mark)
|
||||||
"Ask the target for MARK, if the user should be asked the target."
|
"Ask the target for MARK, if the user should be asked the target."
|
||||||
(let ((getter (plist-get (cdr (assq mark mu4e-marks)) :ask-target)))
|
(let ((getter (plist-get (cdr (assq mark mu4e-marks)) :ask-target)))
|
||||||
@ -431,7 +454,8 @@ If NO-CONFIRMATION is non-nil, don't ask user for confirmation."
|
|||||||
(message nil)))))
|
(message nil)))))
|
||||||
|
|
||||||
(defun mu4e-mark-unmark-all (&optional no-confirmation)
|
(defun mu4e-mark-unmark-all (&optional no-confirmation)
|
||||||
"Unmark all marked messages."
|
"Unmark all marked messages.
|
||||||
|
If NO-CONFIRMATION is non-nil, do not ask for confirmation."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e--mark-in-context
|
(mu4e--mark-in-context
|
||||||
(when (zerop (mu4e-mark-marks-num))
|
(when (zerop (mu4e-mark-marks-num))
|
||||||
|
|||||||
@ -154,9 +154,6 @@ but also manually invoked searches."
|
|||||||
:type 'hook
|
:type 'hook
|
||||||
:group 'mu4e-search)
|
:group 'mu4e-search)
|
||||||
|
|
||||||
(defvar mu4e-labels-list nil
|
|
||||||
"Cached list of labels.")
|
|
||||||
|
|
||||||
;; Internals
|
;; Internals
|
||||||
|
|
||||||
;;; History
|
;;; History
|
||||||
|
|||||||
@ -708,6 +708,10 @@ the directory time stamp."
|
|||||||
:lazy-check ,(and lazy-check t)))
|
:lazy-check ,(and lazy-check t)))
|
||||||
(setq mu4e--server-indexing t)) ;; remember we're indexing.
|
(setq mu4e--server-indexing t)) ;; remember we're indexing.
|
||||||
|
|
||||||
|
(defun mu4e--server-label (docid delta-expr)
|
||||||
|
"Apply the label DELTA-EXPR to the message with DOCID."
|
||||||
|
(mu4e--server-call-mu `(label :docid ,docid :labels ,delta-expr)))
|
||||||
|
|
||||||
(defun mu4e--server-mkdir (path &optional update)
|
(defun mu4e--server-mkdir (path &optional update)
|
||||||
"Create a new maildir-directory at file system PATH.
|
"Create a new maildir-directory at file system PATH.
|
||||||
When UPDATE is non-nil, send a update when completed.
|
When UPDATE is non-nil, send a update when completed.
|
||||||
|
|||||||
@ -411,6 +411,8 @@ list."
|
|||||||
(mu4e--view-defun-mark-for unread)
|
(mu4e--view-defun-mark-for unread)
|
||||||
(mu4e--view-defun-mark-for trash)
|
(mu4e--view-defun-mark-for trash)
|
||||||
(mu4e--view-defun-mark-for untrash)
|
(mu4e--view-defun-mark-for untrash)
|
||||||
|
(mu4e--view-defun-mark-for label)
|
||||||
|
(mu4e--view-defun-mark-for unlabel)
|
||||||
|
|
||||||
(defun mu4e-view-marked-execute ()
|
(defun mu4e-view-marked-execute ()
|
||||||
"Execute the marked actions."
|
"Execute the marked actions."
|
||||||
@ -1008,6 +1010,9 @@ This is useful for advising some Gnus-functionality that does not work in mu4e."
|
|||||||
(define-key map (kbd "=") #'mu4e-view-mark-for-untrash)
|
(define-key map (kbd "=") #'mu4e-view-mark-for-untrash)
|
||||||
(define-key map (kbd "&") #'mu4e-view-mark-custom)
|
(define-key map (kbd "&") #'mu4e-view-mark-custom)
|
||||||
|
|
||||||
|
(define-key map (kbd "l") #'mu4e-view-mark-for-label)
|
||||||
|
(define-key map (kbd "L") #'mu4e-view-mark-for-unlabel)
|
||||||
|
|
||||||
(define-key map (kbd "*") #'mu4e-view-mark-for-something)
|
(define-key map (kbd "*") #'mu4e-view-mark-for-something)
|
||||||
(define-key map (kbd "<kp-multiply>") #'mu4e-view-mark-for-something)
|
(define-key map (kbd "<kp-multiply>") #'mu4e-view-mark-for-something)
|
||||||
(define-key map (kbd "<insert>") #'mu4e-view-mark-for-something)
|
(define-key map (kbd "<insert>") #'mu4e-view-mark-for-something)
|
||||||
|
|||||||
111
mu4e/mu4e.texi
111
mu4e/mu4e.texi
@ -196,9 +196,10 @@ following information:
|
|||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@item What did you expect or wish to happen? what actually happened?
|
@item What did you expect or wish to happen? what actually happened?
|
||||||
Please describe in detail what you saw. Also, try some related scenarios and
|
Please describe in detail what you saw; what did you expect to happen and what
|
||||||
whether the problem either @emph{always} happens, or only @emph{sometimes}.
|
actually happened? Also, please try some related scenarios and whether the
|
||||||
E.g., it might happen with only one particular type of message
|
problem either @emph{always} happens, or only @emph{sometimes}. E.g., the issue
|
||||||
|
might happen with only one particular type of message
|
||||||
@item Provide some exact steps to reproduce?
|
@item Provide some exact steps to reproduce?
|
||||||
In particular, some minimal steps, starting from @t{emacs -Q} and with minimal
|
In particular, some minimal steps, starting from @t{emacs -Q} and with minimal
|
||||||
configuration. If the problem is easily producible, it may be easily fixable as
|
configuration. If the problem is easily producible, it may be easily fixable as
|
||||||
@ -215,7 +216,6 @@ reproducing your problem, not the ``remix'' version that some Emacs
|
|||||||
In general, imagine you would be the person receiving the bug-report, and think
|
In general, imagine you would be the person receiving the bug-report, and think
|
||||||
about the information you would need to diagnose the problem.
|
about the information you would need to diagnose the problem.
|
||||||
|
|
||||||
|
|
||||||
@node Getting started
|
@node Getting started
|
||||||
@chapter Getting started
|
@chapter Getting started
|
||||||
|
|
||||||
@ -1046,6 +1046,7 @@ DEL,D mark for complete deletion
|
|||||||
m mark for moving to another maildir folder
|
m mark for moving to another maildir folder
|
||||||
r mark for refiling
|
r mark for refiling
|
||||||
+,- mark for flagging/unflagging
|
+,- mark for flagging/unflagging
|
||||||
|
l mark for labels
|
||||||
?,! mark message as unread, read
|
?,! mark message as unread, read
|
||||||
|
|
||||||
u unmark message at point
|
u unmark message at point
|
||||||
@ -1090,11 +1091,13 @@ Some keybindings are available through minor modes:
|
|||||||
@node HV Marking
|
@node HV Marking
|
||||||
@section Marking
|
@section Marking
|
||||||
|
|
||||||
You can @emph{mark} messages for a certain action, such as deletion or
|
You can @emph{mark} messages for a certain action, such as deletion or move or
|
||||||
move. After one or more messages are marked, you can then execute
|
changing the labels.
|
||||||
|
|
||||||
|
After one or more messages are marked, you can then execute
|
||||||
(@code{mu4e-mark-execute-all}, @key{x}) these actions. This two-step
|
(@code{mu4e-mark-execute-all}, @key{x}) these actions. This two-step
|
||||||
mark-execute sequence is similar to what e.g. @t{dired} does. It is how
|
mark-execute sequence is similar to what e.g. @t{dired} does. It is how @t{mu4e}
|
||||||
@t{mu4e} tries to be as quick as possible, while avoiding accidents.
|
tries to be as quick as possible, while avoiding accidents.
|
||||||
|
|
||||||
The mark/unmark commands support the @emph{region} (i.e., ``selection'')
|
The mark/unmark commands support the @emph{region} (i.e., ``selection'')
|
||||||
--- so, for example, if you select some messages and press @key{DEL},
|
--- so, for example, if you select some messages and press @key{DEL},
|
||||||
@ -1423,6 +1426,7 @@ d mark for moving to the trash folder
|
|||||||
DEL,D mark for complete deletion
|
DEL,D mark for complete deletion
|
||||||
m mark for moving to another maildir folder
|
m mark for moving to another maildir folder
|
||||||
r mark for refiling
|
r mark for refiling
|
||||||
|
l mark for labels
|
||||||
+,- mark for flagging/unflagging
|
+,- mark for flagging/unflagging
|
||||||
|
|
||||||
u unmark message at point
|
u unmark message at point
|
||||||
@ -2431,7 +2435,7 @@ Note, messages are considered duplicates when they have the same
|
|||||||
In @t{mu4e}, the common way to do things with messages is a two-step process -
|
In @t{mu4e}, the common way to do things with messages is a two-step process -
|
||||||
first you @emph{mark} them for a certain action, then you @emph{execute}
|
first you @emph{mark} them for a certain action, then you @emph{execute}
|
||||||
(@key{x}) those marks. This is similar to the way @t{dired} operates. Marking
|
(@key{x}) those marks. This is similar to the way @t{dired} operates. Marking
|
||||||
can happen in both the @ref{Headers view} and the @ref{Message view}.
|
can happen from both the @ref{Headers view} and the @ref{Message view}.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Marking messages::Selecting message do something with them
|
* Marking messages::Selecting message do something with them
|
||||||
@ -2472,22 +2476,84 @@ messages.
|
|||||||
@verbatim
|
@verbatim
|
||||||
mark for/as | keybinding | description
|
mark for/as | keybinding | description
|
||||||
-------------+-------------+------------------------------
|
-------------+-------------+------------------------------
|
||||||
'something' | *, <insert> | mark now, decide later
|
|
||||||
delete | D, <delete> | delete
|
delete | D, <delete> | delete
|
||||||
flag | + | mark as 'flagged' ('starred')
|
|
||||||
move | m | move to some maildir
|
move | m | move to some maildir
|
||||||
read | ! | mark as read
|
|
||||||
refile | r | mark for refiling
|
refile | r | mark for refiling
|
||||||
|
-------------+-------------+------------------------------
|
||||||
|
flag | + | mark as 'flagged' ('starred')
|
||||||
|
unflag | - | remove 'flagged' mark
|
||||||
|
read | ! | mark as read
|
||||||
|
unread | ? | marks as unread
|
||||||
trash | d | move to the trash folder
|
trash | d | move to the trash folder
|
||||||
untrash | = | remove 'trash' flag
|
untrash | = | remove 'trash' flag
|
||||||
unflag | - | remove 'flagged' mark
|
-------------+-------------+------------------------------
|
||||||
|
label | l | change the labels
|
||||||
|
unlabel | L | clear all labels
|
||||||
|
action | a | apply some action
|
||||||
|
'something' | *, <insert> | mark now, decide later
|
||||||
|
-------------+-------------------------------------------
|
||||||
unmark | u | remove mark at point
|
unmark | u | remove mark at point
|
||||||
unmark all | U | remove all marks
|
unmark all | U | remove all marks
|
||||||
unread | ? | marks as unread
|
-------------+-------------------------------------------
|
||||||
action | a | apply some action
|
|
||||||
@end verbatim
|
@end verbatim
|
||||||
@end cartouche
|
@end cartouche
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item @emph{delete} deletes the message from database and file-system
|
||||||
|
@item @emph{move} moves the message to some different maildir
|
||||||
|
@item @emph{refile} is similar @emph{move}, but determines the target maildir based
|
||||||
|
on the characteristics of the message; this is very powerful. See
|
||||||
|
@code{mu4e-refile-folder} and especially @xref{Smart refiling} for details.
|
||||||
|
@item @emph{flag}/@emph{unflag}, @emph{read}/@emph{unread} and @emph{trash}/@emph{untrash}
|
||||||
|
set or unset the corresponding Maildir flags
|
||||||
|
@item @emph{label} lets you enter a label delta expression which gets applied; see below
|
||||||
|
@item @emph{unlabel} lets you clear @emph{all} labels; see below
|
||||||
|
@item @emph{action} lets you apply some pre-defined action on the message, as per @code{mu4e-headers-actions}
|
||||||
|
@item @emph{'something'} marks the message for ``something'', and then decide
|
||||||
|
later what this something should be; see below
|
||||||
|
@item @emph{unmark} and @emph{unmark all} are ``meta'' marks, which remove the mark from the currently selected message(s) or all
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@node Applying and clearing labels
|
||||||
|
@subsection Applying and clearing labels
|
||||||
|
@cindex labels
|
||||||
|
|
||||||
|
The @t{label} mark lets you apply @emph{labels} to messages, which are short
|
||||||
|
strings to attach to this message which you can query using the @t{label:}
|
||||||
|
field. To see them in your headers / message views, you need to add the field to
|
||||||
|
the @code{mu4e-headers-fields} and @code{mu4e-view-fields}, respectively.
|
||||||
|
|
||||||
|
To change the labels for some message, you specify a @emph{label expression},
|
||||||
|
which consists of a space-separated sequence of labels, each prefixed either
|
||||||
|
with a @t{+} to add the label or @t{-} to remove it.
|
||||||
|
|
||||||
|
For instance, to remove the @t{boring} label and add @t{urgent} from the message
|
||||||
|
at point or the messages in region, press @kbd{l} and enter:
|
||||||
|
@example
|
||||||
|
+urgent -boring
|
||||||
|
@end example
|
||||||
|
|
||||||
|
For @emph{clearing all labels}, you mark with @kbd{L} ('unlabel').
|
||||||
|
|
||||||
|
You can search for labels using the @t{label:} field. For instance,
|
||||||
|
@t{label:urgent} retrieves all messages labeled @t{urgent}.
|
||||||
|
|
||||||
|
It is important to note that the labels are only stored in the database (the
|
||||||
|
message files are not changed). This means that you loose this information when
|
||||||
|
you remove the database and recrate it; it is however possible to @emph{export}
|
||||||
|
the labels and re-@emph{import} them later; see the @t{mu-label} man-page for
|
||||||
|
further details.
|
||||||
|
|
||||||
|
@subsection Doing @emph{something}
|
||||||
|
|
||||||
|
@t{something} is a special kind of mark; you can use it to mark messages for
|
||||||
|
`something', and then decide later what the `something' should be@footnote{This
|
||||||
|
kind of `deferred marking' is similar to the facility in @t{dired}, @t{midnight
|
||||||
|
commander} (@url{https://www.midnight-commander.org/}) and the like, and uses
|
||||||
|
the same key binding (@key{insert}).} Later, you can set the actual mark using
|
||||||
|
@kbd{M-x mu4e-mark-resolve-deferred-marks} (@key{#}). Alternatively, @t{mu4e}
|
||||||
|
will ask you when you try to execute the marks (@key{x}).
|
||||||
|
|
||||||
After marking a message, the left-most columns in the headers view indicate
|
After marking a message, the left-most columns in the headers view indicate
|
||||||
the kind of mark. This is informative, but if you mark many (say, thousands)
|
the kind of mark. This is informative, but if you mark many (say, thousands)
|
||||||
messages, this slows things down significantly@footnote{this uses an
|
messages, this slows things down significantly@footnote{this uses an
|
||||||
@ -2495,15 +2561,6 @@ Emacs feature called @emph{overlays}, which are slow when used a lot
|
|||||||
in a buffer}. For this reason, you can disable this by setting
|
in a buffer}. For this reason, you can disable this by setting
|
||||||
@code{mu4e-headers-show-target} to @code{nil}.
|
@code{mu4e-headers-show-target} to @code{nil}.
|
||||||
|
|
||||||
@t{something} is a special kind of mark; you can use it to mark messages
|
|
||||||
for `something', and then decide later what the `something' should
|
|
||||||
be@footnote{This kind of `deferred marking' is similar to the facility
|
|
||||||
in @t{dired}, @t{midnight commander}
|
|
||||||
(@url{https://www.midnight-commander.org/}) and the like, and uses the
|
|
||||||
same key binding (@key{insert}).} Later, you can set the actual mark
|
|
||||||
using @kbd{M-x mu4e-mark-resolve-deferred-marks}
|
|
||||||
(@key{#}). Alternatively, @t{mu4e} will ask you when you try to execute
|
|
||||||
the marks (@key{x}).
|
|
||||||
|
|
||||||
@node Executing the marks
|
@node Executing the marks
|
||||||
@section Executing the marks
|
@section Executing the marks
|
||||||
@ -2598,7 +2655,6 @@ messages. There are more examples in the defaults for
|
|||||||
@code{mu4e-headers-custom-markers}; see @file{mu4e-headers.el} and see
|
@code{mu4e-headers-custom-markers}; see @file{mu4e-headers.el} and see
|
||||||
@ref{Extending mu4e} for general information about writing your own functions.
|
@ref{Extending mu4e} for general information about writing your own functions.
|
||||||
|
|
||||||
|
|
||||||
@node Adding a new kind of mark
|
@node Adding a new kind of mark
|
||||||
@section Adding a new kind of mark
|
@section Adding a new kind of mark
|
||||||
|
|
||||||
@ -3128,7 +3184,10 @@ viewing messages in an external web browser or tagging.
|
|||||||
It is easy to add such actions to your configuration; for instance, to enable
|
It is easy to add such actions to your configuration; for instance, to enable
|
||||||
@emph{tagging}@footnote{@t{mu4e} does not offer tagging by default since it
|
@emph{tagging}@footnote{@t{mu4e} does not offer tagging by default since it
|
||||||
mutates the message files, something that @t{mu}/@t{mu4e} generally try to
|
mutates the message files, something that @t{mu}/@t{mu4e} generally try to
|
||||||
avoid.} both in the message view and headers view, you could add:
|
avoid. An alternative to tagging is @emph{labeling}, @xref{Applying and clearing
|
||||||
|
labels}
|
||||||
|
|
||||||
|
} both in the message view and headers view, you could add:
|
||||||
@lisp
|
@lisp
|
||||||
(add-to-list 'mu4e-headers-actions
|
(add-to-list 'mu4e-headers-actions
|
||||||
'("Tag message" . mu4e-action-retag-message))
|
'("Tag message" . mu4e-action-retag-message))
|
||||||
|
|||||||
Reference in New Issue
Block a user