Commit 453eb1013d6f

Vincent Demeester <vincent@sbr.pm>
2025-03-07 17:06:57
tools/emacs: add consult-mu as a submodule for now.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 9cc0e42
tools/emacs/lisp/consult-mu
@@ -0,0 +1,1 @@
+Subproject commit e1dc63674b924698b30a9ecc0400a05864711c85
tools/emacs/lisp/consult-mu-embark.el
@@ -1,249 +0,0 @@
-;;; consult-mu-embark.el --- Emabrk Actions for consult-mu -*- lexical-binding: t -*-
-
-;; Copyright (C) 2021-2023
-
-;; Author: Armin Darvish
-;; Maintainer: Armin Darvish
-;; Created: 2023
-;; Version: 1.0
-;; Package-Requires: ((emacs "28.0") (consult "2.0"))
-;; Homepage: https://github.com/armindarvish/consult-mu
-;; Keywords: convenience, matching, tools, email
-;; Homepage: https://github.com/armindarvish/consult-mu
-
-;; SPDX-License-Identifier: GPL-3.0-or-later
-
-;; This file 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.
-;;
-;; This file 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 this file.  If not, see <https://www.gnu.org/licenses/>.
-
-
-;;; Commentary:
-
-;; This package provides an alternative interactive serach interface for
-;; mu and mu4e (see URL `https://djcbsoftware.nl/code/mu/mu4e.html').
-;; It uses a consult-based minibuffer completion for searching and
-;; selecting, and marking emails, as well as additional utilities for
-;; composing emails and more.
-
-;;  This package requires mu4e version "1.10.8" or later.
-
-;;; Code:
-
-;;; Requirements
-(require 'embark)
-(require 'consult-mu)
-
-;;; Customization Variables
-(defcustom consult-mu-embark-noconfirm-before-execute nil
-  "Should consult-mu-embark skip confirmation when executing marks?"
-  :group 'consult-mu
-  :type 'boolean)
-
-;;; Define Embark Action Functions
-(defun consult-mu-embark-default-action (cand)
-  "Run `consult-mu-action' on the candidate, CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand))
-         (newcand (cons cand `(:msg ,msg :query ,query :type ,type))))
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-    (funcall consult-mu-action newcand)))
-
-
-
-(defun consult-mu-embark-reply (cand)
-  "Reply to message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand)))
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-    (consult-mu--reply msg nil)))
-
-(defun consult-mu-embark-wide-reply (cand)
-  "Reply all for message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand)))
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-    (consult-mu--reply msg )))
-
-(defun consult-mu-embark-forward (cand)
-  "Forward the message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand)))
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-    (consult-mu--forward msg)))
-
-(defun consult-mu-embark-kill-message-field (cand)
-  "Get a header field of message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand))
-         (msg-id (plist-get msg :message-id)))
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-    (with-current-buffer consult-mu-headers-buffer-name
-      (unless (equal (mu4e-message-field-at-point :message-id) msg-id)
-        (mu4e-headers-goto-message-id msg-id))
-      (if (equal (mu4e-message-field-at-point :message-id) msg-id)
-          (progn
-            (mu4e~headers-update-handler msg nil nil))))
-
-    (with-current-buffer consult-mu-view-buffer-name
-      (kill-new (consult-mu--message-get-header-field))
-      (consult-mu--pulse-region (point) (line-end-position)))))
-
-(defun consult-mu-embark-save-attachmnts (cand)
-  "Save attachments of CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (query (get-text-property 0 :query cand))
-         (type (get-text-property 0 :type cand))
-         (msg-id (plist-get msg :message-id)))
-
-    (if (equal type :async)
-        (consult-mu--update-headers query t msg :async))
-
-    (with-current-buffer consult-mu-headers-buffer-name
-      (unless (equal (mu4e-message-field-at-point :message-id) msg-id)
-        (mu4e-headers-goto-message-id msg-id))
-      (if (equal (mu4e-message-field-at-point :message-id) msg-id)
-          (progn
-            (mu4e~headers-update-handler msg nil nil))))
-
-    (with-current-buffer consult-mu-view-buffer-name
-      (goto-char (point-min))
-      (re-search-forward "^\\(Attachment\\|Attachments\\): " nil t)
-      (consult-mu--pulse-region (point) (line-end-position))
-      (mu4e-view-save-attachments t))))
-
-(defun consult-mu-embark-search-messages-from-contact (cand)
-  "Search messages from the same sender as the message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (from (car (plist-get msg :from)))
-         (email (plist-get from :email)))
-    (consult-mu (concat "from:" email))))
-
-(defun consult-mu-embark-search-messages-with-subject (cand)
-  "Search all messages for the same subject as the message in CAND."
-  (let* ((msg (get-text-property 0 :msg cand))
-         ;;(subject (replace-regexp-in-string ":\\|#\\|\\.\\|\\+" "" (plist-get msg :subject)))
-         (subject (replace-regexp-in-string ":\\|#\\|\\.\\|\\+\\|\\(\\[.*\\]\\)" "" (format "%s" (plist-get msg :subject)))))
-    (consult-mu (concat "subject:" subject))))
-
-;; macro for defining functions for marks
-(defmacro consult-mu-embark--defun-mark-for (mark)
-  "Define a function mu4e-view-mark-for- MARK."
-  (let ((funcname (intern (format "consult-mu-embark-mark-for-%s" mark)))
-        (docstring (format "Mark the current message for %s." mark)))
-    `(progn
-       (defun ,funcname (cand) ,docstring
-              (let* ((msg (get-text-property 0 :msg cand))
-                     (msgid (plist-get msg  :message-id))
-                     (query (get-text-property 0 :query cand))
-                     (buf (get-buffer consult-mu-headers-buffer-name)))
-                (if buf
-                    (progn
-                      (with-current-buffer buf
-                        (if (eq major-mode 'mu4e-headers-mode)
-                            (progn
-                              (goto-char (point-min))
-                              (mu4e-headers-goto-message-id msgid)
-                              (if (equal (mu4e-message-field-at-point :message-id) msgid)
-                                  (mu4e-headers-mark-and-next ',mark)
-                                (progn
-                                  (consult-mu--update-headers query t msg :async)
-                                  (with-current-buffer buf
-                                    (goto-char (point-min))
-                                    (mu4e-headers-goto-message-id msgid)
-                                    (if (equal (mu4e-message-field-at-point :message-id) msgid)
-                                        (mu4e-headers-mark-and-next ',mark))))))
-                          (progn
-                            (consult-mu--update-headers query t msg :async)
-                            (with-current-buffer buf
-                              (goto-char (point-min))
-                              (mu4e-headers-goto-message-id msgid)
-                              (if (equal (mu4e-message-field-at-point :message-id) msgid)
-                                  (mu4e-headers-mark-and-next ',mark)))))))))))))
-
-;; add embark functions for marks
-(defun consult-mu-embark--defun-func-for-marks (marks)
-  "Run the macro `consult-mu-embark--defun-mark-for' on MARKS.
-
-MARKS is a list of marks.
-
-This is useful for creating embark functions for all the `mu4e-marks'
-elements."
-  (mapcar (lambda (mark) (eval `(consult-mu-embark--defun-mark-for ,mark))) marks))
-
-;; use consult-mu-embark--defun-func-for-marks to make a function for each `mu4e-marks' element.
-(consult-mu-embark--defun-func-for-marks (mapcar 'car mu4e-marks))
-
-;;; Define Embark Keymaps
-(defvar-keymap consult-mu-embark-general-actions-map
-  :doc "Keymap for consult-mu-embark"
-  :parent embark-general-map)
-
-(add-to-list 'embark-keymap-alist '(consult-mu . consult-mu-embark-general-actions-map))
-
-
-(defvar-keymap consult-mu-embark-messages-actions-map
-  :doc "Keymap for consult-mu-embark-messages"
-  :parent consult-mu-embark-general-actions-map
-  "r" #'consult-mu-embark-reply
-  "w" #'consult-mu-embark-wide-reply
-  "f" #'consult-mu-embark-forward
-  "?" #'consult-mu-embark-kill-message-field
-  "c" #'consult-mu-embark-search-messages-from-contact
-  "s" #'consult-mu-embark-search-messages-with-subject
-  "S" #'consult-mu-embark-save-attachmnts)
-
-(add-to-list 'embark-keymap-alist '(consult-mu-messages . consult-mu-embark-messages-actions-map))
-
-
-;; add mark keys to `consult-mu-embark-messages-actions-map' keymap
-(defun consult-mu-embark--add-keys-for-marks (marks)
-  "Add a key for each mark in MARKS to embark map.
-
-Adds the keys in `consult-mu-embark-messages-actions-map', and binds the
-combination “m key”, where key is the :char in mark plist in the
-`consult-mu-embark-messages-actions-map' to the function defined by the
-prefix “consult-mu-embark-mark-for-” and mark.
-
-This is useful for adding all `mu4e-marks' to embark key bindings under a
-submenu (called by “m”), for example, the default mark-for-archive mark
-that is bound to r in mu4e buffers can be called in embark by “m r”."
-  (mapcar (lambda (mark)
-            (let* ((key (plist-get (cdr mark) :char))
-                   (key (cond ((consp key) (car key)) ((stringp key) key)))
-                   (func (intern (concat "consult-mu-embark-mark-for-" (format "%s" (car mark)))))
-                   (key (concat "m" key)))
-              (define-key consult-mu-embark-messages-actions-map key func)))
-          marks))
-
-;; add all `mu4e-marks to embark keybindings. See `consult-mu-embark--add-keys-for-marks' above for more details
-(consult-mu-embark--add-keys-for-marks mu4e-marks)
-
-;; change the default action on `consult-mu-messages' category.
-(add-to-list 'embark-default-action-overrides '(consult-mu-messages . consult-mu-embark-default-action))
-
-
-;;; Provide `consult-mu-embark' module
-
-(provide 'consult-mu-embark)
-
-;;; consult-mu-embark.el ends here
tools/emacs/lisp/consult-mu.el
@@ -1,1673 +0,0 @@
-;;; consult-mu.el --- Consult Mu4e asynchronously -*- lexical-binding: t -*-
-
-;; Copyright (C) 2023 Armin Darvish
-
-;; Author: Armin Darvish
-;; Maintainer: Armin Darvish
-;; Created: 2023
-;; Version: 1.0
-;; Package-Requires: ((emacs "28.0") (consult "2.0"))
-;; Keywords: convenience, matching, tools, email
-;; Homepage: https://github.com/armindarvish/consult-mu
-
-;; SPDX-License-Identifier: GPL-3.0-or-later
-
-;; This file 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.
-;;
-;; This file 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 this file.  If not, see <https://www.gnu.org/licenses/>.
-
-
-;;; Commentary:
-
-;; This package provides an alternative interactive serach interface for
-;; mu and mu4e (see URL `https://djcbsoftware.nl/code/mu/mu4e.html').
-;; It uses a consult-based minibuffer completion for searching and
-;; selecting, and marking emails, as well as additional utilities for
-;; composing emails and more.
-
-;;  This package requires mu4e version "1.10.8" or later.
-
-;;; Code:
-
-;;; Requirements
-(require 'consult)
-(require 'mu4e)
-
-;;; Group
-
-(defgroup consult-mu nil
-  "Options for `consult-mu'."
-  :group 'convenience
-  :group 'minibuffer
-  :group 'consult
-  :group 'mu4e
-  :prefix "consult-mu-")
-
-;;; Customization Variables
-
-(defcustom consult-mu-args '("mu")
-  "Command line arguments to call `mu` asynchronously.
-
-The dynamically computed arguments are appended.
-Can be either a string, or a list of strings or expressions."
-  :group 'consult-mu
-  :type '(choice string (repeat (choice string sexp))))
-
-(defcustom consult-mu-maxnum mu4e-search-results-limit
-  "Maximum number of results.
-
-This is normally passed to “--maxnum” in the command line or is defined by
-`mu4e-search-results-limit'.  By default inherits from
-`mu4e-search-results-limit'."
-  :group 'consult-mu
-  :type '(choice (const :tag "Unlimited" -1)
-                 (integer :tag "Limit")))
-
-(defcustom consult-mu-search-sort-field mu4e-search-sort-field
-  "What field to sort results by?
-
-By defualt inherits from `mu4e-search-sort-field'."
-  :group 'consult-mu
-  :type '(radio (const :tag "Date" :date)
-                (const :tag "Subject" :subject)
-                (const :tag "File Size" :size)
-                (const :tag "Priority" :prio)
-                (const :tag "From (Sender)" :from)
-                (const :tag "To (Recipients)" :to)
-                (const :tag "Mailing List" :list)))
-
-(defcustom consult-mu-headers-fields mu4e-headers-fields
-  "A list of header fields to show in the headers buffer.
-
-By default inherits from `mu4e-headers-field'.
-
-From mu4e docs:
-
-Each element has the form (HEADER . WIDTH), where HEADER is one of
-the available headers (see `mu4e-header-info') and WIDTH is the
-respective width in characters.
-
-A width of nil means “unrestricted”, and this is best reserved
-for the rightmost \(last\) field.  Note that Emacs may become very
-slow with excessively long lines \(1000s of characters\), so if you
-regularly get such messages, you want to avoid fields with nil
-altogether."
-  :group 'consult-mu
-  :type `(repeat (cons (choice ,@(mapcar (lambda (h)
-                                           (list 'const
-                                                 :tag (plist-get (cdr h) :help)
-                                                 (car h)))
-                                         mu4e-header-info))
-                       (choice (integer :tag "width")
-                               (const :tag "unrestricted width" nil)))))
-
-(defcustom consult-mu-headers-template nil
-  "A template string to make custom header formats.
-
-If non-nil, `consult-mu' uses this string to format the headers instead of
-`consult-mu-headers-field'.
-
-The string should be of the format “%[char][integer]%[char][integer]...”,
-and allow dynamic insertion of the content.  Each “%[char][integer]“ chunk
-represents a different field and the integer defines the length of the
-field.
-
-The list of available fields are:
-
-  %f  sender(s) \(e.g. from: field of email\)
-  %t  receivers(s) \(i.e. to: field of email\)
-  %s  subject \(i.e. title of email\)
-  %d  date \(i.e. the date email was sent/received\)
-  %p  priority
-  %z  size
-  %i  message-id \(as defined by mu\)
-  %g  flags \(as defined by mu\)
-  %G  pretty flags \(this uses `mu4e~headers-flags-str' to pretify flags\)
-  %x  tags \(as defined by mu\)
-  %c  cc \(i.e. cc: field of the email\)
-  %h  bcc \(i.e. bcc: field of the email\)
-  %r  date chaged \(as defined by :changed in mu4e\)
-
-For exmaple, “%d15%s50” means 15 characters for date and 50 charcters for
-subject, and “%d13%s37%f17” would make a header containing 13 characters
-for Date, 37 characters for Subject, and 20 characters for From field,
-making a header that looks like this:
-
-Thu 09 Nov 23  Title of the Email Limited to 50 Char...  example@domain..."
-  :group 'consult-mu
-  :type '(choice (const :tag "Fromatted String" :format "%{%%d13%%s50%%f17%}")
-                 (function :tag "Custom Function")))
-
-(defcustom consult-mu-search-sort-direction mu4e-search-sort-direction
-  "Direction to sort by a symbol.
-
-By defualt inherits from `mu4e-search-sort-direction', and can either be
-\='descending (sorting  Z->A) or \='ascending (sorting A->Z)."
-
-  :group 'consult-mu
-  :type '(radio (const ascending)
-                (const descending)))
-
-
-(defcustom consult-mu-search-threads mu4e-search-threads
-  "Whether to calculate threads for search results.
-
-By defualt inherits from `mu4e-search-threads'.
-
-Note that per mu4e docs:
-When threading is enabled, the headers are exclusively sorted
-chronologically (:date) by the newest message in the thread."
-  :group 'consult-mu
-  :type 'boolean)
-
-(defcustom consult-mu-group-by nil
-  "What field to use to group the results in the minibuffer.
-
-By default it is set to :date, but can be any of:
-
-  :subject      group by subject
-  :from         group by the name/email the sender(s)
-  :to           group by name/email of the reciver(s)
-  :date         group by date
-  :time         group by the time of email \(i.e. hour, minute, seconds\)
-  :datetime     group by date and time of the email
-  :year         group by the year of the email \(i.e. 2023, 2022, ...\)
-  :month        group by the month of the email \(i.e. Jan, Feb, ..., Dec\)
-  :week         group by the week number of the email
-                \(i.e. 1st week, 2nd week, ... 52nd week\)
-  :day-of-week  group by the day email was sent (i.e. Mondays, Tuesdays, ...)
-  :day          group by the day email was sent (similar to :day-of-week)
-  :size         group by the file size of the email
-  :flags        group by flags (as defined by mu)
-  :tags         group by tags (as defined by mu)
-  :changed      group by the date changed
-                \(as defined by :changed field in mu4e\)"
-  :group 'consult-mu
-  :type '(radio (const :date)
-                (const :subject)
-                (const :from)
-                (const :to)
-                (const :time)
-                (const :datetime)
-                (const :year)
-                (const :month)
-                (const :week)
-                (const :day-of-week)
-                (const :day)
-                (const :size)
-                (const :flags)
-                (const :tags)
-                (const :changed)
-                (const nil)))
-
-(defcustom consult-mu-mark-previewed-as-read nil
-  "Whether to mark PREVIEWED emails as read or not?"
-  :group 'consult-mu
-  :type 'boolean)
-
-(defcustom consult-mu-mark-viewed-as-read t
-  "Whether to mark VIEWED emails as read or not?"
-  :group 'consult-mu
-  :type 'boolean)
-
-(defcustom consult-mu-headers-buffer-name "*consult-mu-headers*"
-  "Default name for HEADERS buffer explicitly for `consult-mu'.
-
-For more info see `mu4e-headers-buffer-name'."
-  :group 'consult-mu
-  :type 'string)
-
-(defcustom consult-mu-view-buffer-name "*consult-mu-view*"
-  "Default name for VIEW buffer explicitly for `consult-mu'.
-
-For more info see `mu4e-view-buffer-name'."
-  :group 'consult-mu
-  :type 'string)
-
-(defcustom consult-mu-preview-key consult-preview-key
-  "Preview key for `consult-mu'.
-
-This is similar to `consult-preview-key' but explicitly for `consult-mu'."
-  :group 'consult-mu
-  :type '(choice (symbol :tag "Any key" 'any)
-                 (list :tag "Debounced"
-                       (const :debounce)
-                       (float :tag "Seconds" 0.1)
-                       (const any))
-                 (const :tag "No preview" nil)
-                 (key :tag "Key")
-                 (repeat :tag "List of keys" key)))
-
-
-(defcustom consult-mu-highlight-matches t
-  "Should `consult-mu' highlight search queries in preview buffers?"
-  :group 'consult-mu
-  :type 'boolean)
-
-(defcustom consult-mu-use-wide-reply 'ask
-  "Reply to all or not?
-
-This defines whether `consult-mu--reply-action' should reply to all or not."
-  :group 'consult-mu
-  :type '(choice (symbol :tag "Ask for confirmation" 'ask)
-                 (const :tag "Do not reply to all" nil)
-                 (const :tag "Always reply to all" t)))
-
-(defcustom consult-mu-action #'consult-mu--view-action
-  "The function that is used when selecting a message.
-By default it is bound to `consult-mu--view-action'."
-  :group 'consult-mu
-  :type '(choice (function :tag "(Default) View Message in Mu4e Buffers" consult-mu--view-action)
-                 (function :tag "Reply to Message" consult-mu--reply-action)
-                 (function :tag "Forward Message" consult-mu--forward-action)
-                 (function :tag "Custom Function")))
-
-(defcustom consult-mu-default-command #'consult-mu-dynamic
-  "Which command should `consult-mu' call."
-  :group 'consult-mu
-  :type '(choice (function :tag "(Default) Use Dynamic Collection (i.e. `consult-mu-dynamic')" #'consult-mu-dynamic)
-                 (function :tag "Use Async Collection (i.e. `consult-mu-async')"  #'consult-mu-async)
-                 (function :tag "Custom Function")))
-
-;;; Other Variables
-(defvar consult-mu-category 'consult-mu
-  "Category symbol for the `consult-mu' package.")
-
-(defvar consult-mu-messages-category 'consult-mu-messages
-  "Category symbol for messages in `consult-mu' package.")
-
-(defvar consult-mu--view-buffers-list (list)
-  "List of currently open preview buffers for `consult-mu'.")
-
-(defvar consult-mu--history nil
-  "History variable for `consult-mu'.")
-
-(defvar consult-mu-delimiter "      "
-  "Delimiter to use for fields in mu command output.
-
-The idea is Taken from  https://github.com/seanfarley/counsel-mu.")
-
-(defvar consult-mu-saved-searches-dynamic (list)
-  "List of Favorite searches for `consult-mu-dynamic'.")
-
-(defvar consult-mu-saved-searches-async consult-mu-saved-searches-dynamic
-  "List of Favorite searches for `consult-mu-async'.")
-
-(defvar consult-mu--override-group nil
-  "Override grouping in `consult-mu' based on user input.")
-
-(defvar consult-mu--mail-headers '("Subject" "From" "To" "From/To" "Cc" "Bcc" "Reply-To" "Date" "Attachments" "Tags" "Flags" "Maildir" "Summary" "List" "Path" "Size" "Message-Id" "List-Id" "Changed")
-  "List of possible headers in a message.")
-
-;;; Faces
-
-(defface consult-mu-highlight-match-face
-  `((t :inherit 'consult-highlight-match))
-  "Highlight match face in `consult-mu' view buffer.
-
-By default inherits from `consult-highlight-match'.
-This is used to highlight matches of search queries in the minibufffer
-completion list.")
-
-(defface consult-mu-preview-match-face
-  `((t :inherit 'consult-preview-match))
-  "Preview match face in `consult-mu' preview buffers.
-
-By default inherits from `consult-preview-match'.
-This is used to highlight matches of search query terms in preview buffers
-\(i.e. `consult-mu-view-buffer-name'\).")
-
-(defface consult-mu-default-face
-  `((t :inherit 'default))
-  "Default face in `consult-mu' minibuffer annotations.
-
-By default inherits from `default' face.")
-
-(defface consult-mu-subject-face
-  `((t :inherit 'font-lock-keyword-face))
-  "Subject face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-keyword-face'.")
-
-(defface consult-mu-sender-face
-  `((t :inherit 'font-lock-variable-name-face))
-  "Contact face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-variable-name-face'.")
-
-(defface consult-mu-receiver-face
-  `((t :inherit 'font-lock-variable-name-face))
-  "Contact face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-variable-name-face'.")
-
-(defface consult-mu-date-face
-  `((t :inherit 'font-lock-preprocessor-face))
-  "Date face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-preprocessor-face'.")
-
-(defface consult-mu-count-face
-  `((t :inherit 'font-lock-string-face))
-  "Count face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-string-face'.")
-
-(defface consult-mu-size-face
-  `((t :inherit 'font-lock-string-face))
-  "Size face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-string-face'.")
-
-(defface consult-mu-tags-face
-  `((t :inherit 'font-lock-comment-face))
-  "Tags/Comments face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-comment-face'.")
-
-(defface consult-mu-flags-face
-  `((t :inherit 'font-lock-function-call-face))
-  "Flags face in `consult-mu' minibuffer annotations.
-
-By default inherits from `font-lock-function-call-face'.")
-
-(defface consult-mu-url-face
-  `((t :inherit 'link))
-  "URL face in `consult-mu' minibuffer annotations;
-
-By default inherits from `link'.")
-
-(defun consult-mu--pulse-regexp (regexp)
-  "Find and pulse REGEXP."
-  (goto-char (point-min))
-  (while (re-search-forward regexp nil t)
-    (when-let* ((m (match-data))
-                (beg (car m))
-                (end (cadr m))
-                (ov (make-overlay beg end))
-                (pulse-delay 0.075))
-      (pulse-momentary-highlight-overlay ov 'highlight))))
-
-(defun consult-mu--pulse-region (beg end)
-  "Find and pulse region from BEG to END."
-  (let ((ov (make-overlay beg end))
-        (pulse-delay 0.075))
-    (pulse-momentary-highlight-overlay ov 'highlight)))
-
-(defun consult-mu--pulse-line ()
-  "Pulse line at point momentarily."
-  (let* ((pulse-delay 0.055)
-         (ov (make-overlay (car (bounds-of-thing-at-point 'line))
-                           (cdr (bounds-of-thing-at-point 'line)))))
-    (pulse-momentary-highlight-overlay ov 'highlight)))
-
-(defun consult-mu--set-string-width (string width &optional prepend)
-  "Set the STRING width to a fixed value, WIDTH.
-
-If the STRING is longer than WIDTH, it truncates the string and adds
-ellipsis, “...”.  If the string is shorter, it adds whitespace to the
-string.  If PREPEND is non-nil, it truncates or adds whitespace from the
-beginning of string, instead of the end."
-  (let* ((string (format "%s" string))
-         (w (string-width string)))
-    (when (< w width)
-      (if prepend
-          (setq string (format "%s%s" (make-string (- width w) ?\s) (substring string)))
-        (setq string (format "%s%s" (substring string) (make-string (- width w) ?\s)))))
-    (when (> w width)
-      (if prepend
-          (setq string (format "...%s" (substring string (- w (- width 3)) w)))
-        (setq string (format "%s..." (substring string 0 (- width (+ w 3)))))))
-    string))
-
-(defun consult-mu--justify-left (string prefix maxwidth)
-  "Set the width of  STRING+PREFIX justified from left.
-
-Use `consult-mu--set-string-width' to the width of the concatenate of
-STRING+PREFIX \(e.g. “(concat prefix string)”\) within MAXWIDTH.  This is
-used for aligning marginalia info in the minibuffer."
-  (let ((w (string-width prefix)))
-    (if (> maxwidth w)
-        (consult-mu--set-string-width string (- maxwidth w) t)
-      string)))
-
-(defun consult-mu--highlight-match (regexp str ignore-case)
-  "Highlight REGEXP in STR.
-
-If a REGEXP contains a capturing group, only the captured group is
-highlighted, otherwise, the whole match is highlighted.
-Case is ignored if IGNORE-CASE is non-nil.
-\(This is adapted from `consult--highlight-regexps'.\)"
-  (let ((i 0))
-    (while (and (let ((case-fold-search ignore-case))
-                  (string-match regexp str i))
-                (> (match-end 0) i))
-      (let ((m (match-data)))
-        (setq i (cadr m)
-              m (or (cddr m) m))
-        (while m
-          (when (car m)
-            (add-face-text-property (car m) (cadr m)
-                                    'consult-mu-highlight-match-face nil str))
-          (setq m (cddr m))))))
-  str)
-
-(defun consult-mu--overlay-match (match-str buffer ignore-case)
-  "Highlight MATCH-STR in BUFFER using an overlay.
-
-If IGNORE-CASE is non-nil, it uses case-insensitive match.
-
-This is used to highlight matches to use queries when viewing emails.  See
-`consult-mu-overlays-toggle' for toggling highligths on/off."
-  (with-current-buffer (or (get-buffer buffer) (current-buffer))
-    (remove-overlays (point-min) (point-max) 'consult-mu-overlay t)
-    (goto-char (point-min))
-    (let ((case-fold-search ignore-case))
-      (while (search-forward match-str nil t)
-        (when-let* ((m (match-data))
-                    (beg (car m))
-                    (end (cadr m))
-                    (overlay (make-overlay beg end)))
-          (overlay-put overlay 'consult-mu-overlay t)
-          (overlay-put overlay 'face 'consult-mu-highlight-match-face))))))
-
-(defun consult-mu-overlays-toggle (&optional buffer)
-  "Toggle overlay highlight in BUFFER.
-
-BUFFER defaults to `current-buffer'."
-  (interactive)
-  (let ((buffer (or buffer (current-buffer))))
-    (with-current-buffer buffer
-      (dolist (o (overlays-in (point-min) (point-max)))
-        (when (overlay-get o 'consult-mu-overlay)
-          (if (and (overlay-get o 'face) (eq (overlay-get o 'face) 'consult-mu-highlight-match-face))
-              (overlay-put o 'face nil)
-            (overlay-put o 'face 'consult-mu-highlight-match-face)))))))
-
-(defun consult-mu--format-date (string)
-  "Format the date STRING from mu output.
-
-STRING is the output form a mu command, for example:
-`mu find query --fields d`
-Returns the date in the format Day-of-Week Month Day Year Time
-\(e.g. Sat Nov 04 2023 09:46:54\)"
-  (let ((string (replace-regexp-in-string " " "0" string)))
-    (format "%s %s %s"
-            (substring string 0 10)
-            (substring string -4 nil)
-            (substring string 11 -4))))
-
-(defun consult-mu-flags-to-string (FLAG)
-  "Covert FLAGS, from mu output to strings.
-
-FLAG is the output form mu command in the terminal, for example:
- `mu find query --fields g`.
-This function converts each character in FLAG to an expanded string of the
-flag and returns the list of these strings."
-  (cl-loop for c across FLAG
-           collect
-           (pcase (string c)
-             ("D" 'draft)
-             ("F" 'flagged)
-             ("N" 'new)
-             ("P" 'forwarded)
-             ("R" 'replied)
-             ("S" 'read)
-             ("T" 'trashed)
-             ("a" 'attachment)
-             ("x" 'encrrypted)
-             ("s" 'signed)
-             ("u" 'unread)
-             ("l" 'list)
-             ("q" 'personal)
-             ("c" 'calendar)
-             (_ nil))))
-
-(defun consult-mu--message-extract-email-from-string (string)
-  "Find and return the first email address in the STRING."
-  (when (stringp string)
-    (string-match "[a-zA-Z0-9\_\.\+\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+" string)
-    (match-string 0 string)))
-
-(defun consult-mu--message-emails-string-to-list (string)
-  "Convert comma-separated STRING of email addresses to a list."
-  (when (stringp string)
-    (remove '(" " "\s" "\t")
-            (mapcar #'consult-mu--message-extract-email-from-string
-                    (split-string string ",\\|;\\|\t" t)))))
-
-(defun consult-mu--message-get-header-field (&optional field)
-  "Retrive FIELD header from the message/mail in the current buffer."
-  (save-match-data
-    (save-excursion
-      (when (or (derived-mode-p 'message-mode)
-                (derived-mode-p 'mu4e-view-mode)
-                (derived-mode-p 'org-msg-edit-mode)
-                (derived-mode-p 'mu4e-compose-mode))
-        (let* ((case-fold-search t)
-               (header-regexp (mapconcat (lambda (str) (concat "\n" str ": "))
-                                        consult-mu--mail-headers "\\|"))
-               (field (or (downcase field)
-                          (downcase (consult--read consult-mu--mail-headers
-                                                   :prompt "Header Field: ")))))
-          (if (string-prefix-p "attachment" field) (setq field "\\(attachment\\|attachments\\)"))
-          (goto-char (point-min))
-          (message-goto-body)
-          (let* ((match (re-search-backward (concat "^" field ": \\(?1:[[:ascii:][:nonascii:]]*?\\)\n\\(.*?:\\|\n\\)") nil t))
-                 (str (if (and match (match-string 1)) (string-trim (match-string 1)))))
-            (if (string-empty-p str) nil str)))))))
-
-(defun consult-mu--headers-append-handler (msglst)
-  "Append one-line descriptions of messages in MSGLST.
-
-This is used to override `mu4e~headers-append-handler' to ensure that
-buffer handling is done right for `consult-mu'."
-  (with-current-buffer "*consult-mu-headers*"
-    (let ((inhibit-read-only t))
-      (seq-do
-       ;; I use mu4e-column-faces and it overrides the default append-handler. To get the same effect I check if mu4e-column-faces is active and enabled.
-       (if (and (featurep 'mu4e-column-faces) mu4e-column-faces-mode)
-           (lambda (msg)
-             (mu4e-column-faces--insert-header msg (point-max)))
-         (lambda (msg)
-           (mu4e~headers-insert-header msg (point-max))))
-       msglst))))
-
-(defun consult-mu--view-msg (msg &optional buffername)
-  "Display the message MSG in a buffer with BUFFERNAME.
-
-BUFFERNAME defaults to `consult-mu-view-buffer-name'.
-
-This s used to overrides `mu4e-view' to ensure that buffer handling is done
-right for `consult-mu'."
-  (let* ((linked-headers-buffer (mu4e-get-headers-buffer "*consult-mu-headers*" t))
-         (mu4e-view-buffer-name (or buffername consult-mu-view-buffer-name)))
-    (setq gnus-article-buffer (mu4e-get-view-buffer linked-headers-buffer t))
-    (with-current-buffer gnus-article-buffer
-      (let ((inhibit-read-only t))
-        (remove-overlays (point-min) (point-max) 'mu4e-overlay t)
-        (erase-buffer)
-        (insert-file-contents-literally
-         (mu4e-message-readable-path msg) nil nil nil t)
-        (setq-local mu4e--view-message msg)
-        (mu4e--view-render-buffer msg)
-        (mu4e-loading-mode 0)
-        (with-current-buffer linked-headers-buffer
-          (setq-local mu4e~headers-view-win (mu4e-display-buffer gnus-article-buffer nil)))
-        (run-hooks 'mu4e-view-rendered-hook)))))
-
-(defun consult-mu--headers-clear (&optional text)
-  "Clear the headers buffer and related data structures.
-
-Optionally, show TEXT.
-
-This is used to override `mu4e~headers-clear' to ensure that buffer
-handling is done right for `consult-mu'."
-  (setq mu4e~headers-render-start (float-time)
-        mu4e~headers-hidden 0)
-  (with-current-buffer "*consult-mu-headers*"
-    (let ((inhibit-read-only t))
-      (mu4e--mark-clear)
-      (erase-buffer)
-      (when text
-        (goto-char (point-min))
-        (insert (propertize text 'face 'mu4e-system-face 'intangible t))))))
-
-(defun consult-mu--set-mu4e-search-sortfield (opts)
-  "Dynamically set the `mu4e-search-sort-field' based on user input.
-
-Uses user input (i.e. from `consult-mu' command) to define the sort field.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-For example if the user enters the following in the minibuffer:
-
-“#query -- --maxnum 400 --sortfield from”
-
-`mu4e-search-sort-field' is set to :from
-
-Note that per mu4e docs:
-When threading is enabled, the headers are exclusively sorted
-chronologically (:date) by the newest message in the thread."
-  (let* ((sortfield (cond
-                     ((member "-s" opts) (nth (+ (cl-position "-s" opts :test 'equal) 1) opts))
-                     ((member "--sortfield" opts) (nth (+ (cl-position "--sortfield" opts :test 'equal) 1) opts))
-                     (t consult-mu-search-sort-field))))
-    (pcase sortfield
-      ('nil
-       consult-mu-search-sort-field)
-      ((or "date" "d")
-       :date)
-      ((or "subject" "s")
-       :subject)
-      ((or "size" "z")
-       :size)
-      ((or "prio" "p")
-       :prio)
-      ((or "from" "f")
-       :from)
-      ((or "to" "t")
-       :to)
-      ((or "list" "v")
-       :list)
-      ;; ((or "tags" "x")
-      ;;  :tags)
-      (_
-       consult-mu-search-sort-field))))
-
-(defun consult-mu--set-mu4e-search-sort-direction (opts)
-  "Dynamically set the `mu4e-search-sort-direction' based on user input.
-
-Uses user input \(i.e. from `consult-mu' command\) to define the sort field.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-For example, if the user enters the following in the minibuffer:
-
-“#query -- --maxnum 400 --sortfield from --reverse”
-
-The `mu4e-search-sort-direction' is reversed; If it is set to
-\='ascending, it is toggled to \='descending and vise versa."
-  (if (or (member "-z" opts) (member "--reverse" opts))
-      (pcase consult-mu-search-sort-direction
-        ('descending
-         'ascending)
-        ('ascending
-         'descending))
-    consult-mu-search-sort-direction))
-
-(defun consult-mu--set-mu4e-skip-duplicates (opts)
-  "Dynamically set the `mu4e-search-skip-duplicates' based on user input.
-
-Uses user input \(i.e. from `consult-mu' command\) to define whether to
-skip duplicates.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-For example, if the user enters the following in the minibuffer:
-
-“#query -- --maxnum 400 --skip-dups”
-
-The `mu4e-search-skip-duplicates' is set to t."
-  (if (or (member "--skip-dups" opts) mu4e-search-skip-duplicates) t nil))
-
-(defun consult-mu--set-mu4e-results-limit (opts)
-  "Dynamically set the `mu4e-search-results-limit' based on user input.
-
-
-Uses user input \(i.e. from `consult-mu' command\) to define the number of
-results shown.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-For example, if the user enters the following in the minibuffer:
-
-“#query -- --maxnum 400”
-
-The `mu4e-search-results-limit' is set to 400."
-  (cond
-   ((member "-n" opts) (string-to-number (nth (+ (cl-position "-n" opts :test 'equal) 1) opts)))
-   ((member "--maxnum" opts) (string-to-number (nth (+ (cl-position "--maxnum" opts :test 'equal) 1) opts)))
-   (t consult-mu-maxnum)))
-
-
-(defun consult-mu--set-mu4e-include-related (opts)
-  "Dynamically set the `mu4e-search-include-related' based on user input.
-
-Uses user input \(i.e. from `consult-mu' command\) to define whether to
-include related messages.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-For example if the user enters the following in the minibuffer:
-
-“#query -- --include-related”
-
-The `mu4e-search-include-related' is set to t."
-  (if (or (member "-r" opts) (member "--include-related" opts) mu4e-search-include-related) t nil))
-
-
-
-(defun consult-mu--set-mu4e-threads (opts)
-  "Set  the `mu4e-search-threads' based on `mu4e-search-sort-field'.
-
-Uses user input \(i.e. from `consult-mu' command\) to define whether to
-show threads.
-
-OPTS is the command line options for mu and can be set by entering options
-in the minibuffer input.  For more details, refer to `consult-grep' and
-consult async documentation.
-
-Note that per mu4e docs, when threading is enabled, the headers are
-exclusively sorted by date.  Here the logic is reversed in order to allow
-dynamically sorting by fields other than date \(even when threads are
-enabled\).  In other words, if the sort-field is not the :date, threading
-is disabled because otherwise sort field will be ignored.  This allows the
-user to use command line arguments to sort messages by fields other than
-the date.  For example, the user can enter the following in the minibuffer
-input to sort by subject
-
-“#query -- --sortfield subject”
-
-When the sort-field is :date, the default setting,
-`consult-mu-search-threads' is used, and if that is set to nil, the user
-can use command line arguments \(a.k.a. -t or --thread\) to enable it
-dynamically."
-  (cond
-   ((not (equal mu4e-search-sort-field :date))
-    nil)
-   ((or (member "-t" opts) (member "--threads" opts) consult-mu-search-threads)
-    t)))
-
-(defun consult-mu--update-headers (query ignore-history msg type)
-  "Search for QUERY, and update `consult-mu-headers-buffer-name' buffer.
-
-If IGNORE-HISTORY is true, does *not* update the query history stack,
-`mu4e--search-query-past'.
-If MSG is non-nil, put the cursor on MSG.
-TYPE can be either \=':dynamic or \=':async"
-  (consult-mu--execute-all-marks)
-  (cl-letf* (((symbol-function #'mu4e~headers-append-handler) #'consult-mu--headers-append-handler))
-    (unless (mu4e-running-p) (mu4e--server-start))
-    (let* ((buf (mu4e-get-headers-buffer consult-mu-headers-buffer-name t))
-           (view-buffer (get-buffer consult-mu-view-buffer-name))
-           (expr (car (consult--command-split (substring-no-properties query))))
-           (rewritten-expr (funcall mu4e-query-rewrite-function expr))
-           (mu4e-headers-fields consult-mu-headers-fields))
-      (pcase type
-        (:dynamic)
-        (:async
-         (setq rewritten-expr (funcall mu4e-query-rewrite-function (concat "msgid:" (plist-get msg :message-id)))))
-        (_ ))
-
-      (with-current-buffer buf
-        (save-excursion
-          (let ((inhibit-read-only t))
-            (erase-buffer)
-            (mu4e-headers-mode)
-            (setq-local mu4e-view-buffer-name consult-mu-view-buffer-name)
-            (if view-buffer
-                (setq-local mu4e~headers-view-win (mu4e-display-buffer gnus-article-buffer nil)))
-            (unless ignore-history
-                                        ; save the old present query to the history list
-              (when mu4e--search-last-query
-                (mu4e--search-push-query mu4e--search-last-query 'past)))
-            (setq mu4e--search-last-query rewritten-expr)
-            (setq list-buffers-directory rewritten-expr)
-            (mu4e--modeline-update)
-            (run-hook-with-args 'mu4e-search-hook expr)
-            (consult-mu--headers-clear mu4e~search-message)
-            (setq mu4e~headers-search-start (float-time))
-
-            (pcase-let* ((`(,_arg . ,opts) (consult--command-split query))
-                         (mu4e-search-sort-field (consult-mu--set-mu4e-search-sortfield opts))
-                         (mu4e-search-sort-direction (consult-mu--set-mu4e-search-sort-direction opts))
-                         (mu4e-search-skip-duplicates (consult-mu--set-mu4e-skip-duplicates opts))
-                         (mu4e-search-results-limit (consult-mu--set-mu4e-results-limit opts))
-                         (mu4e-search-threads (consult-mu--set-mu4e-threads opts))
-                         (mu4e-search-include-related (consult-mu--set-mu4e-include-related opts)))
-              (mu4e--server-find
-               rewritten-expr
-               mu4e-search-threads
-               mu4e-search-sort-field
-               mu4e-search-sort-direction
-               mu4e-search-results-limit
-               mu4e-search-skip-duplicates
-               mu4e-search-include-related))
-            (while (or (string-empty-p (buffer-substring (point-min) (point-max)))
-                       (equal (buffer-substring (point-min) (+ (point-min) (length mu4e~search-message))) mu4e~search-message)
-                       (not (or (equal (buffer-substring (- (point-max) (length mu4e~no-matches)) (point-max)) mu4e~no-matches) (equal (buffer-substring (- (point-max) (length mu4e~end-of-results)) (point-max)) mu4e~end-of-results))))
-              (sleep-for 0.005))))))))
-
-(defun consult-mu--execute-all-marks (&optional no-confirmation)
-  "Execute the actions for all marked messages.
-
-Executes all actions for marked messages in the buffer
-`consult-mu-headers-buffer-name'.
-
-If NO-CONFIRMATION is non-nil, don't ask user for confirmation.
-
-This is similar to `mu4e-mark-execute-all' but, with buffer/window
-handling set accordingly for `consult-mu'."
-  (interactive "P")
-  (when-let* ((buf (get-buffer consult-mu-headers-buffer-name)))
-    (with-current-buffer buf
-      (when (eq major-mode 'mu4e-headers-mode)
-        (mu4e--mark-in-context
-         (let* ((marknum (mu4e-mark-marks-num)))
-           (unless (zerop marknum)
-             (pop-to-buffer buf)
-             (unless (one-window-p) (delete-other-windows))
-             (mu4e-mark-execute-all no-confirmation)
-             (quit-window))))))))
-
-(defun consult-mu--headers-goto-message-id (msgid)
-  "Jump to message with MSGID.
-
-This is done in `consult-mu-headers-buffer-name' buffer."
-  (when-let ((buffer consult-mu-headers-buffer-name))
-    (with-current-buffer buffer
-      (setq mu4e-view-buffer-name consult-mu-view-buffer-name)
-      (mu4e-headers-goto-message-id msgid))))
-
-(defun consult-mu--get-message-by-id (msgid)
-  "Find the message with MSGID and return the mu4e MSG plist for it."
-  (cl-letf* (((symbol-function #'mu4e-view) #'consult-mu--view-msg))
-    (when-let ((buffer consult-mu-headers-buffer-name))
-      (with-current-buffer buffer
-        (setq mu4e-view-buffer-name consult-mu-view-buffer-name)
-        (mu4e-headers-goto-message-id msgid)
-        (mu4e-message-at-point)))))
-
-(defun consult-mu--contact-string-to-plist (string)
-  "Convert STRING for contacts to plist.
-
-STRING is the output form mu command, for example from:
-`mu find query --fields f`
-
-Returns a plist with \=':email and \':name keys.
-
-For example
-
-“John Doe <john.doe@example.com>”
-
-will be converted to
-
-\(:name “John Doe” :email “john.doe@example.com”\)"
-  (let* ((string (replace-regexp-in-string ">,\s\\|>;\s" ">\n" string))
-         (list (split-string string "\n" t)))
-    (mapcar (lambda (item)
-              (cond
-               ((string-match "\\(?2:.*\\)\s+<\\(?1:.+\\)>" item)
-                (list :email (or (match-string 1 item) nil) :name (or (match-string 2 item) nil)))
-               ((string-match "^\\(?1:[a-zA-Z0-9\_\.\+\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+\\)" item)
-                (list :email (or (match-string 1 item) nil) :name nil))
-               (t
-                (list :email (format "%s" item) :name nil)))) list)))
-
-(defun consult-mu--contact-name-or-email (contact)
-  "Retrieve name or email of CONTACT.
-
-Looks at the contact plist \(e.g. (:name “John Doe” :email
-“john.doe@example.com”)\) and returns the name.  If the name is missing,
-returns the email address."
-  (cond
-   ((stringp contact)
-    contact)
-   ((listp contact)
-    (mapconcat (lambda (item) (or (plist-get item :name) (plist-get item :email) "")) contact ","))))
-
-(defun consult-mu--headers-template ()
-  "Make headers template using `consult-mu-headers-template'."
-  (if (and consult-mu-headers-template (functionp consult-mu-headers-template))
-      (funcall consult-mu-headers-template)
-    consult-mu-headers-template))
-
-(defun consult-mu--expand-headers-template (msg string)
-  "Expand STRING to create a custom header format for MSG.
-
-See `consult-mu-headers-template' for explanation of the format of
-STRING."
-
-  (cl-loop for c in (split-string string "%" t)
-           concat (concat (pcase  (substring c 0 1)
-                            ("f" (let ((sender (consult-mu--contact-name-or-email (plist-get msg :from)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if sender
-                                       (propertize (if (> length 0) (consult-mu--set-string-width sender length) sender) 'face 'consult-mu-sender-face))))
-                            ("t" (let ((receiver (consult-mu--contact-name-or-email (plist-get msg :to)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if receiver
-                                       (propertize (if (> length 0) (consult-mu--set-string-width receiver length) receiver) 'face 'consult-mu-sender-face))))
-                            ("s" (let ((subject (plist-get msg :subject))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if subject
-                                       (propertize (if (> length 0) (consult-mu--set-string-width subject length) subject) 'face 'consult-mu-subject-face))))
-                            ("d" (let ((date (format-time-string "%a %d %b %y" (plist-get msg :date)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if date
-                                       (propertize (if (> length 0) (consult-mu--set-string-width date length) date) 'face 'consult-mu-date-face))))
-
-                            ("p" (let ((priority (plist-get msg :priority))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if priority
-                                       (propertize (if (> length 0) (consult-mu--set-string-width (format "%s" priority) length) (format "%s" priority)) 'face 'consult-mu-size-face))))
-                            ("z" (let ((size (file-size-human-readable (plist-get msg :size)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if size
-                                       (propertize (if (> length 0) (consult-mu--set-string-width size length) size)  'face 'consult-mu-size-face))))
-                            ("i" (let ((id (plist-get msg :message-id))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if id
-                                       (propertize (if (> length 0) (consult-mu--set-string-width id length) id) 'face 'consult-mu-default-face))))
-
-                            ("g" (let ((flags  (plist-get msg :flags))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if flags
-                                       (propertize (if (> length 0) (consult-mu--set-string-width (format "%s" flags) length) (format "%s" flags)) 'face 'consult-mu-flags-face))))
-
-                            ("G" (let ((flags (plist-get msg :flags))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if flags
-                                       (propertize (if (> length 0) (consult-mu--set-string-width (format "%s" (mu4e~headers-flags-str flags)) length) (format "%s" (mu4e~headers-flags-str flags))) 'face 'consult-mu-flags-face))))
-
-                            ("x" (let ((tags (plist-get msg :tags))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if tags
-                                       (propertize (if (> length 0) (consult-mu--set-string-width tags length) tags) 'face 'consult-mu-tags-face) nil)))
-
-                            ("c" (let ((cc (consult-mu--contact-name-or-email (plist-get msg :cc)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if cc
-                                       (propertize (if (> length 0) (consult-mu--set-string-width cc length) cc) 'face 'consult-mu-tags-face))))
-
-                            ("h" (let ((bcc (consult-mu--contact-name-or-email (plist-get msg :bcc)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if bcc
-                                       (propertize (if (> length 0) (consult-mu--set-string-width bcc length) bcc) 'face 'consult-mu-tags-face))))
-
-                            ("r" (let ((changed (format-time-string "%a %d %b %y" (plist-get msg :changed)))
-                                       (length (string-to-number (substring c 1 nil))))
-                                   (if changed
-                                       (propertize (if (> length 0) (consult-mu--set-string-width changed length) changed) 'face 'consult-mu-tags-face))))
-                            (_ nil))
-                          "  ")))
-
-(defun consult-mu--quit-header-buffer ()
-  "Quits `consult-mu-headers-buffer-name' buffer."
-  (save-mark-and-excursion
-    (when-let* ((buf (get-buffer consult-mu-headers-buffer-name)))
-      (with-current-buffer buf
-        (if (eq major-mode 'mu4e-headers-mode)
-            (mu4e-mark-handle-when-leaving)
-          (quit-window t)
-          ;; clear the decks before going to the main-view
-          (mu4e--query-items-refresh 'reset-baseline))))))
-
-(defun consult-mu--quit-view-buffer ()
-  "Quits `consult-mu-view-buffer-name' buffer."
-  (when-let* ((buf (get-buffer consult-mu-view-buffer-name)))
-    (with-current-buffer buf
-      (if (eq major-mode 'mu4e-view-mode)
-          (mu4e-view-quit)))))
-
-(defun consult-mu--quit-main-buffer ()
-  "Quits `mu4e-main-buffer-name' buffer."
-  (when-let* ((buf (get-buffer mu4e-main-buffer-name)))
-    (with-current-buffer buf
-      (if (eq major-mode 'mu4e-main-mode)
-          (mu4e-quit)))))
-
-(defun consult-mu--lookup ()
-  "Lookup function for `consult-mu' or `consult-mu-async' candidates.
-
-This is passed as LOOKUP to `consult--read' on candidates and is used to
-format the output when a candidate is selected."
-  (lambda (sel cands &rest _args)
-    (let* ((info (cdr (assoc sel cands)))
-           (msg  (plist-get info :msg))
-           (subject (plist-get msg :subject)))
-      (cons subject info))))
-
-(defun consult-mu--group-name (cand)
-  "Get the group name of CAND using `consult-mu-group-by'.
-
-See `consult-mu-group-by' for details of grouping options."
-  (let* ((msg (get-text-property 0 :msg cand))
-         (group (or consult-mu--override-group consult-mu-group-by))
-         (field (if (not (keywordp group)) (intern (concat ":" (format "%s" group))) group)))
-    (pcase field
-      (:date (format-time-string "%a %d %b %y" (plist-get msg field)))
-      (:from (cond
-              ((listp (plist-get msg field))
-               (mapconcat (lambda (item) (or (plist-get item :name) (plist-get item :email))) (plist-get msg field) ";"))
-              ((stringp (plist-get msg field)) (plist-get msg field))))
-      (:to (cond
-            ((listp (plist-get msg field))
-             (mapconcat (lambda (item) (or (plist-get item :name) (plist-get item :email))) (plist-get msg field) ";"))
-            ((stringp (plist-get msg field)) (plist-get msg field))))
-      (:changed (format-time-string "%a %d %b %y" (plist-get msg field)))
-      (:datetime (format-time-string "%F %r" (plist-get msg :date)))
-      (:time (format-time-string "%X" (plist-get msg :date)))
-      (:year (format-time-string "%Y" (plist-get msg :date)))
-      (:month (format-time-string "%B" (plist-get msg :date)))
-      (:day-of-week (format-time-string "%A" (plist-get msg :date)))
-      (:day (format-time-string "%A" (plist-get msg :date)))
-      (:week (format-time-string "%V" (plist-get msg :date)))
-      (:size (file-size-human-readable (plist-get msg field)))
-      (:flags (format "%s" (plist-get msg field)))
-      (:tags (format "%s" (plist-get msg field)))
-      (_ (if (plist-get msg field) (format "%s" (plist-get msg field)) nil)))))
-
-(defun consult-mu--group (cand transform)
-  "Group function for `consult-mu' or `consult-mu-async'.
-
-CAND is passed to `consult-mu--group-name' to get the group for CAND.
-When TRANSFORM is non-nil, the name of CAND is used for group."
-  (when-let ((name (consult-mu--group-name cand)))
-    (if transform (substring cand) name)))
-
-(defun consult-mu--view (msg noselect mark-as-read match-str)
-  "Opens MSG in `consult-mu-headers' and `consult-mu-view'.
-
-If NOSELECT is non-nil, does not select the view buffer/window.
-If MARK-AS-READ is non-nil, marks the MSG as read.
-If MATCH-STR is non-nil, highlights the MATCH-STR in the view buffer."
-  (let ((msgid (plist-get msg :message-id)))
-    (when-let ((buf (mu4e-get-headers-buffer consult-mu-headers-buffer-name t)))
-      (with-current-buffer buf
-        ;;(mu4e-headers-mode)
-        (goto-char (point-min))
-        (setq mu4e-view-buffer-name consult-mu-view-buffer-name)
-        (unless noselect
-          (switch-to-buffer buf))))
-
-    (consult-mu--view-msg msg consult-mu-view-buffer-name)
-
-    (with-current-buffer consult-mu-headers-buffer-name
-      (if msgid
-          (progn
-            (mu4e-headers-goto-message-id msgid)
-            (if mark-as-read
-                (mu4e--server-move (mu4e-message-field-at-point :docid) nil "+S-u-N")))))
-
-    (when match-str
-      (add-to-history 'search-ring match-str)
-      (consult-mu--overlay-match match-str consult-mu-view-buffer-name t))
-
-    (with-current-buffer consult-mu-view-buffer-name
-      (goto-char (point-min)))
-
-    (unless noselect
-      (when msg
-        (select-window (get-buffer-window consult-mu-view-buffer-name))))
-    consult-mu-view-buffer-name))
-
-
-(defun consult-mu--view-action (cand)
-  "Open the candidate, CAND.
-
-This is a wrapper function around `consult-mu--view'.  It parses CAND to
-extract relevant MSG plist and other information and passes them to
-`consult-mu--view'.
-
-To use this as the default action for `consult-mu', set
-`consult-mu-default-action' to \=#'consult-mu--view-action."
-
-  (let* ((info (cdr cand))
-         (msg (plist-get info :msg))
-         (query (plist-get info :query))
-         (match-str (car (consult--command-split query))))
-    (consult-mu--view msg nil consult-mu-mark-viewed-as-read match-str)
-    (consult-mu-overlays-toggle consult-mu-view-buffer-name)))
-
-(defun consult-mu--reply (msg &optional wide-reply)
-  "Reply to MSG using `mu4e-compose-reply'.
-
-If WIDE-REPLY is non-nil use wide-reply \(a.k.a. reply all\) with
-`mu4e-compose-wide-reply'."
-  (let ((msgid (plist-get msg :message-id)))
-    (when-let ((buf (mu4e-get-headers-buffer consult-mu-headers-buffer-name t)))
-      (with-current-buffer buf
-        (goto-char (point-min))
-        (setq mu4e-view-buffer-name consult-mu-view-buffer-name)))
-
-
-    (with-current-buffer consult-mu-headers-buffer-name
-      (mu4e-headers-goto-message-id msgid)
-      (if (not wide-reply)
-          (mu4e-compose-reply)
-        (mu4e-compose-wide-reply)))))
-
-(defun consult-mu--reply-action (cand &optional wide-reply)
-  "Reply to CAND.
-
-This is a wrapper function around `consult-mu--reply'.  It passes
-relevant message plist, from CAND, as well as WIDE-REPLY to
-`consult-mu--reply'.
-
-To use this as the default action for `consult-mu', set
-`consult-mu-default-action' to \=#'consult-mu--reply-action."
-  (let* ((info (cdr cand))
-         (msg (plist-get info :msg))
-         (wide-reply (or wide-reply
-                         (pcase consult-mu-use-wide-reply
-                           ('ask (y-or-n-p "Reply All?"))
-                           ('nil nil)
-                           ('t t)))))
-    (consult-mu--reply msg wide-reply)))
-
-(defun consult-mu--forward (msg)
-  "Forward the MSG using `mu4e-compose-forward'."
-  (let ((msgid (plist-get msg :message-id)))
-    (when-let ((buf (mu4e-get-headers-buffer consult-mu-headers-buffer-name t)))
-      (with-current-buffer buf
-        (goto-char (point-min))
-        (setq mu4e-view-buffer-name consult-mu-view-buffer-name)))
-    (with-current-buffer consult-mu-headers-buffer-name
-      (mu4e-headers-goto-message-id msgid)
-      (mu4e-compose-forward))))
-
-(defun consult-mu--forward-action (cand)
-  "Forward CAND.
-
-This is a wrapper function around `consult-mu--forward'.  It passes
-the relevant message plist, from CAND to `consult-mu--forward'.
-
-To use this as the default action for `consult-mu', set
-`consult-mu-default-action' to \=#'consult-mu--forward-action."
-  (let* ((info (cdr cand))
-         (msg (plist-get info :msg)))
-    (consult-mu--forward msg)))
-
-(defun consult-mu--get-split-style-character (&optional style)
-  "Get the character for consult async split STYLE.
-
-STYLE defaults to `consult-async-split-style'."
-  (let ((style (or style consult-async-split-style 'none)))
-    (or (char-to-string (plist-get (alist-get style consult-async-split-styles-alist) :initial))
-        (char-to-string (plist-get (alist-get style consult-async-split-styles-alist) :separator))
-        "")))
-
-(defun consult-mu--dynamic-format-candidate (cand highlight)
-  "Format minibuffer candidate, CAND.
-
-CAND is the minibuffer completion candidate \(a mu4e message collected by
-`consult-mu--dynamic-collection'\).  If HIGHLIGHT is non-nil, it is
-highlighted with `consult-mu-highlight-match-face'."
-
-  (let* ((string (car cand))
-         (info (cadr cand))
-         (msg (plist-get info :msg))
-         (query (plist-get info :query))
-         (match-str (if (stringp query) (consult--split-escaped (car (consult--command-split query))) nil))
-         (headers-template (consult-mu--headers-template))
-         (str (if headers-template
-                  (consult-mu--expand-headers-template msg headers-template)
-                string))
-         (str (propertize str :msg msg :query query :type :dynamic)))
-    (if (and consult-mu-highlight-matches highlight)
-        (cond
-         ((listp match-str)
-          (mapc (lambda (match) (setq str (consult-mu--highlight-match match str t))) match-str))
-         ((stringp match-str)
-          (setq str (consult-mu--highlight-match match-str str t))))
-      str)
-    (when msg
-      (cons str (list :msg msg :query query :type :dynamic)))))
-
-(defun consult-mu--dynamic-collection (input)
-  "Dynamically collect mu4e search results.
-
-INPUT is the user input.  It is passed as QUERY to
-`consult-mu--update-headers', appends the result to
-`consult-mu-headers-buffer-name' and returns a list of found
-messages."
-
-  (save-excursion
-    (pcase-let* ((`(,_arg . ,opts) (consult--command-split input)))
-      (consult-mu--update-headers (substring-no-properties input) nil nil :dynamic)
-      (if (or (member "-g" opts)  (member "--group" opts))
-          (cond
-           ((member "-g" opts)
-            (setq consult-mu--override-group (intern (or (nth (+ (cl-position "-g" opts :test 'equal) 1) opts) "nil"))))
-           ((member "--group" opts)
-            (setq consult-mu--override-group (intern (or (nth (+ (cl-position "--group" opts :test 'equal) 1) opts) "nil")))))
-        (setq consult-mu--override-group nil)))
-
-    (with-current-buffer consult-mu-headers-buffer-name
-      (goto-char (point-min))
-      (remove nil
-              (cl-loop until (eobp)
-                       collect (consult-mu--dynamic-format-candidate (list (buffer-substring (point) (line-end-position)) (list :msg (ignore-errors (mu4e-message-at-point)) :query input)) t)
-                       do (forward-line 1))))))
-
-(defun consult-mu--dynamic-state ()
-  "State function for `consult-mu' candidates.
-This is passed as STATE to `consult--read' and is used to preview or do
-other actions on the candidate."
-  (lambda (action cand)
-    (let ((preview (consult--buffer-preview)))
-      (pcase action
-        ('preview
-         (if cand
-             (when-let* ((info (cdr cand))
-                         (msg (plist-get info :msg))
-                         (query (plist-get info :query))
-                         (msgid (substring-no-properties (plist-get msg :message-id)))
-                         (match-str (car (consult--command-split query)))
-                         (match-str (car (consult--command-split query)))
-                         (mu4e-headers-buffer-name consult-mu-headers-buffer-name)
-                         (buffer consult-mu-view-buffer-name))
-               ;;(get-buffer-create consult-mu-view-buffer-name)
-               (add-to-list 'consult-mu--view-buffers-list buffer)
-               (funcall preview action
-                        (consult-mu--view msg t consult-mu-mark-previewed-as-read match-str))
-               (with-current-buffer consult-mu-view-buffer-name
-                 (unless (one-window-p) (delete-other-windows))))))
-        ('return
-         (save-mark-and-excursion
-           (consult-mu--execute-all-marks))
-         (setq consult-mu--override-group nil)
-         cand)))))
-
-(defun consult-mu--dynamic (prompt collection &optional initial)
-  "Query mu4e messages dyunamically.
-
-This is a non-interactive internal function.  For the interactive version
-see `consult-mu'.
-
-It runs the `consult-mu--dynamic-collection' to do a `mu4e-search' with
-user input \(e.g. INITIAL\) and returns the results \(list of messages
-found\) as a completion table in minibuffer.
-
-The completion table gets dynamically updated as the user types in the
-minibuffer.  Each candidate in the minibuffer is formatted by
-`consult-mu--dynamic-format-candidate' to add annotation and other info to
-the candidate.
-
-Description of Arguments:
-  PROMPT     the prompt in the minibuffer
-             \(passed as PROMPT to   `consult--read'\)
-  COLLECTION a colection function passed to `consult--dynamic-collection'.
-  INITIAL    an optional arg for the initial input in the minibuffer.
-             \(passed as INITITAL to `consult--read'\)
-
-commandline arguments/options \(see `mu find --help` in the command line
-for details\) can be passed to the minibuffer input similar to
-`consult-grep'.  For example the user can enter:
-
-“#paper -- --maxnum 200 --sortfield from --reverse”
-
-this will search for mu4e messages with the query “paper”, retrives a
-maximum of 200 messages and sorts them by the “from:” field and reverses
-the sort direction (opposite of `consult-mu-search-sort-field').
-
-Note that some command line arguments are not supported by mu4e (for
-example sorting based on cc: or bcc: fields are not supported in
-`mu4e-search-sort-field')
-
-Also, the results can further be narrowed by
-`consult-async-split-style' \(e.g. by entering “#” when
-`consult-async-split-style' is set to \='perl\).
-
-For example:
-
-“#paper -- --maxnum 200 --sortfield from --reverse#accepted”
-
-will retrieve the message as the example above, then narrows down the
-candidates to those that  that match “accepted”."
-  (consult--read
-   (consult--dynamic-collection (or collection #'consult-mu--dynamic-collection))
-   :prompt (or prompt "Select: ")
-   :lookup (consult-mu--lookup)
-   :state (funcall #'consult-mu--dynamic-state)
-   :initial initial
-   :group #'consult-mu--group
-   :add-history (append (list (thing-at-point 'symbol))
-                        consult-mu-saved-searches-dynamic)
-   :history '(:input consult-mu--history)
-   :require-match t
-   :category 'consult-mu-messages
-   :preview-key consult-mu-preview-key
-   :sort nil))
-
-(defun consult-mu-dynamic (&optional initial noaction)
-  "Lists results of `mu4e-search' dynamically.
-
-This is an interactive wrapper function around `consult-mu--dynamic'.  It
-queries the user for a search term in the minibuffer, then fetches a list
-of messages for the entered search term as a minibuffer completion table
-for selection.  The list of candidates in the completion table are
-dynamically updated as the user changes the entry.
-
-Upon selection of a candidate either
- - the candidate is returned if NOACTION is non-nil
- or
- - the candidate is passed to `consult-mu-action' if NOACTION is nil.
-
-Additional commandline arguments can be passed in the minibuffer entry by
-typing “--” followed by command line arguments.
-
-For example, the user can enter:
-
-“#consult-mu -- -n 10”
-
-this will run a `mu4e-search' with the query “consult-mu” and changes the
-search limit \(i.e. `mu4e-search-results-limit' to 10\).
-
-
-Also, the results can further be narrowed by
-`consult-async-split-style' \(e.g. by entering “#” when
-`consult-async-split-style' is set to \='perl\).
-
-For example:
-
-“#consult-mu -- -n 10#github”
-
-will retrieve the messages as the example above, then narrows down the
-completion table to candidates that match “github”.
-
-INITIAL is an optional arg for the initial input in the minibuffer.
-\(passed as INITITAL to `consult-mu--dynamic'\)
-
-For more details on consult--async functionalities, see `consult-grep' and
-the official manual of consult, here:
-URL `https://github.com/minad/consult'"
-  (interactive)
-  (save-mark-and-excursion
-    (consult-mu--execute-all-marks))
-  (let* ((sel
-          (consult-mu--dynamic (concat "[" (propertize "consult-mu-dynamic" 'face 'consult-mu-sender-face) "]" " Search For:  ") #'consult-mu--dynamic-collection initial)))
-    (save-mark-and-excursion
-      (consult-mu--execute-all-marks))
-    (if noaction
-        sel
-      (progn
-        (funcall consult-mu-action sel)
-        sel))))
-
-(defun consult-mu--async-format-candidate (string input highlight)
-  "Formats minibuffer candidates for `consult-mu-async'.
-
-STRING is the output retrieved from `mu find INPUT ...` in the command line.
-INPUT is the query from the user.
-
-If HIGHLIGHT is t, input is highlighted with
-`consult-mu-highlight-match-face' in the minibuffer."
-
-  (let* ((query input)
-         (parts (split-string (replace-regexp-in-string "^\\\\->\s\\|^\\\/->\s" "" string) consult-mu-delimiter))
-         (msgid (car parts))
-         (date (date-to-time (cadr parts)))
-         (sender (cadr (cdr parts)))
-         (sender (consult-mu--contact-string-to-plist sender))
-         (receiver (cadr (cdr (cdr parts))))
-         (receiver (consult-mu--contact-string-to-plist receiver))
-         (subject (cadr (cdr (cdr (cdr parts)))))
-         (size (string-to-number (cadr (cdr (cdr (cdr (cdr parts)))))))
-         (flags (consult-mu-flags-to-string (cadr (cdr (cdr (cdr (cdr (cdr parts))))))))
-         (tags (cadr (cdr (cdr (cdr (cdr (cdr (cdr parts))))))))
-         (priority (cadr (cdr (cdr (cdr (cdr (cdr (cdr (cdr parts)))))))))
-         (cc (cadr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr parts))))))))))
-         (cc (consult-mu--contact-string-to-plist cc))
-         (bcc (cadr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr parts)))))))))))
-         (bcc (consult-mu--contact-string-to-plist bcc))
-         (path (cadr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr (cdr parts))))))))))))
-         (msg (list :subject subject :date date :from sender :to receiver :size size :message-id msgid :flags flags :tags tags :priority priority :cc cc :bcc bcc :path path))
-         (match-str (if (stringp input) (consult--split-escaped (car (consult--command-split query))) nil))
-         (headers-template (consult-mu--headers-template))
-         (str (if headers-template
-                  (consult-mu--expand-headers-template msg headers-template)
-                (format "%s\s\s%s\s\s%s\s\s%s\s\s%s\s\s%s"
-                        (propertize (consult-mu--set-string-width
-                                     (format-time-string "%x" date) 10)
-                                    'face 'consult-mu-date-face)
-                        (propertize (consult-mu--set-string-width (consult-mu--contact-name-or-email sender) (floor (* (frame-width) 0.2)))  'face 'consult-mu-sender-face)
-                        (propertize (consult-mu--set-string-width subject (floor (* (frame-width) 0.55))) 'face 'consult-mu-subject-face)
-                        (propertize (file-size-human-readable size) 'face 'consult-mu-size-face)
-                        (propertize (format "%s" flags) 'face 'consult-mu-flags-face)
-                        (propertize (if tags (format "%s" tags) nil) 'face 'consult-mu-tags-face))))
-         (str (propertize str :msg msg :query query :type :async)))
-    (if (and consult-mu-highlight-matches highlight)
-        (cond
-         ((listp match-str)
-          (mapc (lambda (match) (setq str (consult-mu--highlight-match match str t))) match-str))
-         ((stringp match-str)
-          (setq str (consult-mu--highlight-match match-str str t))))
-      str)
-    (cons str (list :msg msg :query query :type :async))))
-
-(defun consult-mu--async-state ()
-  "State function for `consult-mu-async' candidates.
-
-This is passed as STATE to `consult--read' and is used to preview or do
-other actions on the candidate."
-  (lambda (action cand)
-    (let ((preview (consult--buffer-preview)))
-      (pcase action
-        ('preview
-         (if cand
-             (when-let* ((info (cdr cand))
-                         (msg (plist-get info :msg))
-                         (msgid (substring-no-properties (plist-get msg :message-id)))
-                         (query (plist-get info :query))
-                         (match-str (car (consult--command-split query)))
-                         (mu4e-headers-buffer-name consult-mu-headers-buffer-name)
-                         (buffer consult-mu-view-buffer-name))
-               (add-to-list 'consult-mu--view-buffers-list buffer)
-               (funcall preview action
-                        (consult-mu--view msg t consult-mu-mark-previewed-as-read match-str))
-               (with-current-buffer consult-mu-view-buffer-name
-                 (unless (one-window-p) (delete-other-windows))))))
-        ('return
-         (save-mark-and-excursion
-           (consult-mu--execute-all-marks))
-         cand)))))
-
-(defun consult-mu--async-transform (input)
-  "Add annotation to minibuffer candiates for `consult-mu'.
-
-Format each candidates with `consult-gh--repo-format' and INPUT."
-  (lambda (cands)
-    (cl-loop for cand in cands
-             collect
-             (consult-mu--async-format-candidate cand input t))))
-
-(defun consult-mu--async-builder (input)
-  "Build mu command line for searching messages by INPUT (e.g. `mu find INPUT)`."
-  (pcase-let* ((consult-mu-args (append consult-mu-args '("find")))
-               (cmd (consult--build-args consult-mu-args))
-               (`(,arg . ,opts) (consult--command-split input))
-               (flags (append cmd opts))
-               (sortfield (cond
-                           ((member "-s" flags) (nth (+ (cl-position "-s" opts :test 'equal) 1) flags))
-                           ((member "--sortfield" flags) (nth (+ (cl-position "--sortfield" flags :test 'equal) 1) flags))
-                           (t (substring (symbol-name consult-mu-search-sort-field) 1))))
-               (threads (if (not (equal sortfield :date)) nil (or (member "-t" flags) (member "--threads" flags) mu4e-search-threads)))
-               (skip-dups (or (member "-u" flags) (member "--skip-dups" flags) mu4e-search-skip-duplicates))
-               (include-related (or (member "-r" flags) (member "--include-related" flags) mu4e-search-include-related)))
-    (if (or (member "-g" flags)  (member "--group" flags))
-        (cond
-         ((member "-g" flags)
-          (setq consult-mu--override-group (intern (or (nth (+ (cl-position "-g" opts :test 'equal) 1) opts) "nil")))
-          (setq opts (remove "-g" (remove (nth (+ (cl-position "-g" opts :test 'equal) 1) opts) opts))))
-         ((member "--group" flags)
-          (setq consult-mu--override-group (intern (or (nth (+ (cl-position "--group" opts :test 'equal) 1) opts) "nil")))
-          (setq opts (remove "--group" (remove (nth (+ (cl-position "--group" opts :test 'equal) 1) opts) opts)))))
-      (setq consult-mu--override-group nil))
-    (setq opts (append opts (list "--nocolor")))
-    (setq opts (append opts (list "--fields" (format "i%sd%sf%st%ss%sz%sg%sx%sp%sc%sh%sl"
-                                                     consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter consult-mu-delimiter))))
-    (unless (or (member "-s" flags) (member "--sortfiled" flags))
-      (setq opts (append opts (list "--sortfield" (substring (symbol-name consult-mu-search-sort-field) 1)))))
-    (if threads (setq opts (append opts (list "--thread"))))
-    (if skip-dups (setq opts (append opts (list "--skip-dups"))))
-    (if include-related (setq opts (append opts (list "--include-related"))))
-    (cond
-     ((and (member "-n" flags) (< (string-to-number (nth (+ (cl-position "-n" opts :test 'equal) 1) opts)) 0))
-      (setq opts (remove "-n" (remove (nth (+ (cl-position "-n" opts :test 'equal) 1) opts) opts))))
-     ((and (member "--maxnum" flags) (< (string-to-number (nth (+ (cl-position "--maxnum" opts :test 'equal) 1) opts)) 0))
-      (setq opts (remove "--maxnum" (remove (nth (+ (cl-position "--maxnum" opts :test 'equal) 1) opts) opts)))))
-    (unless (or (member "-n" flags)  (member "--maxnum" flags))
-      (if (and consult-mu-maxnum (> consult-mu-maxnum 0))
-          (setq opts (append opts (list "--maxnum" (format "%s" consult-mu-maxnum))))))
-
-    (pcase consult-mu-search-sort-direction
-      ('descending
-       (if (or (member "-z" flags) (member "--reverse" flags))
-           (setq opts (remove "-z" (remove "--reverse" opts)))
-         (setq opts (append opts (list "--reverse")))))
-      ('ascending)
-      (_))
-    (pcase-let* ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'basic t)))
-      (when re
-        (cons (append cmd
-                      (list (string-join re " "))
-                      opts)
-              hl)))))
-
-(defun consult-mu--async (prompt builder &optional initial)
-  "Query mu4e messages asynchronously.
-
-This is a non-interactive internal function.  For the interactive
-version, see `consult-mu-async'.
-
-It runs the command line from `consult-mu--async-builder' in an async
-process and returns the results (list of messages) as a completion table
-in minibuffer that will be passed to `consult--read'.  The completion
-table gets dynamically updated as the user types in the minibuffer.  Each
-candidate in the minibuffer is formatted by `consult-mu--async-transform'
-to add annotation and other info to the candidate.
-
-Description of Arguments:
-
-PROMPT  the prompt in the minibuffer
-        \(passed as PROMPT to `consult--red'\)
-BUILDER an async builder function passed to `consult--async-command'
-INITIAL an optional arg for the initial input in the minibuffer
-        \(passed as INITITAL to `consult--read'\)
-
-commandline arguments/options \(see `mu find --help` in the command line
-for details\) can be passed to the minibuffer input similar to
-`consult-grep'.  For example the user can enter:
-
-“#paper -- --maxnum 200 --sortfield from --reverse”
-
-this will search for mu4e messages with the query “paper”, retrives a
-maximum of 200 messages sorts them by the “from:” field and reverses the
-sort direction (opposite of `consult-mu-search-sort-field').
-
-Also, the results can further be narrowed by
-`consult-async-split-style' \(e.g. by entering “#” when
-`consult-async-split-style' is set to \='perl\).
-
-For example:
-
-`#paper -- --maxnum 200 --sortfield from --reverse#accepted'
-
-will retrieve the message as the example above, then narrows down the
-completion table to candidates that match “accepted”."
-  (consult--read
-   (consult--process-collection builder
-     :transform (consult--async-transform-by-input #'consult-mu--async-transform))
-   :prompt prompt
-   :lookup (consult-mu--lookup)
-   :state (funcall #'consult-mu--async-state)
-   :initial initial
-   :group #'consult-mu--group
-   :add-history (append (list (thing-at-point 'symbol))
-                        consult-mu-saved-searches-async)
-   :history '(:input consult-mu--history)
-   :require-match t
-   :category 'consult-mu-messages
-   :preview-key consult-mu-preview-key
-   :sort nil))
-
-(defun consult-mu-async (&optional initial noaction)
-  "Lists results of `mu find` Asynchronously.
-
-This is an interactive wrapper function around `consult-mu--async'.  It
-queries the user for a search term in the minibuffer, then fetches a list
-of messages for the entered search term as a minibuffer completion table
-for selection.  The list of candidates in the completion table are
-dynamically updated as the user changes the entry.
-
-Upon selection of a candidate either
- - the candidate is returned if NOACTION is non-nil
- or
- - the candidate is passed to `consult-mu-action' if NOACTION is nil.
-
-Additional commandline arguments can be passed in the minibuffer entry by
-typing `--` followed by command line arguments.
-
-For example the user can enter:
-
-`#consult-mu -- -n 10'
-
-this will run a `mu4e-search' with the query \"consult-my\" and changes the
-search limit (i.e. `mu4e-search-results-limit' to 10.
-
-
-Also, the results can further be narrowed by `consult-async-split-style'
-\(e.g. by entering “#” when `consult-async-split-style' is set to \='perl\).
-
-For example:
-
-“#consult-mu -- -n 10#github”
-
-will retrieve the message as the example above, then narrows down the
-completion table to candidates that match “github”.
-
-INITIAL is an optional arg for the initial input in the minibuffer.
-\(passed as INITITAL to `consult-mu--async'\).
-
-For more details on consult--async functionalities, see `consult-grep' and
-the official manual of consult, here:
-URL `https://github.com/minad/consult'
-
-Note that this is the async search directly using the commandline `mu`
-command and not mu4e-search. As a result, mu4e-headers buffers are not
-created until a single message is selected \(or interacted with using
-embark, etc.\)  Previews are shown in a mu4e-view buffer \(see
-`consult-mu-view-buffer-name'\) attached to an empty mu4e-headers buffer
-\(i.e. `consult-mu-headers-buffer-name'\).  This allows quick retrieval of
-many messages \(tens of thousands\) and previews, but not opening the
-results in a mu4e-headers buffer.  If you want ot open the results in a
-mu4e-headers buffer for other work flow, then you should use the
-dynamically collected function `consult-mu' which is slower if searching
-for many emails but allows follow up interactions in a mu4e-headers
-buffer."
-  (interactive)
-  (save-mark-and-excursion
-    (consult-mu--execute-all-marks))
-  (let* ((sel
-          (consult-mu--async (concat "[" (propertize "consult-mu async" 'face 'consult-mu-sender-face) "]" " Search For:  ") #'consult-mu--async-builder initial))
-         (info (cdr sel))
-         (msg (plist-get info :msg))
-         (query (plist-get info :query)))
-    (save-mark-and-excursion
-      (consult-mu--execute-all-marks))
-    (if noaction
-        sel
-      (progn
-        (consult-mu--update-headers query t msg :async))
-      (funcall consult-mu-action sel)
-      sel)))
-
-(defun consult-mu (&optional initial noaction)
-  "Default interactive command.
-
-This is a wrapper function that calls `consult-mu-default-command' with
-INITIAL and NOACTION.
-
-For example, the `consult-mu-default-command can be set to
- `#'consult-mu-dynamic' sets the default behavior to dynamic collection
- `#'consult-mu-async' sets the default behavior to async collection"
-
-  (interactive "P")
-  (funcall consult-mu-default-command initial noaction))
-
-;;; provide `consult-mu' module
-(provide 'consult-mu)
-
-;;; consult-mu.el ends here
.gitmodules
@@ -1,3 +1,6 @@
 [submodule "tools/emacs/lisp/aider.el"]
 	path = tools/emacs/lisp/aider.el
 	url = https://github.com/tninja/aider.el
+[submodule "tools/emacs/lisp/consult-mu"]
+	path = tools/emacs/lisp/consult-mu
+	url = https://github.com/armindarvish/consult-mu