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:
Dirk-Jan C. Binnema
2025-08-27 21:45:37 +03:00
committed by Seth Ladygo
parent bf2f4ce57d
commit a2b1a7cc31
8 changed files with 289 additions and 42 deletions

View File

@ -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

View File

@ -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
View 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

View File

@ -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))

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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))