emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Show Paren mode: New prelude style


From: Alain Schneble
Subject: Show Paren mode: New prelude style
Date: Thu, 27 Oct 2016 14:27:59 +0200

Below you will find a patch to extend show-paren-mode with a new
`prelude' style.  It's an extension of `parenthesis' style.  If the
matching opening paren is not visible, it will show the line of text
containing it as an overlay on the window's start line.  I think it's
pretty useful, as it helps in keeping context when working e.g. in
defuns with many lines of code -- all without having to scroll up and
down.

If this extension sounds useful to be included for some of you as well,
I would be very happy to get some feedback.  There for sure are things
to improve.  (It actually works quite well with the use cases I tried.)

To try it out:

- emacs -Q
- In scratch buffer, enter some long lisp expressions that overlap the
  window.
- (setq show-paren-style 'prelude)
- (show-paren-mode)

Note 1: There may already be such functionality available that I'm not
aware of.  Please let me know if that is the case.

Note 2: When the fade-in line contains multiple opening parens, the
matching one is highlighted.

Note 3: I'm not too sure about the colors to choose for the new
`show-paren-prelude' face.

Any feedback is welcome.

Thanks,
Alain

>From 5e5164ab6de8167004bf3ecac5937106984d64f9 Mon Sep 17 00:00:00 2001
From: Alain Schneble <address@hidden>
Date: Thu, 27 Oct 2016 13:47:18 +0200
Subject: [PATCH] New `prelude' style for show-paren-mode

* lisp/paren.el (show-paren-style): Add new prelude style to the list of
admissible styles.
* lisp/paren.el (show-paren--overlay-prelude): New overlay object.
* lisp/paren.el (show-paren-function): Implement new prelude style logic
to show line of text containing the matching opening paren on the
window's starting line, if it is not already visible.
* lisp/faces.el (show-paren-prelude): New defface to decorate new
show-paren--overlay-prelude overlay line.
* etc/NEWS (Show Paren mode): Add news entry for Show Paren mode, to
describe new style.
* doc/emacs/programs.texi (Matching): Update manual to include
description of new style.
---
 doc/emacs/programs.texi |  5 +++-
 etc/NEWS                |  8 +++++++
 lisp/faces.el           | 10 ++++++++
 lisp/paren.el           | 61 ++++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index 0c79d9c..20f9e97 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -851,7 +851,10 @@ Matching
 @code{parenthesis} (show the matching paren), @code{expression}
 (highlight the entire expression enclosed by the parens), and
 @code{mixed} (highlight the matching paren if it is visible, the
-expression otherwise).
+expression otherwise).  Furthermore, there is @code{prelude}, an
+extension of @code{parenthesis}, that shows the line of text
+containing the matching opening paren as an overlay on the window's
+start line, if it is not already visible.
 
 @item
 @code{show-paren-when-point-inside-paren}, when address@hidden, causes
diff --git a/etc/NEWS b/etc/NEWS
index d9973c0..e78fce7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -479,6 +479,14 @@ contents of the buffer to determine whether it's a C or 
C++ source
 file.
 
 
+** Show Paren mode
+
+*** New style 'prelude' to fade-in invisible lines of text.
+If point is at a closing paren and the matching opening paren is not
+visible, show line of text containing the opening paren as an overlay
+on the window's start line.
+
+
 * New Modes and Packages in Emacs 26.1
 
 ** New Elisp data-structure library 'radix-tree'.
diff --git a/lisp/faces.el b/lisp/faces.el
index d6ec98b..20f1b02 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -2807,6 +2807,16 @@ show-paren-mismatch
   "Face used for a mismatching paren."
   :group 'paren-showing-faces)
 
