matches the current @dfn{separator pattern}---a regular expression
that may change from command to command. The default separator
pattern, which most commands use, matches a comma along with any
-surrounding spaces or tabs. When reading multiple inputs, the
-@file{*Completions*} buffer displays the @samp{Multi} indicator in the
+surrounding spaces or tabs.
+
+@noindent
+When reading multiple inputs, Emacs highlights input separators in the
+minibuffer with the @code{crm-separator} face, and the
+@file{*Completions*} buffer displays the indicator @samp{Multi} in the
mode line. You can hover over that indicator with the mouse to get
help about the current input separator pattern.
minibuffer, and inserts a new separator at the end of the minibuffer
for you to insert a another input.
++++
+*** Highlight 'completing-read-multiple' separators in the minibuffer.
+Emacs now highlights input separators when you provide multiple inputs
+in the minibuffer for 'completing-read-multiple'. This highlighting
+uses the new 'crm-separator' face.
+
+++
*** 'completion-category-overrides' supports more metadata.
The new supported completion properties are 'cycle-sort-function',
(when current-prefix-arg
(read-string-matching sep "Replace existing separators with: "))))
minibuffer-mode)
- (when rep
- (goto-char (minibuffer-prompt-end))
- (while (re-search-forward crm-current-separator nil t)
- (replace-match rep t t)))
+ (save-excursion
+ (when rep
+ (goto-char (minibuffer-prompt-end))
+ (while (re-search-forward crm-current-separator nil t)
+ (replace-match rep t t))))
(setq crm-current-separator sep crm-canonical-separator rep)
+ (crm-highlight-separators (minibuffer-prompt-end) (point-max))
(when (get-buffer-window "*Completions*" 0)
;; Update *Completions* to avoid stale `completion-base-affixes'.
(minibuffer-completion-help)))
(define-obsolete-variable-alias 'crm-local-must-match-map
'completing-read-multiple-mode-map "30.1")
+(defface crm-separator
+ '((t :inherit minibuffer-prompt))
+ "Face for highlighting input separators in multi-input minibuffers."
+ :version "30.1")
+
+(defun crm-highlight-separators (beg end &optional _)
+ "Highlight current minibuffer input separators between BEG and END."
+ (let* ((bob (minibuffer-prompt-end))
+ (beg (or (save-excursion
+ (goto-char beg)
+ (re-search-backward crm-current-separator bob t))
+ bob))
+ (end (or (save-excursion
+ (goto-char end)
+ (re-search-forward crm-current-separator nil t))
+ (point-max)))
+ (ovs (seq-filter (lambda (ov) (overlay-get ov 'crm-separator))
+ (overlays-in beg end))))
+ (mapc #'delete-overlay ovs)
+ (save-excursion
+ (goto-char beg)
+ (save-match-data
+ (while (re-search-forward crm-current-separator nil t)
+ (let ((ov (make-overlay (match-beginning 0) (match-end 0))))
+ (overlay-put ov 'face 'crm-separator)
+ (overlay-put ov 'crm-separator t)
+ (overlay-put ov 'evaporate t)))))))
+
(defvar-keymap completing-read-multiple-mode-map
:doc "Keymap for `completing-read-multiple-mode'."
"<remap> <minibuffer-complete-and-exit>" #'crm-complete-and-exit
(define-minor-mode completing-read-multiple-mode
"Minor mode for reading multiple strings in the minibuffer."
- :lighter nil
+ :interactive nil
(if completing-read-multiple-mode
- (add-hook 'completion-setup-hook #'crm-completion-setup 10 t)
- (remove-hook 'completion-setup-hook #'crm-completion-setup t)))
+ (progn
+ (add-hook 'completion-setup-hook #'crm-completion-setup 10 t)
+ (add-hook 'after-change-functions #'crm-highlight-separators nil t)
+ (crm-highlight-separators (minibuffer-prompt-end) (point-max)))
+ (remove-hook 'completion-setup-hook #'crm-completion-setup t)
+ (remove-hook 'after-change-functions #'crm-highlight-separators t)
+ (mapc #'delete-overlay
+ (seq-filter (lambda (ov) (overlay-get ov 'crm-separator))
+ (overlays-in (minibuffer-prompt-end) (point-max))))))
;;;###autoload
(defun completing-read-multiple