mu4e-helpers: support completing-read for mu4e-read-option

Instead of using mu4e's tradional completion UI, allow for delegating to
some implementation of completing-read.

Default
  mu4e-read-option-use-builtin t

means that things work more-or-less as before.
This commit is contained in:
Dirk-Jan C. Binnema 2023-02-15 14:47:10 +02:00
parent 51ba56cf6e
commit 0c04300f61
1 changed files with 56 additions and 32 deletions

View File

@ -44,13 +44,38 @@
(defcustom mu4e-completing-read-function 'ido-completing-read (defcustom mu4e-completing-read-function 'ido-completing-read
"Function to be used to receive user-input during completion. "Function to be used to receive user-input during completion.
Suggested possible values are: Suggested possible values are:
* `completing-read': built-in completion method * `completing-read': emacs built-in completion method
* `ido-completing-read': dynamic completion within the minibuffer." * `ido-completing-read': dynamic completion within the minibuffer.
The function is used in two contexts -
1) directly - for instance in when listing _other_ maildirs
in `mu4e-ask-maildir'
2) if `mu4e-read-option-use-builtin' is nil, it is used
as part of `mu4e-read-option' in many places."
:type 'function :type 'function
:options '(completing-read ido-completing-read) :options '(completing-read ido-completing-read)
:group 'mu4e) :group 'mu4e)
(defcustom mu4e-read-option-use-builtin t
"Whether to use mu4e's traditional completion for
`mu4e-read-option'.
If nil, use the value of `mu4e-completing-read-function', integrated
into mu4e.
Note that many of the third-party completion frameworks influence
`completion-read' itself rather than offering their own e.g.
`ido-completing-read'; so to have mu4e follow your overall
settings, try the equivalent of
(setq mu4e-read-option-use-builtin nil
mu4e-completing-read-function \\='completing-read)"
:type 'boolean
:group 'mu4e)
(defcustom mu4e-use-fancy-chars nil (defcustom mu4e-use-fancy-chars nil
"When set, allow fancy (Unicode) characters for marks/threads. "When set, allow fancy (Unicode) characters for marks/threads.
You can customize the exact fancy characters used with You can customize the exact fancy characters used with
@ -167,25 +192,21 @@ Return the cdr (value) of the matching cell, if any."
(if match (cdadr match) (if match (cdadr match)
(when match-ci (cdadr match-ci))))) (when match-ci (cdadr match-ci)))))
(defun new/mu4e--read-char-choice (prompt candidates) (defun mu4e--read-choice-completing-read (prompt choices)
"Run a quick `completing-read' for the given CANDIDATES. "Read and return one of CHOICES, prompting for PROMPT.
List of CANDIDATES is a list of strings. The first character is PROMPT describes a multiple-choice question to the user. CHOICES
used for quick selection." is an alist of the fiorm
(let* ((candidates-alist ( ( <display-string> ( <shortcut> . <value> ))
(mapcar (lambda (cand) ... )
(prog1 Any input that is not one of CHOICES is ignored. This is mu4e's
(cons version of `read-char-choice' which becomes case-insensitive
(concat "[" after trying an exact match.
(propertize (substring cand 0 1)
'face 'mu4e-highlight-face) Return the matching choice value (cdr of the cell)."
"]" (let* ((metadata `(metadata
(substring cand 1))
cand)))
candidates))
(metadata `(metadata
(display-sort-function . ,#'identity) (display-sort-function . ,#'identity)
(cycle-sort-function . ,#'identity))) (cycle-sort-function . ,#'identity)))
(quick-result) (quick-result)
(result (result
(minibuffer-with-setup-hook (minibuffer-with-setup-hook
@ -195,24 +216,22 @@ used for quick selection."
;; Exit directly if a quick key is pressed ;; Exit directly if a quick key is pressed
(let ((prefix (minibuffer-contents-no-properties))) (let ((prefix (minibuffer-contents-no-properties)))
(unless (string-empty-p prefix) (unless (string-empty-p prefix)
(mapc (lambda (cand) (setq quick-result
(when (string-prefix-p prefix (cdr cand) t) (mu4e--matching-choice choices (string-to-char prefix)))
(setq quick-result cand) (when quick-result
(exit-minibuffer))) (exit-minibuffer)))))
candidates-alist))))
-1 'local)) -1 'local))
(completing-read (funcall mu4e-completing-read-function
prompt prompt
;; Use function with metadata to disable sorting. ;; Use function with metadata to disable sorting.
(lambda (input predicate action) (lambda (input predicate action)
(if (eq action 'metadata) (if (eq action 'metadata)
metadata metadata
(complete-with-action action candidates-alist input predicate))) (complete-with-action action choices input predicate)))
;; Require confirmation, if the input does not match a suggestion ;; Require confirmation, if the input does not match a suggestion
nil t nil nil nil)))) nil t nil nil nil))))
(or (cdr quick-result) (or quick-result
(cdr (assoc result candidates-alist))))) (cdr (assoc result choices)))))
(defun mu4e--read-choice-builtin (prompt choices) (defun mu4e--read-choice-builtin (prompt choices)
"Read and return one of CHOICES, prompting for PROMPT. "Read and return one of CHOICES, prompting for PROMPT.
@ -273,9 +292,14 @@ Function returns the value (cdr) of the matching cell."
(substring (car option) 1)) (substring (car option) 1))
(cons (cons
(string-to-char (car option)) ;; <key> (string-to-char (car option)) ;; <key>
(cdr option)))) ;; <value> (cdr option)))) ;; <value>
options))) options))
(or (mu4e--read-choice-builtin prompt choices) (response (funcall
(if mu4e-read-option-use-builtin
#'mu4e--read-choice-builtin
#'mu4e--read-choice-completing-read)
prompt choices)))
(or response
(mu4e-warn "invalid input")))) (mu4e-warn "invalid input"))))
(defun mu4e-filter-single-key (lst) (defun mu4e-filter-single-key (lst)