From 03ea46b66128ee906cb829a0fa62f2da5ba68f94 Mon Sep 17 00:00:00 2001
From: Shynur <one.last.kiss@outlook.com>
Date: Sun, 30 Apr 2023 17:54:01 +0800
Subject: [PATCH] Display offscreen matched openparen

Propertize the matched openparen displayed in the echo area in order to make
it prominent; use light font for non-context characters (i.e., 'Matches').
* lisp/simple.el (blink-matching-open): Set face shadow for 'Matches'.
* lisp/simple.el (blink-paren-open-paren-line-string): Propertize the macthed
openparen's face by user option `show-paren-openparen-face-in-message'.
* lisp/paren.el (show-paren-openparen-face-in-message): Add a user option
which determines the face of the matched offscreen openparen shown in the
echo area.
---
 lisp/paren.el  |  8 ++++++
 lisp/simple.el | 68 +++++++++++++++++++++++++++++++++++---------------
 2 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/lisp/paren.el b/lisp/paren.el
index 4c91fd29490..f6a0c1c8b6b 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -81,6 +81,14 @@ whitespace there."
   :type 'boolean
   :version "25.1")
 
+(defcustom show-paren-openparen-face-in-message nil
+  "Face for showing in the echo area matched open paren that is off-screen.
+By default, the line containing the matched offscreen openparen
+is shown in the echo area, where the openparen will be propertized
+with a face based on the value of this option."
+  :type '(choice face sexp (const nil))
+  :version "30.1")
+
 (defcustom show-paren-highlight-openparen t
   "Non-nil turns on openparen highlighting when matching forward.
 When nil, and point stands just before an open paren, the paren
diff --git a/lisp/simple.el b/lisp/simple.el
index b621e1603bd..4d8f24e3252 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9312,47 +9312,75 @@ The function should return non-nil if the two tokens do not match.")
                  (delete-overlay blink-matching--overlay)))))
        ((not show-paren-context-when-offscreen)
         (minibuffer-message
-         "Matches %s"
-         (substring-no-properties
-          (blink-paren-open-paren-line-string blinkpos))))))))
+         #("Matches %s"
+           ;; Make the following text (i.e., %s) prominent.
+           0 7 (face shadow))
+         (blink-paren-open-paren-line-string blinkpos)))))))
 
 (defun blink-paren-open-paren-line-string (pos)
-  "Return the line string that contains the openparen at POS."
+  "Return the line string that contains the openparen at POS.
+Remove the line string's properties but give the openparen a
+face based on the option `show-paren-openparen-face-in-message'."
   (save-excursion
     (goto-char pos)
     ;; Capture the regions in terms of (beg . end) conses whose
     ;; buffer-substrings we want to show as a context string.  Ensure
     ;; they are font-locked (bug#59527).
-    (let (regions)
-      ;; Show what precedes the open in its line, if anything.
+    (let (regions
+          openparen-idx)
       (cond
+       ;; Show what precedes the open in its line, if anything.
        ((save-excursion (skip-chars-backward " \t") (not (bolp)))
-        (setq regions (list (cons (line-beginning-position)
-                                  (1+ pos)))))
+        (let ((bol (line-beginning-position)))
+          (setq regions (list (cons bol (1+ pos)))
+                openparen-idx (- pos bol))))
        ;; Show what follows the open in its line, if anything.
        ((save-excursion
           (forward-char 1)
           (skip-chars-forward " \t")
           (not (eolp)))
-        (setq regions (list (cons pos (line-end-position)))))
+        (setq regions (list (cons pos (line-end-position)))
+              openparen-idx 0))
        ;; Otherwise show the previous nonblank line,
        ;; if there is one.
        ((save-excursion (skip-chars-backward "\n \t") (not (bobp)))
-        (setq regions (list (cons (progn
-                                    (skip-chars-backward "\n \t")
-                                    (line-beginning-position))
-                                  (progn (end-of-line)
-                                         (skip-chars-backward " \t")
-                                         (point)))
+        (setq regions (list (cons
+                             (let (bol)
+                               (skip-chars-backward "\n \t")
+                               (setq bol (line-beginning-position)
+                                     openparen-idx (- bol))
+                               bol)
+                             (let (eol)
+                               (end-of-line)
+                               (skip-chars-backward " \t")
+                               (setq eol (point)
+                                     openparen-idx (+ openparen-idx
+                                                      eol
+                                                      ;; (length "...")
+                                                      3))
+                               eol))
                             (cons pos (1+ pos)))))
        ;; There is nothing to show except the char itself.
-       (t (setq regions (list (cons pos (1+ pos))))))
+       (t (setq regions (list (cons pos (1+ pos)))
+                openparen-idx 0)))
       ;; Ensure we've font-locked the context region.
       (font-lock-ensure (caar regions) (cdar (last regions)))
-      (mapconcat (lambda (region)
-                   (buffer-substring (car region) (cdr region)))
-                 regions
-                 "..."))))
+      (let ((line-string
+             (mapconcat
+              (lambda (region)
+                (buffer-substring (car region) (cdr region)))
+              regions
+              "..."))
+            (openparen-next-char-idx (1+ openparen-idx)))
+        (setq line-string (substring-no-properties line-string))
+        (concat
+         (substring line-string
+                    0 openparen-idx)
+         (propertize (substring line-string
+                                openparen-idx openparen-next-char-idx)
+                     'face show-paren-openparen-face-in-message)
+         (substring line-string
+                    openparen-next-char-idx))))))
 
 (defvar blink-paren-function 'blink-matching-open
   "Function called, if non-nil, whenever a close parenthesis is inserted.
-- 
2.34.1