+(defface show-paren-prelude
+  '((((class color) (background light))
+     :background "lightblue")
+    (((class color) (background dark))
+     :background "darkblue")
+    (t
+     :inherit underline))
+  "Face used to fade-in invisible lines of text."
+  :group 'paren-showing-faces)
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Manipulating font names.
diff --git a/lisp/paren.el b/lisp/paren.el
index e37cace..af5908c 100644
--- a/lisp/paren.el
+++ b/lisp/paren.el
@@ -40,10 +40,12 @@ paren-showing
 (defcustom show-paren-style 'parenthesis
   "Style used when showing a matching paren.
 Valid styles are `parenthesis' (meaning show the matching paren),
-`expression' (meaning show the entire expression enclosed by the paren) and
+`expression' (meaning show the entire expression enclosed by the paren),
 `mixed' (meaning show the matching paren if it is visible, and the expression
-otherwise)."
-  :type '(choice (const parenthesis) (const expression) (const mixed)))
+otherwise) and `prelude' (meaning show the matching paren if it is
+visible, or the line of text containing the matching opening paren
+as an overlay in the window's start line)."
+  :type '(choice (const parenthesis) (const expression) (const mixed) (const 
prelude)))
 
 (defcustom show-paren-delay 0.125
   "Time in seconds to delay before showing a matching paren.
@@ -95,6 +97,9 @@ show-paren--overlay
 (defvar show-paren--overlay-1
   (let ((ol (make-overlay (point) (point) nil t))) (delete-overlay ol) ol)
   "Overlay used to highlight the paren at point.")
+(defvar show-paren--overlay-prelude
+  (let ((ol (make-overlay (point) (point) nil t))) (delete-overlay ol) ol)
+  "Overlay used to show the line of text containing the opening paren.")
 
 
 ;;;###autoload
@@ -118,7 +123,8 @@ show-paren-mode
                                 #'show-paren-function))
   (unless show-paren-mode
     (delete-overlay show-paren--overlay)
-    (delete-overlay show-paren--overlay-1)))
+    (delete-overlay show-paren--overlay-1)
+    (delete-overlay show-paren--overlay-prelude)))
 
 (defun show-paren--unescaped-p (pos)
   "Determine whether the paren after POS is unescaped."
@@ -234,10 +240,12 @@ show-paren-function
   (let ((data (and show-paren-mode (funcall show-paren-data-function))))
     (if (not data)
         (progn
-          ;; If show-paren-mode is nil in this buffer or if not at a paren that
-          ;; has a match, turn off any previous paren highlighting.
+          ;; If show-paren-mode is nil in this buffer or if not at a
+          ;; paren that has a match, turn off any previous paren
+          ;; highlighting and/or prelude overlay.
           (delete-overlay show-paren--overlay)
-          (delete-overlay show-paren--overlay-1))
+          (delete-overlay show-paren--overlay-1)
+          (delete-overlay show-paren--overlay-prelude))
 
       ;; Found something to highlight.
       (let* ((here-beg (nth 0 data))
@@ -287,7 +295,44 @@ show-paren-function
                           there-beg there-end (current-buffer)))
           ;; Always set the overlay face, since it varies.
           (overlay-put show-paren--overlay 'priority show-paren-priority)
-          (overlay-put show-paren--overlay 'face face))))))
+          (overlay-put show-paren--overlay 'face face))
+        ;;
+        ;; If point is at a closing paren and the matching opening
+        ;; paren is not visible, show line of text containing the
+        ;; opening paren as an overlay on the window's start line.
+        (if (and (eq show-paren-style 'prelude)
+                 there-beg              ; Matching paren found?
+                 (> here-beg there-beg) ; Point placed after closing paren?
+                 ;; Point not on topmost line?
+                 (> (line-number-at-pos here-end) (line-number-at-pos 
(window-start)))
+                 ;; Opening paren not visible?
+                 (not (pos-visible-in-window-p there-beg)))
+            (let* ((prelude-overlay-beg (window-start))
+                   (prelude-overlay-end
+                    ;; Include trailing newline to enable overlays to
+                    ;; work properly on empty lines.
+                    (1+ (line-end-position (- (- (count-lines 
prelude-overlay-beg here-end) 2)))))
+                   (prelude-line-dist (- (- (count-lines there-beg here-end) 
2)))
+                   (prelude-text
+                    (buffer-substring
+                     (line-beginning-position prelude-line-dist)
+                     ;; Again, include newline.
+                     (1+ (line-end-position prelude-line-dist))))
+                   ;; Translate opening paren pos to relative pos in
+                   ;; overlay text.
+                   (prelude-text-paren-beg
+                    (- there-beg (line-beginning-position prelude-line-dist))))
+              ;; Highlight opening paren in overlay text.
+              (put-text-property
+               prelude-text-paren-beg (+ prelude-text-paren-beg (- there-end 
there-beg))
+               'face 'show-paren-match prelude-text)
+              ;; Refresh overlay.
+              (move-overlay show-paren--overlay-prelude
+                            prelude-overlay-beg prelude-overlay-end 
(current-buffer))
+              (overlay-put show-paren--overlay-prelude 'display prelude-text)
+              (overlay-put show-paren--overlay-prelude 'priority 
show-paren-priority)
+              (overlay-put show-paren--overlay-prelude 'face 
'show-paren-prelude))
+          (delete-overlay show-paren--overlay-prelude))))))
 
 (provide 'paren)
 
-- 
2.9.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]