unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#51242: [PATCH] New option show-paren-context-when-offscreen
       [not found] <m1o87ols48.fsf.ref@yahoo.es>
@ 2021-10-16 18:52 ` Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-10-18  7:28   ` Lars Ingebrigtsen
  0 siblings, 1 reply; 2+ messages in thread
From: Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-10-16 18:52 UTC (permalink / raw)
  To: 51242

[-- Attachment #1: Type: text/plain, Size: 795 bytes --]


Now that show-paren-mode is enabled by default, I've implemented a new
customization option for Emacs 29.

When the attached patch is installed, if
show-paren-context-when-offscreen is t, when you move the point to a
closing delimiter, if the opening delimiter is offscreen, the line where
the opening line is will appear in the echo area.  This gives you
context about what a delimiter is closing without having to move the
point or reinsert it.  There is similar functionality in popular IDEs.

The feature is implemented by first extracting some code from simple.el
to reuse it from simple.el and paren.el.  The rest of the implementation
is simple.

I think it plays well with eldoc, blink-matching-paren, and the rest of
the show-paren-mode options.

I hope you find this feature useful.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-New-option-show-paren-context-when-offscreen.patch --]
[-- Type: text/x-patch, Size: 10585 bytes --]

From 6a3cf53c6afeed80a450faba0f66ff5f968142d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=ADn?= <mardani29@yahoo.es>
Date: Sat, 16 Oct 2021 20:24:19 +0200
Subject: [PATCH] New option show-paren-context-when-offscreen

* lisp/simple.el (blink-paren-open-paren-line-string): Extract
functionality that shows the open paren line in the echo area into its
own function, to reuse it from paren.el.
(blink-matching-open): Use blink-paren-open-paren-line-string.
* lisp/paren.el (show-paren-context-when-offscreen): New option
show-paren-context-when-offscreen.
(show-paren-function): Implement it using
blink-paren-open-paren-line-string.
* lisp/emacs-lisp/eldoc.el (eldoc-display-message-no-interference-p):
Make sure the feature works well with eldoc.
* test/lisp/paren-tests.el (paren-tests-open-paren-line): Test
blink-paren-open-paren-line-string.
* doc/emacs/programs.texi (Matching): Update the documentation.
* etc/NEWS: And announce the new feature.
---
 doc/emacs/programs.texi  |  9 +++++
 etc/NEWS                 |  8 +++++
 lisp/emacs-lisp/eldoc.el |  9 ++++-
 lisp/paren.el            | 21 ++++++++++++
 lisp/simple.el           | 71 +++++++++++++++++++++-------------------
 test/lisp/paren-tests.el | 31 ++++++++++++++++++
 6 files changed, 114 insertions(+), 35 deletions(-)

diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index 51a48df2e2..0056906e1f 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -868,6 +868,15 @@ Matching
 line and there is a paren at the first or last non-whitespace position
 on the line, or when point is at the end of a line and there is a
 paren at the last non-whitespace position on the line.
+
+@item
+@vindex show-paren-context-when-offscreen
+@code{show-paren-context-when-offscreen}, when non-@code{nil}, shows
+some context in the echo area when point is in a closing delimiter and
+the opening delimiter is offscreen.  The context is usually the line
+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.
 @end itemize
 
 @cindex Electric Pair mode
diff --git a/etc/NEWS b/etc/NEWS
index 2c09d24dde..5313e8e7ca 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -86,6 +86,14 @@ effectively dragged.
 Customize this option to limit the amount of entries in the menu
 "Edit->Paste from Kill Menu".  The default is 60.
 
