From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: martin rudalics Newsgroups: gmane.emacs.bugs Subject: bug#50766: Regexp paren pairs in query-replace-regexp prompt should be highlighted Date: Thu, 7 Oct 2021 11:07:48 +0200 Message-ID: <7f6c056c-805a-34a8-e432-72320670b472@gmx.at> References: <1LWmgMt-iOZcz0k2N5IVTqgDu922CLEd8GATVBsqdQfVeBzIGEaVuORC9k0SXORQDkpqc8BO3zxOPFbQeMMhNHQmOvcvIOpOpoWL8CAVUq8=@protonmail.com> <87bl4jxacl.fsf@gnus.org> <877df5tqyj.fsf@gnus.org> <87h7e5gtk0.fsf@gnus.org> <87ilyhw6si.fsf@gnus.org> <87k0ivvlyz.fsf@gnus.org> <2a200c3a-1901-fda5-2423-b04eab035347@gmx.at> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------66986AC7E536242FA2F5BE81" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="22708"; mail-complaints-to="usenet@ciao.gmane.io" Cc: ndame , 50766@debbugs.gnu.org To: Lars Ingebrigtsen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu Oct 07 11:09:20 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mYPOx-0005lF-6T for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 07 Oct 2021 11:09:19 +0200 Original-Received: from localhost ([::1]:48588 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mYPOw-0008Ed-0E for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 07 Oct 2021 05:09:18 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:58446) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mYPOg-0008EN-Uu for bug-gnu-emacs@gnu.org; Thu, 07 Oct 2021 05:09:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:34493) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mYPOg-0008Mb-Nd for bug-gnu-emacs@gnu.org; Thu, 07 Oct 2021 05:09:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mYPOg-0007fC-J0 for bug-gnu-emacs@gnu.org; Thu, 07 Oct 2021 05:09:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: martin rudalics Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 07 Oct 2021 09:09:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 50766 X-GNU-PR-Package: emacs Original-Received: via spool by 50766-submit@debbugs.gnu.org id=B50766.163359768329363 (code B ref 50766); Thu, 07 Oct 2021 09:09:02 +0000 Original-Received: (at 50766) by debbugs.gnu.org; 7 Oct 2021 09:08:03 +0000 Original-Received: from localhost ([127.0.0.1]:46035 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mYPNi-0007dP-PD for submit@debbugs.gnu.org; Thu, 07 Oct 2021 05:08:03 -0400 Original-Received: from mout.gmx.net ([212.227.17.21]:49693) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mYPNg-0007cx-AB for 50766@debbugs.gnu.org; Thu, 07 Oct 2021 05:08:00 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1633597671; bh=idPp/Uvu8j41ZLhjNVc1aJ+vVElzHqYTSZZP1tg4X1k=; h=X-UI-Sender-Class:Subject:From:To:Cc:References:Date:In-Reply-To; b=aEctvq5VutvCC/PC4AkXw4zD42DOAY22WV3OVvJUfeCqkISjpdSH9vOe0CjpdYaSA A0QLvOwiA/blGumr3kyd/aFvafNKW8pmszrmrnSctBQhXKbftuECd3BwvtP8kkDnR9 MAxibIxocHVnjpwSqw2I3XmaCl1hdWy6SbubMqgE= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Original-Received: from [192.168.1.101] ([213.142.97.180]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MVvLB-1mOp6Y0rAb-00RnKh; Thu, 07 Oct 2021 11:07:51 +0200 In-Reply-To: <2a200c3a-1901-fda5-2423-b04eab035347@gmx.at> Content-Language: en-US X-Provags-ID: V03:K1:K5/9uat0XJBfKYIAF+57aXdYEbbjwuTZpSlTCaXehKiZGVYLCwE jiIXvvYRfSt7mm87zNi2vHBMEUi8Kxw0HWjdjES4eQ9VF7Rxa+DDQ8LUUXdFySgqbgrp/sT oAQSZsQefTNrWwV8jLvlMLyF4cE2lEjniAmEEizJjv9IZy5+v95VV797eT8T7g8QJsHWiHb fQLCRGaKppx0YsFfQt30A== X-UI-Out-Filterresults: notjunk:1;V03:K0:XWDGn1ihcwc=:QIHu7pQvFxOjL1sZBn5G5a fA2mukQWzEbFHvqmX64EvwtI+X0d4DWy0FyWCWLJimY7fgPC3KbOcxhgYCMZhtGsYeQ/YZNRA kHIb8rTxGs+Ui+Wrx1tuNeT4St5NyEjp5R0fR/7DUJGZ17d6HvuXu4m8SIbzJOgSrIZ9glksh EpCIR0+2YWpfmE+iquFl5CcwhsC89DVTYue0d+ADWRr5ydMtZ1aS5xfjbZxmkPwcgc2BxKsP/ ZxT1FWSCNP8sqXepdSSsemp3uTcF+2IOCq8DAmLlvlupgatDFrd3Tob2+5qQQ+EdIQsrWjndZ PBJIrj3yrznwZadrwgYpvhpTtbkZ41Tt9K7ElmBQ69rcMoIHPALm8jTXM7NJAMTvFk7F26Vmd Ro3uQ0BKmrZUllr1k5PEOFglkLIfTznHRTQG6gUEPTOx27vTzVU9fxL258jZOdtLMcKHBTR9p 2N9P1ZHQizlkB135r4nRnnzFCW6j8Y2xgkXaYFP2iHqdBlEktgGHGqEXhFI8PI3wgH3TpNhvb 1VUShjILXmzocsnrgfZIsi/QlkGoxLneQsN1hEZ2yD+YubCcsncUKQ7SBZnxN9C++dBe3MQLc 4BvNHNQ1fpJfLJYnngGYTGbsVmUyoNu57qnGXxnuXXPZ9ygLOO03hb7nzq0HXHdNRS58NS7DZ QxyBEDBJm1zgN/vxc85tK8siBjzN92jPQwCp0QmM2pQTWBymMJRzlzA0bwYkIVXSke+g96Elx fSSNNUehE2e8hqLeEnZz1rpRArj+E7ToPb708q58QiAt3xAy/NGyzQlUeS9VKlmNdHPNUmtH X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:216621 Archived-At: This is a multi-part message in MIME format. --------------66986AC7E536242FA2F5BE81 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit > Which means I have to prime these before-change to avoid parsing the > buffer twice. Darn it! > So a fix for both has to hook into post-self-insert and after-change. I attach a preliminary patch that should work for both. Please give it some testing. martin --------------66986AC7E536242FA2F5BE81 Content-Type: text/x-patch; name="minibuffer.el.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="minibuffer.el.diff" diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 1e1a6f852e..fed08c9018 100644 =2D-- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -4242,6 +4242,170 @@ format-prompt default))) ": ")) +(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 ni= l)) + (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-t= able '(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-t= able '(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 rege= xp\\)" + "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 "29.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-ch= ange nil t) + (add-hook 'after-change-functions #'minibuffer--regexp-after-chan= ge nil t) + (add-hook 'post-self-insert-hook #'minibuffer--regexp-post-self-i= nsert 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-chang= e t) + (remove-hook 'after-change-functions #'minibuffer--regexp-after-change = t) + (remove-hook 'post-self-insert-hook #'minibuffer--regexp-post-self-inse= rt 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 --------------66986AC7E536242FA2F5BE81--