Subject: [PATCH] Add option for not highlight parens inside comments or strings.
From: Elijah Gabe Pérez <[email-masked]>
To: [email-masked]
Date: Mon, 12 May 2025 12:51:57 -0600
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Sometimes show-paren will highlight the parens that are inside a
comment/string which looks annoying and somewhat confusing.

e.g.
show-paren will highlight this paren:

  ;; :^)| <- cursor
       ^ paren highlighted as mismatch

or:
  v
  (
 ;; )| <- cursor
    ^ both parens highlighted

I've made an option for disable/control this behavior, by default its
disabled but I wonder if this should be activated instead.

From cf70180ae5ffe895c44ca84ac7670ab583334495 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?El=C3=ADas=20Gabriel=20P=C3=A9rez?= <[email-masked]>
Date: Mon, 12 May 2025 12:04:46 -0600
Subject: [PATCH] Add option for not highlight parens inside comments or
 strings.

* lisp/paren.el (show-paren-not-in-comments-or-strings):
New user option.
(show-paren-function): Enclose code in catch function.
* etc/NEWS: Announce changes.
* doc/emacs/programs.texi: Document new option.
---
 doc/emacs/programs.texi |   7 ++
 etc/NEWS                |   7 ++
 lisp/paren.el           | 183 ++++++++++++++++++++++------------------
 3 files changed, 116 insertions(+), 81 deletions(-)

diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index f3cdc1b8e6c..5da6c263f0d 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -1056,6 +1056,13 @@ Matching
 that contains the opening delimiter, except if the opening delimiter
 is on its own line, in which case the context includes the previous
 nonblank line.
+
+@item
+@vindex show-paren-not-in-comments-or-strings
+@code{show-paren-not-in-comments-or-strings}, If set to @code{all}, do
+not highlight all the parens that are inside comments or strings.  If
+set to @code{on-mismatch}, only don't highlight if paren mismatched.  If set
+to @code{nil} (by default), highlight the paren wherever it is.
 @end itemize
 
 @cindex Electric Pair mode
diff --git a/etc/NEWS b/etc/NEWS
index d1b0189da0c..f9314af8036 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -471,6 +471,13 @@ setting is an alternative to 'help-at-pt-display-when-idle'.
 Customize this to nil to disable starting new asynchronous native
 compilations while AC power is not connected.
 
+** New user option 'show-paren-not-in-comments-or-strings'
+This option tells show-paren don't highlight the parens that are inside
+a comment or string.  If set to 'all', do not highlight all the parens
+that are inside comments or strings.  If set to 'on-mismatch', only
+don't highlight if paren mismatched.  If set to nil (by default),
+highlight the paren wherever it is.
+
 
 * Editing Changes in Emacs 31.1
 
diff --git a/lisp/paren.el b/lisp/paren.el
index 9d7f131e043..ee5501a9726 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -110,6 +110,18 @@ show-paren-context-when-offscreen
                  (const :tag "In child-frame" child-frame))
   :version "29.1")
 
+(defcustom show-paren-not-in-comments-or-strings nil
+  "Do not highlight the parens that are inside a comment or string.
+If set to `all', do not highlight all the parens that are inside comments
+or strings.
+If set to `on-mismatch', only don't highlight if paren mismatched.
+If set to nil (by default), highlight the paren wherever it is."
+  :type '(choice
+          (const :tag "Enable" all)
+          (const :tag "Only on mismatch" on-mismatch)
+          (const :tag "" nil))
+  :version "31.1")
+
 (defvar show-paren--idle-timer nil)
 (defvar show-paren--overlay
   (let ((ol (make-overlay (point) (point) nil t))) (delete-overlay ol) ol)
@@ -450,88 +462,97 @@ show-paren-function
           (setq show-paren--last-pos (point)))
 
       ;; Found something to highlight.
