From 47b4e2830e8049ed6ab7f313aaa0fb9ac3e57b7b Mon Sep 17 00:00:00 2001 From: Nicholas Seckar Date: Sun, 11 Oct 2015 12:23:48 -0700 Subject: [PATCH 1/4] Add header style for fold display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Header mode is optional, enabled via origami-fold-display-mode. Rendering is similar to vimish-fold’s style. --- origami.el | 79 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/origami.el b/origami.el index 3f34f79..7ccb7fd 100644 --- a/origami.el +++ b/origami.el @@ -37,27 +37,79 @@ (require 'cl) (require 'origami-parsers) +;;; fold display mode and faces + +(defcustom origami-fold-display-mode 'dots + "Display mode for folded areas. +By default, a traditional \"...\" format is used. A highlighted +header is also available." + :tag "Display mode for folds" + :type '(choice (const :tag "Three dots" dots) + (const :tag "Highlighted header" header)) + :group 'origami) + +(defface origami-fold-header + '((t (:box (:line-width 1 :color "#050") + :background "#001500"))) + "Face used to display fold headers.") + +(defface origami-fold-fringe + '((t (:inherit highlight))) + "Face used to display fringe contents.") + +(defgroup origami '((origami-fold-header custom-face) + (origami-fold-fringe custom-face)) + "Origami: A text folding minor mode for Emacs, by Greg Sexton.") + ;;; overlay manipulation (defun origami-create-overlay (beg end offset buffer) (when (> (- end beg) 0) (let ((ov (make-overlay (+ beg offset) end buffer))) + (overlay-put ov 'creator 'origami) (overlay-put ov 'isearch-open-invisible 'origami-isearch-show) (overlay-put ov 'isearch-open-invisible-temporary (lambda (ov hide-p) (if hide-p (origami-hide-overlay ov) (origami-show-overlay ov)))) - ov))) + ;; We create a header overlay even when disabled; this could be avoided, + ;; especially if we called origami-reset for each buffer if customizations + ;; changed. + (with-current-buffer buffer + (let* ((line-begin + (save-excursion + (goto-char (+ beg offset)) + (line-beginning-position))) + (fold-end + ;; Find the end of the folded region -- try to include the + ;; newline if possible. The header will span the entire fold. + (save-excursion + (goto-char end) + (when (looking-at ".") + (forward-char 1) + (when (looking-at "\n") + (forward-char 1))) + (point))) + (header-ov (make-overlay line-begin fold-end buffer))) + (overlay-put header-ov 'creator 'origami) + (overlay-put header-ov 'fold-overlay ov) + (overlay-put ov 'header-ov header-ov))) + ov))) (defun origami-hide-overlay (ov) - ;; TODO: make all of this customizable + ;; TODO: make more of this customizable (overlay-put ov 'invisible 'origami) - (overlay-put ov 'display "...") - (overlay-put ov 'face 'font-lock-comment-delimiter-face)) + (case origami-fold-display-mode + ('dots + (overlay-put ov 'display "...") + (overlay-put ov 'face 'font-lock-comment-delimiter-face)) + ('header + (origami-activate-header (overlay-get ov 'header-ov))))) (defun origami-show-overlay (ov) (overlay-put ov 'invisible nil) (overlay-put ov 'display nil) - (overlay-put ov 'face nil)) + (overlay-put ov 'face nil) + (origami-deactivate-header (overlay-get ov 'header-ov))) (defun origami-hide-node-overlay (node) (-when-let (ov (origami-fold-data node)) @@ -67,6 +119,21 @@ (-when-let (ov (origami-fold-data node)) (origami-show-overlay ov))) +(defun origami-activate-header (ov) + (overlay-put ov 'origami-header-active t) + (overlay-put ov 'face 'origami-fold-header) + (overlay-put ov 'before-string + (propertize + "…" + 'display + '(left-fringe empty-line origami-fold-fringe)))) + +(defun origami-deactivate-header (ov) + (overlay-put ov 'origami-header-active nil) + (overlay-put ov 'face nil) + (overlay-put ov 'before-string nil) + (overlay-put ov 'after-string nil)) + (defun origami-isearch-show (ov) (origami-show-node (current-buffer) (point))) @@ -83,7 +150,7 @@ (defun origami-remove-all-overlays (buffer) (with-current-buffer buffer - (remove-overlays (point-min) (point-max) 'invisible 'origami))) + (remove-overlays (point-min) (point-max) 'creator 'origami))) ;;; fold structure From d372bd1af1283866c3c08b2b282107e999a68a65 Mon Sep 17 00:00:00 2001 From: Nicholas Seckar Date: Sun, 11 Oct 2015 13:08:19 -0700 Subject: [PATCH 2/4] Allow dots plus header mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed origami-fold-display-mode; instead display is controlled via new customs origami-show-fold-header and origami-fold-replacement. Replacement text can be customized, or set to “” to effectively disable. --- origami.el | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/origami.el b/origami.el index 7ccb7fd..3fc2ded 100644 --- a/origami.el +++ b/origami.el @@ -39,26 +39,32 @@ ;;; fold display mode and faces -(defcustom origami-fold-display-mode 'dots - "Display mode for folded areas. -By default, a traditional \"...\" format is used. A highlighted -header is also available." - :tag "Display mode for folds" - :type '(choice (const :tag "Three dots" dots) - (const :tag "Highlighted header" header)) +(defcustom origami-fold-replacement "..." + "Show this string instead of the folded text." + :type 'string :group 'origami) -(defface origami-fold-header +(defcustom origami-show-fold-header t + "Highlight the line the fold start on." + :type 'boolean + :group 'origami) + +(defface origami-fold-header-face '((t (:box (:line-width 1 :color "#050") :background "#001500"))) "Face used to display fold headers.") -(defface origami-fold-fringe - '((t (:inherit highlight))) +(defface origami-fold-fringe-face + '((t ())) "Face used to display fringe contents.") -(defgroup origami '((origami-fold-header custom-face) - (origami-fold-fringe custom-face)) +(defface origami-fold-replacement-face + '((t :foreground "#555")) + "Face used to display the fold replacement text.") + +(defgroup origami '((origami-fold-header-face custom-face) + (origami-fold-fringe-face custom-face) + (origami-fold-replacement-face custom-face)) "Origami: A text folding minor mode for Emacs, by Greg Sexton.") ;;; overlay manipulation @@ -98,12 +104,10 @@ header is also available." (defun origami-hide-overlay (ov) ;; TODO: make more of this customizable (overlay-put ov 'invisible 'origami) - (case origami-fold-display-mode - ('dots - (overlay-put ov 'display "...") - (overlay-put ov 'face 'font-lock-comment-delimiter-face)) - ('header - (origami-activate-header (overlay-get ov 'header-ov))))) + (overlay-put ov 'display origami-fold-replacement) + (overlay-put ov 'face 'origami-fold-replacement-face) + (if origami-show-fold-header + (origami-activate-header (overlay-get ov 'header-ov)))) (defun origami-show-overlay (ov) (overlay-put ov 'invisible nil) @@ -121,12 +125,12 @@ header is also available." (defun origami-activate-header (ov) (overlay-put ov 'origami-header-active t) - (overlay-put ov 'face 'origami-fold-header) + (overlay-put ov 'face 'origami-fold-header-face) (overlay-put ov 'before-string (propertize "…" 'display - '(left-fringe empty-line origami-fold-fringe)))) + '(left-fringe empty-line origami-fold-fringe-face)))) (defun origami-deactivate-header (ov) (overlay-put ov 'origami-header-active nil) From eafd97fc7011618cd21d6d8bcf896a64bea1dc30 Mon Sep 17 00:00:00 2001 From: Nicholas Seckar Date: Tue, 20 Oct 2015 13:17:33 -0700 Subject: [PATCH 3/4] Recompute header ranges when folding. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously header ranges could be broken to extend over previous lines. The easiest way to reproduce is to put the caret at ^ in this line: fn ^foo() { … } And insert a newline; the header will cover both the “fn “ and “foo() { … }” lines. This hacky patch recomputes the header range whenever a modification happens inside it. --- origami.el | 60 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/origami.el b/origami.el index 3fc2ded..1078384 100644 --- a/origami.el +++ b/origami.el @@ -69,6 +69,34 @@ ;;; overlay manipulation +(defun origami-header-overlay-range (fold-overlay) + "Given a `fold-overlay', return the range that the corresponding +header overlay should cover. Result is a cons cell of (begin . end)." + (with-current-buffer (overlay-buffer fold-overlay) + (let ((fold-begin + (save-excursion + (goto-char (overlay-start fold-overlay)) + (line-beginning-position))) + (fold-end + ;; Find the end of the folded region -- include the following + ;; newline if possible. The header will span the entire fold. + (save-excursion + (goto-char (overlay-end fold-overlay)) + (when (looking-at ".") + (forward-char 1) + (when (looking-at "\n") + (forward-char 1))) + (point)))) + (cons fold-begin fold-end)))) + +(defun origami-header-overlay-reset-position (header-overlay) + (-when-let (fold-ov (overlay-get header-overlay 'fold-overlay)) + (let ((range (origami-header-overlay-range fold-ov))) + (move-overlay header-overlay (car range) (cdr range))))) + +(defun origami-header-modify-hook (header-overlay after-p b e &optional l) + (if after-p (origami-header-overlay-reset-position header-overlay))) + (defun origami-create-overlay (beg end offset buffer) (when (> (- end beg) 0) (let ((ov (make-overlay (+ beg offset) end buffer))) @@ -80,26 +108,14 @@ ;; We create a header overlay even when disabled; this could be avoided, ;; especially if we called origami-reset for each buffer if customizations ;; changed. - (with-current-buffer buffer - (let* ((line-begin - (save-excursion - (goto-char (+ beg offset)) - (line-beginning-position))) - (fold-end - ;; Find the end of the folded region -- try to include the - ;; newline if possible. The header will span the entire fold. - (save-excursion - (goto-char end) - (when (looking-at ".") - (forward-char 1) - (when (looking-at "\n") - (forward-char 1))) - (point))) - (header-ov (make-overlay line-begin fold-end buffer))) - (overlay-put header-ov 'creator 'origami) - (overlay-put header-ov 'fold-overlay ov) - (overlay-put ov 'header-ov header-ov))) - ov))) + (let* ((range (origami-header-overlay-range ov)) + (header-ov (make-overlay (car range) (cdr range) buffer + nil))) ;; no front advance + (overlay-put header-ov 'creator 'origami) + (overlay-put header-ov 'fold-overlay ov) + (overlay-put header-ov 'modification-hooks '(origami-header-modify-hook)) + (overlay-put ov 'header-ov header-ov)) + ov))) (defun origami-hide-overlay (ov) ;; TODO: make more of this customizable @@ -124,6 +140,10 @@ (origami-show-overlay ov))) (defun origami-activate-header (ov) + ;; Reposition the header overlay. Since it extends before the folded area, it + ;; may no longer cover the appropriate locations. + (origami-header-overlay-reset-position ov) + (overlay-put ov 'origami-header-active t) (overlay-put ov 'face 'origami-fold-header-face) (overlay-put ov 'before-string From 9b9356cd63d40faa3eeb64348e602d10da57b1f2 Mon Sep 17 00:00:00 2001 From: Greg Sexton Date: Sun, 13 Mar 2016 21:13:33 +0000 Subject: [PATCH 4/4] Change default values for customization options --- origami.el | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/origami.el b/origami.el index 1078384..9c27976 100644 --- a/origami.el +++ b/origami.el @@ -40,18 +40,19 @@ ;;; fold display mode and faces (defcustom origami-fold-replacement "..." + ;; TODO: this should also be specifiable as a function: folded text -> string "Show this string instead of the folded text." :type 'string :group 'origami) -(defcustom origami-show-fold-header t +(defcustom origami-show-fold-header nil "Highlight the line the fold start on." :type 'boolean :group 'origami) (defface origami-fold-header-face - '((t (:box (:line-width 1 :color "#050") - :background "#001500"))) + `((t (:box (:line-width 1 :color ,(face-attribute 'highlight :background)) + :background ,(face-attribute 'highlight :background)))) "Face used to display fold headers.") (defface origami-fold-fringe-face @@ -59,13 +60,13 @@ "Face used to display fringe contents.") (defface origami-fold-replacement-face - '((t :foreground "#555")) + '((t :inherit 'font-lock-comment-face)) "Face used to display the fold replacement text.") (defgroup origami '((origami-fold-header-face custom-face) - (origami-fold-fringe-face custom-face) - (origami-fold-replacement-face custom-face)) - "Origami: A text folding minor mode for Emacs, by Greg Sexton.") + (origami-fold-fringe-face custom-face) + (origami-fold-replacement-face custom-face)) + "Origami: A text folding minor mode for Emacs.") ;;; overlay manipulation @@ -110,7 +111,7 @@ header overlay should cover. Result is a cons cell of (begin . end)." ;; changed. (let* ((range (origami-header-overlay-range ov)) (header-ov (make-overlay (car range) (cdr range) buffer - nil))) ;; no front advance + nil))) ;; no front advance (overlay-put header-ov 'creator 'origami) (overlay-put header-ov 'fold-overlay ov) (overlay-put header-ov 'modification-hooks '(origami-header-modify-hook)) @@ -118,12 +119,11 @@ header overlay should cover. Result is a cons cell of (begin . end)." ov))) (defun origami-hide-overlay (ov) - ;; TODO: make more of this customizable (overlay-put ov 'invisible 'origami) (overlay-put ov 'display origami-fold-replacement) (overlay-put ov 'face 'origami-fold-replacement-face) (if origami-show-fold-header - (origami-activate-header (overlay-get ov 'header-ov)))) + (origami-activate-header (overlay-get ov 'header-ov)))) (defun origami-show-overlay (ov) (overlay-put ov 'invisible nil) @@ -143,7 +143,6 @@ header overlay should cover. Result is a cons cell of (begin . end)." ;; Reposition the header overlay. Since it extends before the folded area, it ;; may no longer cover the appropriate locations. (origami-header-overlay-reset-position ov) - (overlay-put ov 'origami-header-active t) (overlay-put ov 'face 'origami-fold-header-face) (overlay-put ov 'before-string