From 610c94c6d0005beeebc1b7a4cadd83cb0da4c55e Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sat, 20 Jan 2024 20:03:20 +0100 Subject: [PATCH] Highlight input separators in 'c-r-m' minibuffers * lisp/emacs-lisp/crm.el (crm-separator): New face. (crm-highlight-separators): New function. (crm-change-separator, completing-read-multiple-mode): Use it. * doc/emacs/mini.texi (Completion Multi): Mention sep highlighting. * etc/NEWS: Announce it. --- doc/emacs/mini.texi | 8 +++++-- etc/NEWS | 6 +++++ lisp/emacs-lisp/crm.el | 51 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index b6744776fd2..ca5f6d0dc0b 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -848,8 +848,12 @@ treats a part of your minibuffer input as an input separator when it 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. diff --git a/etc/NEWS b/etc/NEWS index 013d76eb44b..ac743cd0bf1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -792,6 +792,12 @@ minibuffers, completes partial inputs that are already in the 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', diff --git a/lisp/emacs-lisp/crm.el b/lisp/emacs-lisp/crm.el index ebea8b060e1..32221047c20 100644 --- a/lisp/emacs-lisp/crm.el +++ b/lisp/emacs-lisp/crm.el @@ -191,11 +191,13 @@ for REP as well." (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))) @@ -291,6 +293,34 @@ that fails this command prompts you for the separator to use." (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'." " " #'crm-complete-and-exit @@ -299,10 +329,17 @@ that fails this command prompts you for the separator to use." (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 -- 2.39.5