]> code.delx.au - gnu-emacs/blobdiff - lisp/reveal.el
2005-10-01 Roland Winkler <Roland.Winkler@physik.uni-erlangen.de>
[gnu-emacs] / lisp / reveal.el
index d9754557475a54f4957db5a0a5424c21f17598d6..41b7c4268c27de713de93954a1f12675fe8b5bfd 100644 (file)
@@ -1,24 +1,27 @@
 ;;; reveal.el --- Automatically reveal hidden text at point
 
-;; Copyright (C) 2000, 2001  Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
+;;   2005 Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@cs.yale.edu>
 ;; Keywords: outlines
 
-;; This file is free software; you can redistribute it and/or modify
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 2, or (at your option)
 ;; any later version.
 
-;; This file is distributed in the hope that it will be useful,
+;; GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 
 (defcustom reveal-around-mark t
   "Reveal text around the mark, if active."
-  :type 'boolean)
+  :type 'boolean
+  :group 'reveal)
 
 (defvar reveal-open-spots nil)
 (make-variable-buffer-local 'reveal-open-spots)
 
+(defvar reveal-last-tick nil)
+(make-variable-buffer-local 'reveal-last-tick)
+
 ;; Actual code
 
 (defun reveal-post-command ()
@@ -66,6 +73,7 @@
   ;; - we only refresh spots in the current window.
   ;; FIXME: do we actually know that (current-buffer) = (window-buffer) ?
   (with-local-quit
+  (condition-case err
    (let* ((spots (cvs-partition
                  (lambda (x)
                    ;; We refresh any spot in the current window as well
                                 (current-buffer)))))
                  reveal-open-spots))
          (old-ols (mapcar 'cdr (car spots)))
-         (repeat t)
-         ;; `post-command-hook' binds it to t, but the user might want to
-         ;; interrupt our work if we somehow get stuck in an infinite loop.
-         (inhibit-quit nil)
-         inv open)
+         (repeat t))
      (setq reveal-open-spots (cdr spots))
      ;; Open new overlays.
      (while repeat
                          (overlays-at (point))))
         (push (cons (selected-window) ol) reveal-open-spots)
         (setq old-ols (delq ol old-ols))
-        (when (setq inv (overlay-get ol 'invisible))
-          (when (or (overlay-get ol 'isearch-open-invisible)
-                    (and (consp buffer-invisibility-spec)
-                         (assq inv buffer-invisibility-spec)))
-            (overlay-put ol 'reveal-invisible inv)
-            (overlay-put ol 'invisible nil)
-            (when (setq open (get inv 'reveal-toggle-invisible))
+        (let ((inv (overlay-get ol 'invisible)) open)
+          (when (and inv
+                     ;; There's an `invisible' property.  Make sure it's
+                     ;; actually invisible.
+                     (or (not (listp buffer-invisibility-spec))
+                         (memq inv buffer-invisibility-spec)
+                         (assq inv buffer-invisibility-spec))
+                     (or (setq open
+                               (or (overlay-get ol 'reveal-toggle-invisible)
+                                   (and (symbolp inv)
+                                        (get inv 'reveal-toggle-invisible))
+                                   (overlay-get ol 'isearch-open-invisible-temporary)))
+                         (overlay-get ol 'isearch-open-invisible)
+                         (and (consp buffer-invisibility-spec)
+                              (cdr (assq inv buffer-invisibility-spec))))
+                     (overlay-put ol 'reveal-invisible inv))
+            (if (null open)
+                (overlay-put ol 'invisible nil)
               ;; Use the provided opening function and repeat (since the
               ;; opening function might have hidden a subpart around point).
               (setq repeat t)
               (condition-case err
-                  (funcall open ol t)
-                (error (message "!!Reveal-show: %s !!" err))))))))
+                  (funcall open ol nil)
+                (error (message "!!Reveal-show (funcall %s %s nil): %s !!"
+                                open ol err)
+                       ;; Let's default to a meaningful behavior to avoid
+                       ;; getting stuck in an infinite loop.
+                       (setq repeat nil)
+                       (overlay-put ol 'invisible nil))))))))
      ;; Close old overlays.
-     (dolist (ol old-ols)
-       (when (and (setq inv (overlay-get ol 'reveal-invisible))
-                 (eq (current-buffer) (overlay-buffer ol))
-                 (not (rassq ol reveal-open-spots)))
-        (if (and (>= (point) (save-excursion
-                               (goto-char (overlay-start ol))
-                               (line-beginning-position 1)))
-                 (<= (point) (save-excursion
-                               (goto-char (overlay-end ol))
-                               (line-beginning-position 2))))
-            ;; Still near the overlay: keep it open.
-            (push (cons (selected-window) ol) reveal-open-spots)
-          ;; Really close it.
-          (overlay-put ol 'invisible inv)
-          (when (setq open (get inv 'reveal-toggle-invisible))
-            (condition-case err
-                (funcall open ol nil)
-              (error (message "!!Reveal-hide: %s !!" err))))))))))
+     (if (not (eq reveal-last-tick
+                 (setq reveal-last-tick (buffer-modified-tick))))
+        ;; The buffer was modified since last command: let's refrain from
+        ;; closing any overlay because it tends to behave poorly when
+        ;; inserting text at the end of an overlay (basically the overlay
+        ;; should be rear-advance when it's open, but things like
+        ;; outline-minor-mode make it non-rear-advance because it's
+        ;; a better choice when it's closed).
+        (dolist (ol old-ols)
+          (push (cons (selected-window) ol) reveal-open-spots))
+       ;; The last command was only a point motion or some such
+       ;; non-buffer-modifying command.  Let's close whatever can be closed.
+       (dolist (ol old-ols)
+        (when (and (eq (current-buffer) (overlay-buffer ol))
+                   (not (rassq ol reveal-open-spots)))
+          (if (and (>= (point) (save-excursion
+                                 (goto-char (overlay-start ol))
+                                 (line-beginning-position 1)))
+                   (<= (point) (save-excursion
+                                 (goto-char (overlay-end ol))
+                                 (line-beginning-position 2))))
+              ;; Still near the overlay: keep it open.
+              (push (cons (selected-window) ol) reveal-open-spots)
+            ;; Really close it.
+            (let ((open (overlay-get ol 'reveal-toggle-invisible)) inv)
+              (if (or open
+                      (and (setq inv (overlay-get ol 'reveal-invisible))
+                           (setq open (or (get inv 'reveal-toggle-invisible)
+                                          (overlay-get ol 'isearch-open-invisible-temporary)))))
+                  (condition-case err
+                      (funcall open ol t)
+                    (error (message "!!Reveal-hide (funcall %s %s t): %s !!"
+                                    open ol err)))
+                (overlay-put ol 'invisible inv))))))))
+   (error (message "Reveal: %s" err)))))
+
+(defvar reveal-mode-map
+  (let ((map (make-sparse-keymap)))
+    ;; Override the default move-beginning-of-line and move-end-of-line
+    ;; which skips valuable invisible text.
+    (define-key map [remap move-beginning-of-line] 'beginning-of-line)
+    (define-key map [remap move-end-of-line] 'end-of-line)
+    map))
 
 ;;;###autoload
 (define-minor-mode reveal-mode
@@ -132,7 +177,9 @@ Reveal mode renders invisible text around point visible again.
 Interactively, with no prefix argument, toggle the mode.
 With universal prefix ARG (or if ARG is nil) turn mode on.
 With zero or negative ARG turn mode off."
-  :lighter "Reveal"
+  :group 'reveal
+  :lighter (global-reveal-mode nil " Reveal")
+  :keymap reveal-mode-map
   (if reveal-mode
       (progn
        (set (make-local-variable 'search-invisible) t)
@@ -148,7 +195,7 @@ Reveal mode renders invisible text around point visible again.
 Interactively, with no prefix argument, toggle the mode.
 With universal prefix ARG (or if ARG is nil) turn mode on.
 With zero or negative ARG turn mode off."
-  :global t
+  :global t :group 'reveal
   (setq-default reveal-mode global-reveal-mode)
   (if global-reveal-mode
       (progn
@@ -158,4 +205,6 @@ With zero or negative ARG turn mode off."
     (remove-hook 'post-command-hook 'reveal-post-command)))
 
 (provide 'reveal)
+
+;; arch-tag: 96ba0242-2274-4ed7-8e10-26bc0707b4d8
 ;;; reveal.el ends here