diff --git a/mu4e/mu4e-compose.el b/mu4e/mu4e-compose.el index 025598e3..3ec1b743 100644 --- a/mu4e/mu4e-compose.el +++ b/mu4e/mu4e-compose.el @@ -112,12 +112,34 @@ for example: The various `message-' functions from `message-mode' are available for querying the message information." - :type '(choice (const :tag "move message to mu4e-sent-folder" sent) - (const :tag "move message to mu4e-trash-folder" trash) - (const :tag "delete message" delete)) + :type '(choice (const :tag "move message to mu4e-sent-folder" sent) + (const :tag "move message to mu4e-trash-folder" trash) + (const :tag "delete message" delete)) :safe 'symbolp :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 "Hook run just *before* message composition starts. 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. (set (make-local-variable 'mu4e-compose-parent-message) original-msg) (put 'mu4e-compose-parent-message 'permanent-local t) - (let ((context (mu4e-context-determine mu4e-compose-parent-message))) - (if context - (mu4e-context-switch nil (mu4e-context-name context)) - (when mu4e-contexts (mu4e-context-switch nil)))) + ;; maybe switch the context + (mu4e~context-autoswitch mu4e-compose-parent-message + mu4e-compose-context-policy) (run-hooks 'mu4e-compose-pre-hook) ;; this opens (or re-opens) a messages with all the basic headers set. diff --git a/mu4e/mu4e-context.el b/mu4e/mu4e-context.el index 0b5f7cd0..2db45753 100644 --- a/mu4e/mu4e-context.el +++ b/mu4e/mu4e-context.el @@ -100,13 +100,13 @@ non-nil." (mu4e-message "Switched context to %s" (mu4e-context-name context))) context)) -(defun mu4e-context-autoselect () +(defun mu4e~context-autoswitch (&optional msg policy) "When contexts are defined but there is no context yet, switch to the first whose :match-func return non-nil. If none of them -match, return the first." - (when (and mu4e-contexts (not (mu4e-context-current))) - (mu4e-context-switch - (mu4e-context-name (mu4e-context-determine nil 'pick-first))))) +match, return the first. For MSG and POLICY, see `mu4e-context-determine'." + (when mu4e-contexts + (let ((context (mu4e-context-determine msg policy))) + (when context (mu4e-context-switch (mu4e-context-name context)))))) (defun mu4e-context-determine (msg &optional policy) "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 `mu4e-compose-pre-hook' does. -POLICY determines what to do if there are contexts but none match. The following -are supported: +POLICY specifies how to do the determination. 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." (when mu4e-contexts - (or (find-if (lambda (context) - (and (mu4e-context-match-func context) - (funcall (mu4e-context-match-func context) msg))) mu4e-contexts) - ;; no context found - (case policy - (pick-first (car mu4e-contexts)) - (ask (mu4e~context-ask-user "Select context: ")) - (otherwise nil))))) + (if (eq policy 'always-ask) + (mu4e~context-ask-user "Select context: ") + (or (find-if (lambda (context) + (and (mu4e-context-match-func context) + (funcall (mu4e-context-match-func context) msg))) mu4e-contexts) + ;; no context found + (case policy + (pick-first (car mu4e-contexts)) + (ask (mu4e~context-ask-user "Select context: ")) + (otherwise nil)))))) (provide 'mu4e-context) diff --git a/mu4e/mu4e-utils.el b/mu4e/mu4e-utils.el index 27d49a9e..1b2ae551 100644 --- a/mu4e/mu4e-utils.el +++ b/mu4e/mu4e-utils.el @@ -46,7 +46,7 @@ (declare-function mu4e~proc-mkdir "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") @@ -737,9 +737,9 @@ first. If mu4e is already running, execute function FUNC (if non-nil). Otherwise, check various requirements, then start mu4e. When successful, call FUNC (if non-nil) afterwards." - - ;; auto-select some account - (mu4e-context-autoselect) + ;; maybe switch the context + (mu4e~context-autoswitch mu4e-compose-parent-message + mu4e-compose-context-policy) ;; if we're already running, simply go to the main view (if (mu4e-running-p) ;; already running? (when func ;; yes! run func if defined diff --git a/mu4e/mu4e-vars.el b/mu4e/mu4e-vars.el index 6b10f49b..350f28c8 100644 --- a/mu4e/mu4e-vars.el +++ b/mu4e/mu4e-vars.el @@ -114,7 +114,6 @@ better with e.g. offlineimap." :group 'mu4e :safe 'booleanp) - (defcustom mu4e-attachment-dir (expand-file-name "~/") "Default directory for saving attachments. 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) :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 (defgroup mu4e-crypto nil "Crypto-related settings." diff --git a/mu4e/mu4e.texi b/mu4e/mu4e.texi index f03ea792..85b4f674 100644 --- a/mu4e/mu4e.texi +++ b/mu4e/mu4e.texi @@ -37,7 +37,7 @@ Documentation License.'' @dircategory Emacs @direntry -* mu4e: (mu4e). An email client for Emacs. +* mu4e: (Mu4e). An email client for GNU/Emacs. @end direntry @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 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 -of @code{mu4e-headers-results-limit}, may show up in the narrowed query. +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. @subsection Including related messages @anchor{Including related messages} @@ -2256,16 +2256,15 @@ example: @menu * Defining a context:: -* Default context:: +* Context policies:: * Contexts example:: -* Contexts notes:: * Some context tricks:: @end menu 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 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 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 objects. -@node Default context -@section Default context +@node Context policies +@section Context policies -When you have defined contexts and you start @t{mu4e}, it automatically -switches to the first context whose @code{match-func} returns -non-nil. If none of them do, it picks the first. So, put your 'default' -context as the first in @code{mu4e-contexts}. +When you have defined contexts and you start @t{mu4e} it decides which +context to use based on the variable @code{mu4e-context-policy}; +similarly, when you compose a new message, the context is determined +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 @section Example -Let's look at an example; we define two contexts, 'Private' and 'Work' -for a fictional user Alice Derleth. +Let's explain how contexts work by looking at an example. We define two +contexts, 'Private' and 'Work' for a fictional user @emph{Alice +Derleth}. Note that in this case, we automatically switch to the first context 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")))))) @end lisp -@node Contexts notes -@section Context notes - -Couple of notes: +A couple of notes about this example: @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. 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. -However, with a prefix-argument (@kbd{C-u}), you can force @t{mu4e} to call -those function even in that case. +@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 +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 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} @@ -2378,13 +2389,13 @@ context we are entering. @node Some context tricks @section Some context tricks - It is possible to automatically fill @code{mu4e-user-address-list} by concatenating the @code{user-mail-address} fields of all contexts: @lisp -;; This sets `mu4e-user-mail-address-list' to the concatenation of all `user-mail-address' values -;; for all contexts. If you have other mail addresses as well, you'll need to add those manually. +;; This sets `mu4e-user-mail-address-list' to the concatenation of all +;; `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 (delq nil (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 for that in headers and view mode: + @lisp (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)