mirror of https://github.com/djcb/mu.git
mu4e: implement context-policies
Allow setting a policy about what context to choose when starting mu4e and composing a message. Basically: When you have defined contexts and you start mu4e it decides which context to use based on the variable `mu4e-context-policy'; similarly, when you compose a new message, the context is determined using `mu4e-compose-context-policy'. These policies can be one of the following: - a symbol always-ask: unconditionally ask the user what context to pick The other choices only apply if none of the context matches (i.e., if none of the contexts' match-functions returns t: - symbol ask: ask the user - a symbol pick-first: pick the first context - nil: don't change the context
This commit is contained in:
parent
4bca0d0739
commit
113c024632
|
@ -112,12 +112,34 @@ for example:
|
||||||
|
|
||||||
The various `message-' functions from `message-mode' are available
|
The various `message-' functions from `message-mode' are available
|
||||||
for querying the message information."
|
for querying the message information."
|
||||||
:type '(choice (const :tag "move message to mu4e-sent-folder" sent)
|
:type '(choice (const :tag "move message to mu4e-sent-folder" sent)
|
||||||
(const :tag "move message to mu4e-trash-folder" trash)
|
(const :tag "move message to mu4e-trash-folder" trash)
|
||||||
(const :tag "delete message" delete))
|
(const :tag "delete message" delete))
|
||||||
:safe 'symbolp
|
:safe 'symbolp
|
||||||
:group 'mu4e-compose)
|
:group 'mu4e-compose)
|
||||||
|
|
||||||
|
|
||||||
|
(defcustom mu4e-compose-context-policy nil
|
||||||
|
"Determines how mu4e should determine the context when composing a new message.
|
||||||
|
|
||||||
|
If POLICY is
|
||||||
|
'always-ask, we ask the user unconditionally.
|
||||||
|
|
||||||
|
In all other cases, if any context matches (using its match
|
||||||
|
function), this context is returned. If none of the contexts
|
||||||
|
match, POLICY determines what to do:
|
||||||
|
|
||||||
|
- pick-first: pick the first of the contexts available
|
||||||
|
- ask: ask the user
|
||||||
|
- otherwise, return nil. Effectively, this leaves the current context in place."
|
||||||
|
:type '(choice
|
||||||
|
(const :tag "Always ask what context to use" 'always-ask)
|
||||||
|
(const :tag "Ask if none of the contexts match" 'ask)
|
||||||
|
(const :tag "Pick the default (first) context if none match" 'pick-first)
|
||||||
|
(const :tag "Don't change the context when none match" nil)
|
||||||
|
:safe 'symbolp
|
||||||
|
:group 'mu4e-compose))
|
||||||
|
|
||||||
(defcustom mu4e-compose-pre-hook nil
|
(defcustom mu4e-compose-pre-hook nil
|
||||||
"Hook run just *before* message composition starts.
|
"Hook run just *before* message composition starts.
|
||||||
If the compose-type is either 'reply' or 'forward', the variable
|
If the compose-type is either 'reply' or 'forward', the variable
|
||||||
|
@ -370,10 +392,9 @@ tempfile)."
|
||||||
;; message being forwarded or replied to, otherwise it is nil.
|
;; message being forwarded or replied to, otherwise it is nil.
|
||||||
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
|
(set (make-local-variable 'mu4e-compose-parent-message) original-msg)
|
||||||
(put 'mu4e-compose-parent-message 'permanent-local t)
|
(put 'mu4e-compose-parent-message 'permanent-local t)
|
||||||
(let ((context (mu4e-context-determine mu4e-compose-parent-message)))
|
;; maybe switch the context
|
||||||
(if context
|
(mu4e~context-autoswitch mu4e-compose-parent-message
|
||||||
(mu4e-context-switch nil (mu4e-context-name context))
|
mu4e-compose-context-policy)
|
||||||
(when mu4e-contexts (mu4e-context-switch nil))))
|
|
||||||
(run-hooks 'mu4e-compose-pre-hook)
|
(run-hooks 'mu4e-compose-pre-hook)
|
||||||
|
|
||||||
;; this opens (or re-opens) a messages with all the basic headers set.
|
;; this opens (or re-opens) a messages with all the basic headers set.
|
||||||
|
|
|
@ -100,13 +100,13 @@ non-nil."
|
||||||
(mu4e-message "Switched context to %s" (mu4e-context-name context)))
|
(mu4e-message "Switched context to %s" (mu4e-context-name context)))
|
||||||
context))
|
context))
|
||||||
|
|
||||||
(defun mu4e-context-autoselect ()
|
(defun mu4e~context-autoswitch (&optional msg policy)
|
||||||
"When contexts are defined but there is no context yet, switch
|
"When contexts are defined but there is no context yet, switch
|
||||||
to the first whose :match-func return non-nil. If none of them
|
to the first whose :match-func return non-nil. If none of them
|
||||||
match, return the first."
|
match, return the first. For MSG and POLICY, see `mu4e-context-determine'."
|
||||||
(when (and mu4e-contexts (not (mu4e-context-current)))
|
(when mu4e-contexts
|
||||||
(mu4e-context-switch
|
(let ((context (mu4e-context-determine msg policy)))
|
||||||
(mu4e-context-name (mu4e-context-determine nil 'pick-first)))))
|
(when context (mu4e-context-switch (mu4e-context-name context))))))
|
||||||
|
|
||||||
(defun mu4e-context-determine (msg &optional policy)
|
(defun mu4e-context-determine (msg &optional policy)
|
||||||
"Return the first context with a match-func that returns t. MSG
|
"Return the first context with a match-func that returns t. MSG
|
||||||
|
@ -114,20 +114,27 @@ points to the plist for the message replied to or forwarded, or
|
||||||
nil if there is no such MSG; similar to what
|
nil if there is no such MSG; similar to what
|
||||||
`mu4e-compose-pre-hook' does.
|
`mu4e-compose-pre-hook' does.
|
||||||
|
|
||||||
POLICY determines what to do if there are contexts but none match. The following
|
POLICY specifies how to do the determination. If POLICY is
|
||||||
are supported:
|
'always-ask, we ask the user unconditionally.
|
||||||
|
|
||||||
|
In all other cases, if any context matches (using its match
|
||||||
|
function), this context is returned. If none of the contexts
|
||||||
|
match, POLICY determines what to do:
|
||||||
|
|
||||||
- pick-first: pick the first of the contexts available
|
- pick-first: pick the first of the contexts available
|
||||||
- ask: ask the user
|
- ask: ask the user
|
||||||
- otherwise, return nil. Effectively, this leaves the current context in place."
|
- otherwise, return nil. Effectively, this leaves the current context in place."
|
||||||
(when mu4e-contexts
|
(when mu4e-contexts
|
||||||
(or (find-if (lambda (context)
|
(if (eq policy 'always-ask)
|
||||||
(and (mu4e-context-match-func context)
|
(mu4e~context-ask-user "Select context: ")
|
||||||
(funcall (mu4e-context-match-func context) msg))) mu4e-contexts)
|
(or (find-if (lambda (context)
|
||||||
;; no context found
|
(and (mu4e-context-match-func context)
|
||||||
(case policy
|
(funcall (mu4e-context-match-func context) msg))) mu4e-contexts)
|
||||||
(pick-first (car mu4e-contexts))
|
;; no context found
|
||||||
(ask (mu4e~context-ask-user "Select context: "))
|
(case policy
|
||||||
(otherwise nil)))))
|
(pick-first (car mu4e-contexts))
|
||||||
|
(ask (mu4e~context-ask-user "Select context: "))
|
||||||
|
(otherwise nil))))))
|
||||||
|
|
||||||
(provide 'mu4e-context)
|
(provide 'mu4e-context)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
(declare-function mu4e~proc-mkdir "mu4e-proc")
|
(declare-function mu4e~proc-mkdir "mu4e-proc")
|
||||||
(declare-function mu4e~proc-running-p "mu4e-proc")
|
(declare-function mu4e~proc-running-p "mu4e-proc")
|
||||||
|
|
||||||
(declare-function mu4e-context-autoselect "mu4e-context")
|
(declare-function mu4e~context-autoswitch "mu4e-context")
|
||||||
|
|
||||||
(declare-function show-all "org")
|
(declare-function show-all "org")
|
||||||
|
|
||||||
|
@ -737,9 +737,9 @@ first.
|
||||||
If mu4e is already running, execute function FUNC (if non-nil).
|
If mu4e is already running, execute function FUNC (if non-nil).
|
||||||
Otherwise, check various requirements, then start mu4e. When
|
Otherwise, check various requirements, then start mu4e. When
|
||||||
successful, call FUNC (if non-nil) afterwards."
|
successful, call FUNC (if non-nil) afterwards."
|
||||||
|
;; maybe switch the context
|
||||||
;; auto-select some account
|
(mu4e~context-autoswitch mu4e-compose-parent-message
|
||||||
(mu4e-context-autoselect)
|
mu4e-compose-context-policy)
|
||||||
;; if we're already running, simply go to the main view
|
;; if we're already running, simply go to the main view
|
||||||
(if (mu4e-running-p) ;; already running?
|
(if (mu4e-running-p) ;; already running?
|
||||||
(when func ;; yes! run func if defined
|
(when func ;; yes! run func if defined
|
||||||
|
|
|
@ -114,7 +114,6 @@ better with e.g. offlineimap."
|
||||||
:group 'mu4e
|
:group 'mu4e
|
||||||
:safe 'booleanp)
|
:safe 'booleanp)
|
||||||
|
|
||||||
|
|
||||||
(defcustom mu4e-attachment-dir (expand-file-name "~/")
|
(defcustom mu4e-attachment-dir (expand-file-name "~/")
|
||||||
"Default directory for saving attachments.
|
"Default directory for saving attachments.
|
||||||
This can be either a string (a file system path), or a function
|
This can be either a string (a file system path), or a function
|
||||||
|
@ -218,6 +217,29 @@ Suggested possible values are:
|
||||||
:options '(completing-read ido-completing-read)
|
:options '(completing-read ido-completing-read)
|
||||||
:group 'mu4e)
|
:group 'mu4e)
|
||||||
|
|
||||||
|
(defcustom mu4e-context-policy 'ask
|
||||||
|
"Determines how mu4e should determine the context when starting up.
|
||||||
|
|
||||||
|
If POLICY is 'always-ask, we ask the user unconditionally.
|
||||||
|
|
||||||
|
In all other cases, if any context matches (using its match
|
||||||
|
function), this context is returned. If none of the contexts
|
||||||
|
match, POLICY determines what to do:
|
||||||
|
|
||||||
|
- pick-first: pick the first of the contexts available
|
||||||
|
- ask: ask the user
|
||||||
|
- otherwise, return nil. Effectively, this leaves the current context in place.
|
||||||
|
|
||||||
|
Also see `mu4e-compose-context-policy'."
|
||||||
|
:type '(choice
|
||||||
|
(const :tag "Always ask what context to use" 'always-ask)
|
||||||
|
(const :tag "Ask if none of the contexts match" 'ask)
|
||||||
|
(const :tag "Pick the default (first) context if none match" 'pick-first)
|
||||||
|
(const :tag "Don't change the context when none match" nil)
|
||||||
|
:safe 'symbolp
|
||||||
|
:group 'mu4e))
|
||||||
|
|
||||||
|
|
||||||
;; crypto
|
;; crypto
|
||||||
(defgroup mu4e-crypto nil
|
(defgroup mu4e-crypto nil
|
||||||
"Crypto-related settings."
|
"Crypto-related settings."
|
||||||
|
|
|
@ -37,7 +37,7 @@ Documentation License.''
|
||||||
|
|
||||||
@dircategory Emacs
|
@dircategory Emacs
|
||||||
@direntry
|
@direntry
|
||||||
* mu4e: (mu4e). An email client for Emacs.
|
* mu4e: (Mu4e). An email client for GNU/Emacs.
|
||||||
@end direntry
|
@end direntry
|
||||||
|
|
||||||
@contents
|
@contents
|
||||||
|
@ -1990,8 +1990,8 @@ also match this extra search pattern. @key{\} takes you back to the previous
|
||||||
query, so, effectively 'widens' the search. Technically, narrowing the results
|
query, so, effectively 'widens' the search. Technically, narrowing the results
|
||||||
of query @t{x} with expression @t{y} implies doing a search @t{(x) AND y}.
|
of query @t{x} with expression @t{y} implies doing a search @t{(x) AND y}.
|
||||||
|
|
||||||
Note, messages that were not in your in your original search results because
|
Note that messages that were not in your original search results because
|
||||||
of @code{mu4e-headers-results-limit}, may show up in the narrowed query.
|
of @code{mu4e-headers-results-limit} may show up in the narrowed query.
|
||||||
|
|
||||||
@subsection Including related messages
|
@subsection Including related messages
|
||||||
@anchor{Including related messages}
|
@anchor{Including related messages}
|
||||||
|
@ -2256,16 +2256,15 @@ example:
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Defining a context::
|
* Defining a context::
|
||||||
* Default context::
|
* Context policies::
|
||||||
* Contexts example::
|
* Contexts example::
|
||||||
* Contexts notes::
|
|
||||||
* Some context tricks::
|
* Some context tricks::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
It can be useful to be able to switch between different sets of settings
|
It can be useful to be able to switch between different sets of settings
|
||||||
in @t{mu4e}; typical examples include the case where you have different
|
in @t{mu4e}; typical examples include the case where you have different
|
||||||
e-mail accounts for private and work email, each with their own settings
|
e-mail accounts for private and work email, each with their own settings
|
||||||
for e-mail addresses, mailservers etc.
|
for folders, e-mail addresses, mailservers etc.
|
||||||
|
|
||||||
The @code{mu4e-context} system is a @t{mu4e}-specific mechanism to allow
|
The @code{mu4e-context} system is a @t{mu4e}-specific mechanism to allow
|
||||||
for that; users can be define different contexts, and either manually
|
for that; users can be define different contexts, and either manually
|
||||||
|
@ -2307,19 +2306,34 @@ an alist of variable settings for this account.
|
||||||
@t{mu4e} uses a variable @code{mu4e-contexts}, which is a list of such
|
@t{mu4e} uses a variable @code{mu4e-contexts}, which is a list of such
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
@node Default context
|
@node Context policies
|
||||||
@section Default context
|
@section Context policies
|
||||||
|
|
||||||
When you have defined contexts and you start @t{mu4e}, it automatically
|
When you have defined contexts and you start @t{mu4e} it decides which
|
||||||
switches to the first context whose @code{match-func} returns
|
context to use based on the variable @code{mu4e-context-policy};
|
||||||
non-nil. If none of them do, it picks the first. So, put your 'default'
|
similarly, when you compose a new message, the context is determined
|
||||||
context as the first in @code{mu4e-contexts}.
|
using @code{mu4e-compose-context-policy}.
|
||||||
|
|
||||||
|
These policies can be one of the following:
|
||||||
|
@itemize
|
||||||
|
@item a symbol @t{always-ask}: unconditionally ask the user what context to pick
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
The other choices only apply if none of the context matches (i.e., if
|
||||||
|
none of the contexts' match-functions returns @code{t}:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item a symbol @t{ask}: ask the user
|
||||||
|
@item a symbol @t{pick-first}: pick the first context
|
||||||
|
@item @t{nil}: don't change the context
|
||||||
|
@end itemize
|
||||||
|
|
||||||
@node Contexts example
|
@node Contexts example
|
||||||
@section Example
|
@section Example
|
||||||
|
|
||||||
Let's look at an example; we define two contexts, 'Private' and 'Work'
|
Let's explain how contexts work by looking at an example. We define two
|
||||||
for a fictional user Alice Derleth.
|
contexts, 'Private' and 'Work' for a fictional user @emph{Alice
|
||||||
|
Derleth}.
|
||||||
|
|
||||||
Note that in this case, we automatically switch to the first context
|
Note that in this case, we automatically switch to the first context
|
||||||
when starting; see the discussion in the previous section.
|
when starting; see the discussion in the previous section.
|
||||||
|
@ -2354,16 +2368,13 @@ when starting; see the discussion in the previous section.
|
||||||
"Miskatonic University, Dept. of Occult Sciences\n"))))))
|
"Miskatonic University, Dept. of Occult Sciences\n"))))))
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
@node Contexts notes
|
A couple of notes about this example:
|
||||||
@section Context notes
|
|
||||||
|
|
||||||
Couple of notes:
|
|
||||||
@itemize
|
@itemize
|
||||||
@item You can manually switch the focus use @code{M-x mu4e-context-switch}, by default bound to @kbd{;} in headers, view and main mode.
|
@item You can manually switch the focus use @code{M-x mu4e-context-switch}, by default bound to @kbd{;} in headers, view and main mode.
|
||||||
The current focus appears in the mode-line.
|
The current focus appears in the mode-line.
|
||||||
@item Normally, @code{M-x mu4e-context-switch} does not call the enter/leave functions if the 'new' context is the same as the old one.
|
@item Normally, @code{M-x mu4e-context-switch} does not call the enter or leave functions if the 'new' context is the same as the old one.
|
||||||
However, with a prefix-argument (@kbd{C-u}), you can force @t{mu4e} to call
|
However, with a prefix-argument (@kbd{C-u}), you can force @t{mu4e} to
|
||||||
those function even in that case.
|
invoke those function even in that case.
|
||||||
@item The function @code{mu4e-context-current} returns the current-context; the current context is also visiable in the mode-line when in
|
@item The function @code{mu4e-context-current} returns the current-context; the current context is also visiable in the mode-line when in
|
||||||
headers, view or main mode.
|
headers, view or main mode.
|
||||||
@item You can set any kind of variable; including settings for mail servers etc. However, settings like @code{mu4e-maildir}
|
@item You can set any kind of variable; including settings for mail servers etc. However, settings like @code{mu4e-maildir}
|
||||||
|
@ -2378,13 +2389,13 @@ context we are entering.
|
||||||
@node Some context tricks
|
@node Some context tricks
|
||||||
@section Some context tricks
|
@section Some context tricks
|
||||||
|
|
||||||
|
|
||||||
It is possible to automatically fill @code{mu4e-user-address-list} by
|
It is possible to automatically fill @code{mu4e-user-address-list} by
|
||||||
concatenating the @code{user-mail-address} fields of all contexts:
|
concatenating the @code{user-mail-address} fields of all contexts:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
;; This sets `mu4e-user-mail-address-list' to the concatenation of all `user-mail-address' values
|
;; This sets `mu4e-user-mail-address-list' to the concatenation of all
|
||||||
;; for all contexts. If you have other mail addresses as well, you'll need to add those manually.
|
;; `user-mail-address' values for all contexts. If you have other mail
|
||||||
|
;; addresses as well, you'll need to add those manually.
|
||||||
(setq mu4e-user-mail-address-list
|
(setq mu4e-user-mail-address-list
|
||||||
(delq nil
|
(delq nil
|
||||||
(mapcar (lambda (context)
|
(mapcar (lambda (context)
|
||||||
|
@ -2906,6 +2917,7 @@ two days, you could add this to @code{org-capture-templates}:
|
||||||
|
|
||||||
If you use the functionality a lot, you may want to define key-bindings
|
If you use the functionality a lot, you may want to define key-bindings
|
||||||
for that in headers and view mode:
|
for that in headers and view mode:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
(define-key mu4e-headers-mode-map (kbd "C-c c") 'org-mu4e-store-and-capture)
|
(define-key mu4e-headers-mode-map (kbd "C-c c") 'org-mu4e-store-and-capture)
|
||||||
(define-key mu4e-view-mode-map (kbd "C-c c") 'org-mu4e-store-and-capture)
|
(define-key mu4e-view-mode-map (kbd "C-c c") 'org-mu4e-store-and-capture)
|
||||||
|
|
Loading…
Reference in New Issue