New minor mode 'minibuffer-regexp-mode'
This mode is for editing regexps in minibuffer, it highlights parens via `show-paren-mode' and `blink-matching-paren' in a user-friendly way, avoids reporting false paren mismatches, and makes sexp navigation more intuitive. * lisp/minibuffer.el (minibuffer-regexp-mode) (minibuffer--regexp-primed, minibuffer--regexp-prompt-regexp): New variables. (minibuffer--regexp-propertize, minibuffer--regexp-primed) (minibuffer--regexp-before-change) (minibuffer--regexp-after-change) (minibuffer--regexp-post-self-insert, minibuffer--regexp-setup) (minibuffer--regexp-exit, minibuffer-regexp-mode): New functions. (minibuffer-regexp-prompts): New option. * doc/lispref/minibuf.texi (Minibuffer Misc): Document the new mode and its option. * etc/NEWS: Announce the new mode. Bug#50766
This commit is contained in:
parent
28cb3a4413
commit
2992b99aab
3 changed files with 189 additions and 0 deletions
|
@ -2877,3 +2877,21 @@ This is the major mode used in inactive minibuffers. It uses
|
|||
keymap @code{minibuffer-inactive-mode-map}. This can be useful
|
||||
if the minibuffer is in a separate frame. @xref{Minibuffers and Frames}.
|
||||
@end deffn
|
||||
|
||||
@deffn Command minibuffer-regexp-mode
|
||||
This is a minor mode for editing regular expressions in the minibuffer.
|
||||
It highlight parens via @code{show-paren-mode} and
|
||||
@code{blink-matching-paren} in a user-friendly way, avoids reporting
|
||||
alleged paren mismatches and makes sexp navigation more intuitive.
|
||||
|
||||
The list of prompts activating this mode in specific minibuffer
|
||||
interactions is customizable via @code{minibuffer-regexp-prompts}, see
|
||||
below.
|
||||
@end deffn
|
||||
|
||||
@defopt minibuffer-regexp-prompts
|
||||
List of minibuffer prompts that trigger @code{minibuffer-regexp-mode}.
|
||||
@code{minibuffer-regexp-mode} is activated in a specific minibuffer
|
||||
interaction if and only if a prompt in this list appears at the
|
||||
beginning of the minibuffer.
|
||||
@end defopt
|
||||
|
|
7
etc/NEWS
7
etc/NEWS
|
@ -775,6 +775,13 @@ A major mode based on the tree-sitter library for editing HEEx files.
|
|||
A major mode based on the tree-sitter library for editing Elixir
|
||||
files.
|
||||
|
||||
+++
|
||||
** New global minor mode 'minibuffer-regexp-mode'.
|
||||
This is a minor mode for editing regular expressions in the minibuffer.
|
||||
It highlight parens via ‘show-paren-mode’ and ‘blink-matching-paren’ in
|
||||
a user-friendly way, avoids reporting alleged paren mismatches and makes
|
||||
sexp navigation more intuitive.
|
||||
|
||||
---
|
||||
** The highly accessible Modus themes collection has eight items.
|
||||
The 'modus-operandi' and 'modus-vivendi' are the main themes that have
|
||||
|
|
|
@ -4663,6 +4663,170 @@ The latter is implemented in `touch-screen.el'."
|
|||
(add-hook 'minibuffer-setup-hook #'minibuffer-setup-on-screen-keyboard)
|
||||
(add-hook 'minibuffer-exit-hook #'minibuffer-exit-on-screen-keyboard)
|
||||
|
||||
(defvar minibuffer-regexp-mode)
|
||||
|
||||
(defun minibuffer--regexp-propertize ()
|
||||
"In current minibuffer propertize parens and slashes in regexps.
|
||||
Put punctuation `syntax-table' property on selected paren and
|
||||
backslash characters in current buffer to make `show-paren-mode'
|
||||
and `blink-matching-paren' more user-friendly."
|
||||
(let (in-char-alt-p)
|
||||
(save-excursion
|
||||
(with-silent-modifications
|
||||
(remove-text-properties (point-min) (point-max) '(syntax-table nil))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward
|
||||
"\\(\\\\\\\\\\)\\|\\(?:\\(?:\\\\\\)\\(?:\\([(){}]\\)\\|\\(\\[\\)\\|\\(\\]\\)\\)\\)\
|
||||
\\|\\(\\[:[a-zA-Z]+:\\]\\)\\|\\(\\[\\)\\|\\(\\]\\)\\|\\([(){}]\\)"
|
||||
(point-max) 'noerror)
|
||||
(cond
|
||||
((match-beginning 1)) ; \\, skip
|
||||
((match-beginning 2) ; \( \) \{ \}
|
||||
(if in-char-alt-p
|
||||
;; Within character alternative, set symbol syntax for
|
||||
;; paren only.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3))
|
||||
;; Not within character alternative, set symbol syntax for
|
||||
;; backslash only.
|
||||
(put-text-property (- (point) 2) (1- (point)) 'syntax-table '(3))))
|
||||
((match-beginning 3) ; \[
|
||||
(if in-char-alt-p
|
||||
(progn
|
||||
;; Set symbol syntax for backslash.
|
||||
(put-text-property (- (point) 2) (1- (point)) 'syntax-table '(3))
|
||||
;; Re-read bracket we might be before a character class.
|
||||
(backward-char))
|
||||
;; Set symbol syntax for bracket.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3))))
|
||||
((match-beginning 4) ; \]
|
||||
(if in-char-alt-p
|
||||
(progn
|
||||
;; Within character alternative, set symbol syntax for
|
||||
;; backslash, exit alternative.
|
||||
(put-text-property (- (point) 2) (1- (point)) 'syntax-table '(3))
|
||||
(setq in-char-alt-p nil))
|
||||
;; Not within character alternative, set symbol syntax for
|
||||
;; bracket.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3))))
|
||||
((match-beginning 5)) ; POSIX character class, skip
|
||||
((match-beginning 6) ; [
|
||||
(if in-char-alt-p
|
||||
;; Within character alternative, set symbol syntax.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3))
|
||||
;; Start new character alternative.
|
||||
(setq in-char-alt-p t)
|
||||
;; Looking for immediately following non-closing ].
|
||||
(when (looking-at "\\^?\\]")
|
||||
;; Non-special right bracket, set symbol syntax.
|
||||
(goto-char (match-end 0))
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3)))))
|
||||
((match-beginning 7) ; ]
|
||||
(if in-char-alt-p
|
||||
(setq in-char-alt-p nil)
|
||||
;; The only warning we can emit before RET.
|
||||
(message "Not in character alternative")))
|
||||
((match-beginning 8) ; (){}
|
||||
;; Plain parenthesis or brace, set symbol syntax.
|
||||
(put-text-property (1- (point)) (point) 'syntax-table '(3)))))))))
|
||||
|
||||
;; The following variable is set by 'minibuffer--regexp-before-change'.
|
||||
;; If non-nil, either 'minibuffer--regexp-post-self-insert' or
|
||||
;; 'minibuffer--regexp-after-change', whichever comes next, will
|
||||
;; propertize the minibuffer via 'minibuffer--regexp-propertize' and
|
||||
;; reset this variable to nil, avoiding to propertize the buffer twice.
|
||||
(defvar-local minibuffer--regexp-primed nil
|
||||
"Non-nil when minibuffer contents change.")
|
||||
|
||||
(defun minibuffer--regexp-before-change (_a _b)
|
||||
"`minibuffer-regexp-mode' function on `before-change-functions'."
|
||||
(setq minibuffer--regexp-primed t))
|
||||
|
||||
(defun minibuffer--regexp-after-change (_a _b _c)
|
||||
"`minibuffer-regexp-mode' function on `after-change-functions'."
|
||||
(when minibuffer--regexp-primed
|
||||
(setq minibuffer--regexp-primed nil)
|
||||
(minibuffer--regexp-propertize)))
|
||||
|
||||
(defun minibuffer--regexp-post-self-insert ()
|
||||
"`minibuffer-regexp-mode' function on `post-self-insert-hook'."
|
||||
(when minibuffer--regexp-primed
|
||||
(setq minibuffer--regexp-primed nil)
|
||||
(minibuffer--regexp-propertize)))
|
||||
|
||||
(defvar minibuffer--regexp-prompt-regexp
|
||||
"\\(?:Posix search\\|RE search\\|Search for regexp\\|Query replace regexp\\)"
|
||||
"Regular expression compiled from `minibuffer-regexp-prompts'.")
|
||||
|
||||
(defcustom minibuffer-regexp-prompts
|
||||
'("Posix search" "RE search" "Search for regexp" "Query replace regexp")
|
||||
"List of minibuffer prompts that trigger `minibuffer-regexp-mode'.
|
||||
`minibuffer-regexp-mode' is activated in a specific minibuffer
|
||||
interaction if and only if a prompt in this list appears at the
|
||||
beginning of the minibuffer."
|
||||
:type '(repeat (string :tag "Prompt"))
|
||||
:set (lambda (sym val)
|
||||
(set-default sym val)
|
||||
(when val
|
||||
(setq minibuffer--regexp-prompt-regexp
|
||||
(concat "\\(?:" (mapconcat 'regexp-quote val "\\|") "\\)"))))
|
||||
:version "30.1")
|
||||
|
||||
(defun minibuffer--regexp-setup ()
|
||||
"Function to activate`minibuffer-regexp-mode' in current buffer.
|
||||
Run by `minibuffer-setup-hook'."
|
||||
(if (and minibuffer-regexp-mode
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(looking-at minibuffer--regexp-prompt-regexp)))
|
||||
(progn
|
||||
(setq-local parse-sexp-lookup-properties t)
|
||||
(add-hook 'before-change-functions #'minibuffer--regexp-before-change nil t)
|
||||
(add-hook 'after-change-functions #'minibuffer--regexp-after-change nil t)
|
||||
(add-hook 'post-self-insert-hook #'minibuffer--regexp-post-self-insert nil t))
|
||||
;; Make sure.
|
||||
(minibuffer--regexp-exit)))
|
||||
|
||||
(defun minibuffer--regexp-exit ()
|
||||
"Function to deactivate `minibuffer-regexp-mode' in current buffer.
|
||||
Run by `minibuffer-exit-hook'."
|
||||
(with-silent-modifications
|
||||
(remove-text-properties (point-min) (point-max) '(syntax-table nil)))
|
||||
(setq-local parse-sexp-lookup-properties nil)
|
||||
(remove-hook 'before-change-functions #'minibuffer--regexp-before-change t)
|
||||
(remove-hook 'after-change-functions #'minibuffer--regexp-after-change t)
|
||||
(remove-hook 'post-self-insert-hook #'minibuffer--regexp-post-self-insert t))
|
||||
|
||||
(define-minor-mode minibuffer-regexp-mode
|
||||
"Minor mode for editing regular expressions in the minibuffer.
|
||||
Highlight parens via `show-paren-mode' and `blink-matching-paren'
|
||||
in a user-friendly way, avoid reporting alleged paren mismatches
|
||||
and make sexp navigation more intuitive.
|
||||
|
||||
The list of prompts activating this mode in specific minibuffer
|
||||
interactions is customizable via `minibuffer-regexp-prompts'."
|
||||
:global t
|
||||
:initialize 'custom-initialize-delay
|
||||
:init-value t
|
||||
(if minibuffer-regexp-mode
|
||||
(progn
|
||||
(add-hook 'minibuffer-setup-hook #'minibuffer--regexp-setup)
|
||||
(add-hook 'minibuffer-exit-hook #'minibuffer--regexp-exit))
|
||||
;; Clean up - why is Vminibuffer_list not available in Lisp?
|
||||
(dolist (buffer (buffer-list))
|
||||
(when (and (minibufferp)
|
||||
parse-sexp-lookup-properties
|
||||
(with-current-buffer buffer
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(looking-at minibuffer--regexp-prompt-regexp))))
|
||||
(with-current-buffer buffer
|
||||
(with-silent-modifications
|
||||
(remove-text-properties
|
||||
(point-min) (point-max) '(syntax-table nil)))
|
||||
(setq-local parse-sexp-lookup-properties t))))
|
||||
(remove-hook 'minibuffer-setup-hook #'minibuffer--regexp-setup)
|
||||
(remove-hook 'minibuffer-exit-hook #'minibuffer--regexp-exit)))
|
||||
|
||||
(provide 'minibuffer)
|
||||
|
||||
;;; minibuffer.el ends here
|
||||
|
|
Loading…
Add table
Reference in a new issue