+** show-paren-mode
+
++++
+*** New user option 'show-paren-context-when-offscreen'.
+When non-nil, if the point is in a closing delimiter and the opening
+delimiter is offscreen, shows some context around the opening
+delimiter in the echo area.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 29.1
 
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index a1c3c3268f..b30d3fc30f 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -380,7 +380,14 @@ eldoc-display-message-p
 ;; it undesirable to print eldoc messages right this instant.
 (defun eldoc-display-message-no-interference-p ()
   "Return nil if displaying a message would cause interference."
-  (not (or executing-kbd-macro (bound-and-true-p edebug-active))))
+  (not (or executing-kbd-macro
+           (bound-and-true-p edebug-active)
+           ;; The following configuration shows "Matches..." in the
+           ;; echo area when point is after a closing bracket, which
+           ;; conflicts with eldoc.
+           (and show-paren-context-when-offscreen
+                (not (pos-visible-in-window-p
+                      (overlay-end show-paren--overlay)))))))
 
 \f
 (defvar eldoc-documentation-functions nil
diff --git a/lisp/paren.el b/lisp/paren.el
index ce6aa9ae13..7e7cf6c262 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -88,6 +88,14 @@ show-paren-highlight-openparen
 its position."
   :type 'boolean)
 
+(defcustom show-paren-context-when-offscreen nil
+  "If non-nil, show context in the echo area when the openparen is offscreen.
+The context is usually the line that contains the openparen,
+except if the openparen is on its own line, in which case the
+context includes the previous nonblank line."
+  :type 'boolean
+  :version "29.1")
+
 (defvar show-paren--idle-timer nil)
 (defvar show-paren--overlay
   (let ((ol (make-overlay (point) (point) nil t))) (delete-overlay ol) ol)
@@ -312,6 +320,19 @@ show-paren-function
                             (current-buffer))
             (move-overlay show-paren--overlay
                           there-beg there-end (current-buffer)))