-      (let* ((here-beg (nth 0 data))
-             (here-end (nth 1 data))
-             (there-beg (nth 2 data))
-             (there-end (nth 3 data))
-             (mismatch (nth 4 data))
-             (highlight-expression
-              (or (eq show-paren-style 'expression)
-                  (and there-beg
-                       (eq show-paren-style 'mixed)
-                       (let ((closest (if (< there-beg here-beg)
-                                          (1- there-end) (1+ there-beg))))
-                         (not (pos-visible-in-window-p closest))))))
-             (face
-              (cond
-               (mismatch
-                (if show-paren-ring-bell-on-mismatch
-                    (beep))
-                'show-paren-mismatch)
-               (highlight-expression 'show-paren-match-expression)
-               (t 'show-paren-match))))
-        ;;
-        ;; If matching backwards, highlight the closeparen
-        ;; before point as well as its matching open.
-        ;; If matching forward, and the openparen is unbalanced,
-        ;; highlight the paren at point to indicate misbalance.
-        ;; Otherwise, turn off any such highlighting.
-        (if (or (not here-beg)
-                (and (not show-paren-highlight-openparen)
-                     (> here-end (point))
-                     (<= here-beg (point))
-                     (integerp there-beg)))
-            (delete-overlay show-paren--overlay-1)
-          (move-overlay show-paren--overlay-1
-                        here-beg here-end (current-buffer))
-          ;; Always set the overlay face, since it varies.
-          (overlay-put show-paren--overlay-1 'priority show-paren-priority)
-          (overlay-put show-paren--overlay-1 'face face))
-        ;;
-        ;; Turn on highlighting for the matching paren, if found.
-        ;; If it's an unmatched paren, turn off any such highlighting.
-        (if (not there-beg)
-            (delete-overlay show-paren--overlay)
-          (if highlight-expression
-              (move-overlay show-paren--overlay
-                            (if (< there-beg here-beg) here-end here-beg)
-                            (if (< there-beg here-beg) there-beg there-end)
-                            (current-buffer))
-            (move-overlay show-paren--overlay
-                          there-beg there-end (current-buffer)))
-          ;; If `show-paren-context-when-offscreen' is non-nil and
-          ;; point is at a closing paren, show the context around the
-          ;; opening paren.
-          (let ((openparen (min here-beg there-beg)))
-            (when (and show-paren-context-when-offscreen
-                       (not (eql show-paren--last-pos (point)))
-                       (< there-beg here-beg)
-                       ;; Either OPENPAREN position is fully visible...
-                       (not (or (pos-visible-in-window-p openparen)
-                                (let ((dfh4 (* 0.25 (default-font-height)))
-                                      (part
-                                       (pos-visible-in-window-p openparen
-                                                                nil t)))
-                                  ;; ...or partially visible, and the
-                                  ;; invisible part is less than 1/4th
-                                  ;; of the default font height
-                                  (and (>= (length part) 4)
-                                       (< (nth 2 part) dfh4)
-                                       (< (nth 3 part) dfh4))))))
-              (let ((context (blink-paren-open-paren-line-string
-                              openparen))
-                    (message-log-max nil))
+      (catch 'sp-exit
+        (let* ((here-beg (nth 0 data))
+               (here-end (nth 1 data))
+               (there-beg (nth 2 data))
+               (there-end (nth 3 data))
+               (mismatch (nth 4 data))
+               (highlight-expression
+                (or (eq show-paren-style 'expression)
+                    (and there-beg
+                         (eq show-paren-style 'mixed)
+                         (let ((closest (if (< there-beg here-beg)
+                                            (1- there-end) (1+ there-beg))))
+                           (not (pos-visible-in-window-p closest))))))
+               (face
                 (cond
-                 ((eq show-paren-context-when-offscreen 'child-frame)
-                  (show-paren--show-context-in-child-frame context))
-                 ((eq show-paren-context-when-offscreen 'overlay)
-                  (show-paren--show-context-in-overlay context))
-                 (show-paren-context-when-offscreen
-                  (minibuffer-message "Matches %s" context))))))
-          (setq show-paren--last-pos (point))
-          ;; Always set the overlay face, since it varies.
-          (overlay-put show-paren--overlay 'priority show-paren-priority)
-          (overlay-put show-paren--overlay 'face face))))))
+                 (mismatch
+                  (if (and (eq show-paren-not-in-comments-or-strings 'on-mismatch)
+                           (save-excursion
+                             (syntax-ppss-context (syntax-ppss here-beg))))
+                      (throw 'sp-exit nil))
+                  (if show-paren-ring-bell-on-mismatch
+                      (beep))
+                  'show-paren-mismatch)
+                 (highlight-expression 'show-paren-match-expression)
+                 (t 'show-paren-match))))
+          (if (and (eq show-paren-not-in-comments-or-strings 'all)
+                   (save-excursion
+                     (syntax-ppss-context (syntax-ppss here-beg))))
+              (throw 'sp-exit nil))
+          ;;
+          ;; If matching backwards, highlight the closeparen
+          ;; before point as well as its matching open.
+          ;; If matching forward, and the openparen is unbalanced,
+          ;; highlight the paren at point to indicate misbalance.
+          ;; Otherwise, turn off any such highlighting.
+          (if (or (not here-beg)
+                  (and (not show-paren-highlight-openparen)
+                       (> here-end (point))
+                       (<= here-beg (point))
+                       (integerp there-beg)))
+              (delete-overlay show-paren--overlay-1)
+            (move-overlay show-paren--overlay-1
+                          here-beg here-end (current-buffer))
+            ;; Always set the overlay face, since it varies.
+            (overlay-put show-paren--overlay-1 'priority show-paren-priority)
+            (overlay-put show-paren--overlay-1 'face face))
+          ;;
+          ;; Turn on highlighting for the matching paren, if found.
+          ;; If it's an unmatched paren, turn off any such highlighting.
+          (if (not there-beg)
+              (delete-overlay show-paren--overlay)
+            (if highlight-expression
+                (move-overlay show-paren--overlay
+                              (if (< there-beg here-beg) here-end here-beg)
+                              (if (< there-beg here-beg) there-beg there-end)
+                              (current-buffer))
+              (move-overlay show-paren--overlay
+                            there-beg there-end (current-buffer)))
+            ;; If `show-paren-context-when-offscreen' is non-nil and
+            ;; point is at a closing paren, show the context around the
+            ;; opening paren.
+            (let ((openparen (min here-beg there-beg)))
+              (when (and show-paren-context-when-offscreen
+                         (not (eql show-paren--last-pos (point)))
+                         (< there-beg here-beg)
+                         ;; Either OPENPAREN position is fully visible...
+                         (not (or (pos-visible-in-window-p openparen)
+                                  (let ((dfh4 (* 0.25 (default-font-height)))
+                                        (part
+                                         (pos-visible-in-window-p openparen
+                                                                  nil t)))
+                                    ;; ...or partially visible, and the
+                                    ;; invisible part is less than 1/4th
+                                    ;; of the default font height
+                                    (and (>= (length part) 4)
+                                         (< (nth 2 part) dfh4)
+                                         (< (nth 3 part) dfh4))))))
+                (let ((context (blink-paren-open-paren-line-string
+                                openparen))
+                      (message-log-max nil))
+                  (cond
+                   ((eq show-paren-context-when-offscreen 'child-frame)
+                    (show-paren--show-context-in-child-frame context))
+                   ((eq show-paren-context-when-offscreen 'overlay)
+                    (show-paren--show-context-in-overlay context))
+                   (show-paren-context-when-offscreen
+                    (minibuffer-message "Matches %s" context))))))
+            (setq show-paren--last-pos (point))
+            ;; Always set the overlay face, since it varies.
+            (overlay-put show-paren--overlay 'priority show-paren-priority)
+            (overlay-put show-paren--overlay 'face face)))))))
 
 (provide 'paren)
 
-- 
2.49.0

-- 
                                          - E.G via GNU Emacs and Org.