From 5e5164ab6de8167004bf3ecac5937106984d64f9 Mon Sep 17 00:00:00 2001 From: Alain Schneble 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 non-@code{nil}, 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