+          ;; If `show-paren-open-line-when-offscreen' is t and point
+          ;; is at a close paren, show the line that contains the
+          ;; openparen in the echo area.
+          (let ((openparen (min here-beg there-beg)))
+            (if (and show-paren-context-when-offscreen
+                     (< there-beg here-beg)
+                     (not (pos-visible-in-window-p openparen)))
+                (let ((open-paren-line-string
+                       (blink-paren-open-paren-line-string openparen))
+                      (message-log-max nil))
+                  (minibuffer-message
+                   "Matches %s"
+                   (substring-no-properties open-paren-line-string)))))
           ;; Always set the overlay face, since it varies.
           (overlay-put show-paren--overlay 'priority show-paren-priority)
           (overlay-put show-paren--overlay 'face face))))))
diff --git a/lisp/simple.el b/lisp/simple.el
index c7bb928cd7..4f711d60ea 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8577,40 +8577,43 @@ blink-matching-open
                                    (current-buffer))
                      (sit-for blink-matching-delay))
                  (delete-overlay blink-matching--overlay)))))
-       (t
-        (let ((open-paren-line-string
-               (save-excursion
-                 (goto-char blinkpos)
-                 ;; Show what precedes the open in its line, if anything.
-                 (cond
-                  ((save-excursion (skip-chars-backward " \t") (not (bolp)))
-                   (buffer-substring (line-beginning-position)
-                                     (1+ blinkpos)))
-                  ;; Show what follows the open in its line, if anything.
-                  ((save-excursion
-                     (forward-char 1)
-                     (skip-chars-forward " \t")
-                     (not (eolp)))
-                   (buffer-substring blinkpos
-                                     (line-end-position)))
-                  ;; Otherwise show the previous nonblank line,
-                  ;; if there is one.
-                  ((save-excursion (skip-chars-backward "\n \t") (not (bobp)))
-                   (concat
-                    (buffer-substring (progn
-                                        (skip-chars-backward "\n \t")
-                                        (line-beginning-position))
-                                      (progn (end-of-line)
-                                             (skip-chars-backward " \t")
-                                             (point)))
-                    ;; Replace the newline and other whitespace with `...'.
-                    "..."
-                    (buffer-substring blinkpos (1+ blinkpos))))
-                  ;; There is nothing to show except the char itself.
-                  (t (buffer-substring blinkpos (1+ blinkpos)))))))
-          (minibuffer-message
-           "Matches %s"
-           (substring-no-properties open-paren-line-string))))))))
+       ((not show-paren-context-when-offscreen)
+        (minibuffer-message
+         "Matches %s"
+         (substring-no-properties
+          (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."
+  (save-excursion
+    (goto-char pos)
+    ;; Show what precedes the open in its line, if anything.
+    (cond
+     ((save-excursion (skip-chars-backward " \t") (not (bolp)))
+      (buffer-substring (line-beginning-position)
+                        (1+ pos)))
+     ;; Show what follows the open in its line, if anything.
+     ((save-excursion
+        (forward-char 1)
+        (skip-chars-forward " \t")
+        (not (eolp)))
+      (buffer-substring pos
+                        (line-end-position)))
+     ;; Otherwise show the previous nonblank line,
+     ;; if there is one.
+     ((save-excursion (skip-chars-backward "\n \t") (not (bobp)))
+      (concat
+       (buffer-substring (progn
+                           (skip-chars-backward "\n \t")
+                           (line-beginning-position))
+                         (progn (end-of-line)
+                                (skip-chars-backward " \t")
+                                (point)))
+       ;; Replace the newline and other whitespace with `...'.
+       "..."
+       (buffer-substring pos (1+ pos))))
+     ;; There is nothing to show except the char itself.
+     (t (buffer-substring pos (1+ pos))))))
 
 (defvar blink-paren-function 'blink-matching-open
   "Function called, if non-nil, whenever a close parenthesis is inserted.
diff --git a/test/lisp/paren-tests.el b/test/lisp/paren-tests.el
index c4bec5d86d..11249ee9bc 100644
--- a/test/lisp/paren-tests.el
+++ b/test/lisp/paren-tests.el
@@ -117,5 +117,36 @@ paren-tests-default
                          (- (point-max) 1) (point-max)
                          nil)))))
 
+(ert-deftest paren-tests-open-paren-line ()
+  (cl-flet ((open-paren-line ()
+                             (let* ((data (show-paren--default))
+                                    (here-beg (nth 0 data))
+                                    (there-beg (nth 2 data)))
+                               (blink-paren-open-paren-line-string
+                                (min here-beg there-beg)))))
+    ;; Lisp-like
+    (with-temp-buffer
+      (insert "(defun foo ()
+                  (dummy))")
+      (goto-char (point-max))
+      (should (string= "(defun foo ()" (open-paren-line))))
+
+    ;; C-like
+    (with-temp-buffer
+      (insert "int foo() {
+                 int blah;
+             }")
+      (goto-char (point-max))
+      (should (string= "int foo() {" (open-paren-line))))
+
+    ;; C-like with hanging {
+    (with-temp-buffer
+      (insert "int foo()
+               {
+                 int blah;
+               }")
+      (goto-char (point-max))
+      (should (string= "int foo()...{" (open-paren-line))))))
+
 (provide 'paren-tests)
 ;;; paren-tests.el ends here
-- 
2.31.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* bug#51242: [PATCH] New option show-paren-context-when-offscreen
  2021-10-16 18:52 ` bug#51242: [PATCH] New option show-paren-context-when-offscreen Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-10-18  7:28   ` Lars Ingebrigtsen
  0 siblings, 0 replies; 2+ messages in thread
From: Lars Ingebrigtsen @ 2021-10-18  7:28 UTC (permalink / raw)
  To: Daniel Martín; +Cc: 51242

Daniel Martín <mardani29@yahoo.es> writes:

> When the attached patch is installed, if
> show-paren-context-when-offscreen is t, when you move the point to a
> closing delimiter, if the opening delimiter is offscreen, the line where
> the opening line is will appear in the echo area.  This gives you
> context about what a delimiter is closing without having to move the
> point or reinsert it.  There is similar functionality in popular IDEs.

I think that's really cool, so I've pushed this to Emacs 29.

One possible tweak:

> +                  (minibuffer-message
> +                   "Matches %s"
> +                   (substring-no-properties open-paren-line-string)))))

Would it make sense to retain the text properties, so that you get the
fontification in the echo area, too?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-10-18  7:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <m1o87ols48.fsf.ref@yahoo.es>
2021-10-16 18:52 ` bug#51242: [PATCH] New option show-paren-context-when-offscreen Daniel Martín via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-18  7:28   ` Lars Ingebrigtsen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).