From a8a4c3a091bc6ebab40db3b33f4d15bb1040dbcb Mon Sep 17 00:00:00 2001 From: Daniel Mendler Date: Mon, 3 Feb 2025 16:39:49 +0100 Subject: [PATCH] completing-read-multiple: CRM indication and prompt customization The `completing-read-multiple' prompt indicates multi completion. The customization option `crm-prompt' configures the formatting of the prompt. The variable can be set to "%p" in order to only display the original prompt, to "[%d] %p" to display the separator description and the prompt, or to "[CRM%s] %p" to display a shorter indicator of only the separator string and the prompt. * lisp/emacs-lisp/crm.el (crm-prompt): New user option. (crm-separator): Update value and docstring. (completing-read-multiple): Use `crm-prompt' to format the prompt. * etc/NEWS: Announce the change. (Bug#76028) --- etc/NEWS | 8 ++++++++ lisp/emacs-lisp/crm.el | 30 ++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 51f481c763c..6d934b2029c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -176,6 +176,14 @@ will still be on that candidate after "*Completions*" is updated with a new list of completions. The candidate is automatically deselected when the "*Completions*" buffer is hidden. +--- +*** New user option 'crm-prompt' for 'completing-read-multiple'. +This option configures the prompt format of 'completing-read-multiple'. +By default the prompt indicates to the user that the completion command +accepts a comma-separated list. The prompt format can include the +separator description and the separator string, which are both stored as +text properties of the 'crm-separator' regular expression. + ** Windows +++ diff --git a/lisp/emacs-lisp/crm.el b/lisp/emacs-lisp/crm.el index a371a8e14de..676252ae126 100644 --- a/lisp/emacs-lisp/crm.el +++ b/lisp/emacs-lisp/crm.el @@ -79,9 +79,25 @@ (define-obsolete-variable-alias 'crm-default-separator 'crm-separator "29.1") -(defvar crm-separator "[ \t]*,[ \t]*" +(defvar crm-separator + (propertize "[ \t]*,[ \t]*" 'separator "," 'description "comma-separated list") "Separator regexp used for separating strings in `completing-read-multiple'. -It should be a regexp that does not match the list of completion candidates.") +It should be a regexp that does not match the list of completion +candidates. The regexp string can carry the text properties `separator' +and `description', which if present `completing-read-multiple' will show +as part of the prompt. See the user option `crm-prompt'.") + +(defcustom crm-prompt "[%d] %p" + "Prompt format for `completing-read-multiple'. +The prompt is formatted by `format-spec' with the keys %d, %s and %p +standing for the separator description, the separator itself and the +original prompt respectively." + :type '(choice (const :tag "Original prompt" "%p") + (const :tag "Description and prompt" "[%d] %p") + (const :tag "Short CRM indication" "[CRM%s] %p") + (string :tag "Custom string")) + :group 'minibuffer + :version "31.1") (defvar-keymap crm-local-completion-map :doc "Local keymap for minibuffer multiple input with completion. @@ -266,8 +282,14 @@ with empty strings removed." (unless (eq require-match t) require-match)) (setq-local crm-completion-table table)) (setq input (read-from-minibuffer - prompt initial-input map - nil hist def inherit-input-method))) + (format-spec + crm-prompt + (let* ((sep (or (get-text-property 0 'separator crm-separator) + (string-replace "[ \t]*" "" crm-separator))) + (desc (or (get-text-property 0 'description crm-separator) + (concat "list separated by " sep)))) + `((?s . ,sep) (?d . ,desc) (?p . ,prompt)))) + initial-input map nil hist def inherit-input-method))) ;; If the user enters empty input, `read-from-minibuffer' ;; returns the empty string, not DEF. (when (and def (string-equal input ""))