;;; foldit.el --- Helpers for folding ;; ;; Author: Lennart Borgman (lennart O borgman A gmail O com) ;; Created: 2009-08-10 Mon ;; Version: ;; Last-Updated: ;; URL: ;; Keywords: ;; Compatibility: ;; ;; Features that might be required by this library: ;; ;; None ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; Defines `foldit-mode' which puts visual clues on hidden regions. ;; Does not do any folding itself but works with `outline-minor-mode' ;; and `hs-minor-mode'. ;; ;; Fix-me: reveal-mode does not work with this and I have no idea why ;; ... ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Change log: ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 3, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: ;; Fix-me: start-tag-beg/start-tag-end are workarounds for smaller ;; bugs in hs-minor-mode and outline-minor-mode. Maybe try to fix ;; them... - but there are a whole bunch of other invisibilty related ;; bugs that ought to be fixed first since otherwise it is impossible ;; to know where point goes after hiding/unhiding. (eval-when-compile (require 'cl)) (eval-when-compile (require 'hideshow)) (eval-when-compile (require 'mumamo nil t)) (eval-when-compile (require 'outline)) (defsubst foldit-overlay-priority () (1+ (or (and (boundp 'mlinks-link-overlay-priority) mlinks-link-overlay-priority) 100))) ;;;###autoload (defgroup foldit nil "Customization group for foldit folding helpers." :group 'nxhtml) (defvar foldit-temp-at-point-ovl nil) (make-variable-buffer-local 'foldit-temp-at-point-ovl) ;;;###autoload (define-minor-mode foldit-mode "Minor mode providing visual aids for folding. Shows some hints about what you have hidden and how to reveal it. Supports `hs-minor-mode', `outline-minor-mode' and major modes derived from `outline-mode'." :lighter nil (if foldit-mode (progn ;; Outline (add-hook 'outline-view-change-hook 'foldit-outline-change nil t) ;; Add our overlays (when (or (and (boundp 'outline-minor-mode) outline-minor-mode) ;; Fix-me: mumamo (derived-mode-p 'outline-mode)) (foldit-outline-change)) ;; hs (unless (local-variable-p 'hs-set-up-overlay) (set (make-local-variable 'hs-set-up-overlay) 'foldit-hs-set-up-overlay)) ;; Add our overlays (when (or (and (boundp 'hs-minor-mode) hs-minor-mode)) (save-restriction (widen) (let (ovl) (dolist (ovl (overlays-in (point-min) (point-max))) (when (eq (overlay-get ovl 'invisible) 'hs) (funcall hs-set-up-overlay ovl))))))) ;; Outline (remove-hook 'outline-view-change-hook 'foldit-outline-change t) ;; hs (when (and (local-variable-p 'hs-set-up-overlay) (eq hs-set-up-overlay 'foldit-hs-set-up-overlay)) (kill-local-variable 'hs-set-up-overlay)) ;; Remove our overlays (save-restriction (widen) (let (ovl prop) (dolist (ovl (overlays-in (point-min) (point-max))) (when (setq prop (overlay-get ovl 'foldit)) (case prop ;;('display (overlay-put ovl 'display nil)) ('foldit (delete-overlay ovl)) (t (delete-overlay ovl)) ))))))) (defcustom foldit-avoid '(org-mode) "List of major modes to avoid." :group 'foldit) ;;;###autoload (define-globalized-minor-mode foldit-global-mode foldit-mode (lambda () (foldit-mode 1)) :group 'foldit) (defun foldit-hidden-line-str (hidden-lines type) "String to display for hidden lines. HIDDEN-LINES are the number of lines and TYPE is a string indicating how they were hidden." (propertize (format " ...(%d %slines)" hidden-lines type) 'face 'shadow)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Outline (defvar foldit-outline-keymap (let ((map (make-sparse-keymap))) (define-key map "\r" 'foldit-outline-show-entry) (define-key map [down-mouse-1] 'foldit-outline-show-entry) (define-key map [S-tab] 'mlinks-backward-link) (define-key map [tab] 'mlinks-forward-link) (define-key map "\t" 'mlinks-forward-link) map)) (defun foldit-outline-change () "Check outline overlays. Run this in `outline-view-change-hook'." ;; We get the variables FROM and TO here from `outline-flag-region' ;; so let us use them. But O is hidden... (let* (from to num-lines ovl (tag "")) (cond ((and (boundp 'start) start (boundp 'end) end) (setq from start) (setq to end)) (t (setq from (point-min)) (setq to (point-max)))) (dolist (ovl (overlays-in from to)) (when (eq (overlay-get ovl 'invisible) 'outline) (setq num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) (overlay-put ovl 'display (concat (propertize "+" 'face 'mode-line) "" tag (foldit-hidden-line-str num-lines ""))) (overlay-put ovl 'foldit 'display) ;; Should be a list... (overlay-put ovl 'keymap foldit-outline-keymap) (overlay-put ovl 'face 'lazy-highlight) (overlay-put ovl 'mouse-face 'highlight) (overlay-put ovl 'help-echo "Press RET to show hidden part") (overlay-put ovl 'mlinks-link t) (overlay-put ovl 'priority (foldit-overlay-priority)) (mumamo-with-buffer-prepared-for-jit-lock (let* ((start-tag-beg (overlay-start ovl)) (start-tag-end start-tag-beg)) (put-text-property start-tag-beg (+ start-tag-beg 1) 'foldit-tag-end (copy-marker start-tag-end)))) )))) (defvar foldit-outline-hide-again-keymap (let ((map (make-sparse-keymap))) (define-key map "\r" 'foldit-outline-hide-again) (define-key map [down-mouse-1] 'foldit-outline-hide-again) (define-key map [S-tab] 'mlinks-backward-link) (define-key map [tab] 'mlinks-forward-link) (define-key map "\t" 'mlinks-forward-link) map)) (defun foldit-outline-show-entry () "Show hidden entry." (interactive) (let ((tag-end (get-text-property (point) 'foldit-tag-end))) (show-entry) (mumamo-with-buffer-prepared-for-jit-lock (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) (when tag-end (goto-char tag-end)) (foldit-add-temp-at-point-overlay "-" foldit-outline-hide-again-keymap "Press RET to hide again"))) (defun foldit-outline-hide-again () "Hide entry again." (interactive) (when (overlayp foldit-temp-at-point-ovl) (delete-overlay foldit-temp-at-point-ovl)) (hide-entry)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Hide/Show (defvar foldit-hs-start-tag-end-func 'foldit-hs-default-start-tag-end) (make-variable-buffer-local 'foldit-hs-start-tag-end-func) (put 'foldit-hs-start-tag-end-func 'permanent-local t) (defun foldit-hs-default-start-tag-end (beg) "Find end of hide/show tag beginning at BEG." (min (+ beg 65) (save-excursion (goto-char beg) (line-end-position)))) (defvar foldit-hs-keymap (let ((map (make-sparse-keymap))) (define-key map "\r" 'foldit-hs-show-block) (define-key map [down-mouse-1] 'foldit-hs-show-block) (define-key map [S-tab] 'mlinks-backward-link) (define-key map [tab] 'mlinks-forward-link) (define-key map "\t" 'mlinks-forward-link) map)) (defvar foldit-hs-hide-again-keymap (let ((map (make-sparse-keymap))) (define-key map "\r" 'foldit-hs-hide-again) (define-key map [down-mouse-1] 'foldit-hs-hide-again) (define-key map [S-tab] 'mlinks-backward-link) (define-key map [tab] 'mlinks-forward-link) (define-key map "\t" 'mlinks-forward-link) map)) (defun foldit-hs-set-up-overlay (ovl) "Set up overlay OVL for hide/show." (let* ((num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) (here (point)) (start-tag-beg (overlay-start ovl)) (start-tag-end (funcall foldit-hs-start-tag-end-func start-tag-beg)) (tag (buffer-substring start-tag-beg start-tag-end))) (goto-char here) ;;(overlay-put ovl 'isearch-open-invisible t) (overlay-put ovl 'display (concat (propertize "+" 'face 'mode-line) " " tag (foldit-hidden-line-str num-lines "h"))) (overlay-put ovl 'foldit 'display) (overlay-put ovl 'keymap foldit-hs-keymap) (overlay-put ovl 'face 'next-error) (overlay-put ovl 'face 'lazy-highlight) (overlay-put ovl 'mouse-face 'highlight) (overlay-put ovl 'help-echo "Press RET to show hidden part") (overlay-put ovl 'mlinks-link t) (overlay-put ovl 'priority (foldit-overlay-priority)) (mumamo-with-buffer-prepared-for-jit-lock (put-text-property start-tag-beg (+ start-tag-beg 1) 'foldit-tag-end (copy-marker start-tag-end))))) (defun foldit-hs-show-block () "Show hidden block." (interactive) (let ((tag-end (get-text-property (point) 'foldit-tag-end))) (hs-show-block) (mumamo-with-buffer-prepared-for-jit-lock (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) (when tag-end (goto-char tag-end)) (foldit-add-temp-at-point-overlay "-" foldit-hs-hide-again-keymap "Press RET to hide again"))) (defun foldit-hs-hide-again () "Hide hide/show block again." (interactive) (when (overlayp foldit-temp-at-point-ovl) (delete-overlay foldit-temp-at-point-ovl)) (hs-hide-block)) ;;; Fix-me: break out this ;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (defun foldit-add-temp-at-point-overlay (marker keymap msg) "Add a temporary overlay with a marker MARKER and a keymap KEYMAP. The overlay is also given the help echo MSG. This overlay is removed as soon as point moves from current point." (let ((ovl (make-overlay (point) (1+ (point)))) (real (buffer-substring (point) (1+ (point))))) (overlay-put ovl 'isearch-open-invisible t) (overlay-put ovl 'display (concat (propertize marker 'face 'mode-line) " " msg real)) (overlay-put ovl 'foldit 'foldit) (overlay-put ovl 'keymap keymap) (overlay-put ovl 'face 'lazy-highlight) (overlay-put ovl 'mouse-face 'highlight) (overlay-put ovl 'help-echo msg) (overlay-put ovl 'mlinks-link t) (overlay-put ovl 'priority (foldit-overlay-priority)) (setq foldit-temp-at-point-ovl ovl) (add-hook 'post-command-hook 'foldit-remove-temp-at-point-overlay nil t))) (defun foldit-remove-temp-at-point-overlay () "Remove overlay made by `foldit-add-temp-at-point-overlay'." (condition-case err (unless (and foldit-temp-at-point-ovl (overlay-buffer foldit-temp-at-point-ovl) (= (overlay-start foldit-temp-at-point-ovl) (point))) (delete-overlay foldit-temp-at-point-ovl) (setq foldit-temp-at-point-ovl nil) (remove-hook 'post-command-hook 'foldit-remove-temp-at-point-overlay t) ) (error (message "foldit-remove-temp-at-point-overlay: %s" (propertize (error-message-string err)))))) ;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ;; (defun put-before-on-invis () ;; (let* (o ;; (io (catch 'io ;; (dolist (o (overlays-at (1+ (point)))) ;; (when (overlay-get o 'invisible) ;; (throw 'io o))))) ;; (str (propertize "IOSTRING" ;; 'face 'secondary-selection ;; ))) ;; (overlay-put io 'before-string str) ;; ;;(overlay-put io 'display "display") ;; (overlay-put io 'display nil) ;; ;;(overlay-put io 'after-string "AFTER") ;; )) (provide 'foldit) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; foldit.el ends here