;;; outline.el --- outline mode commands for Emacs
-;; Copyright (C) 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+;; Copyright (C) 1986, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: outlines
;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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.
;;; Commentary:
;;; Code:
-;; Jan '86, Some new features added by Peter Desnoyers and rewritten by RMS.
-
-(defvar outline-regexp nil
+(defgroup outlines nil
+ "Support for hierarchical outlining"
+ :prefix "outline-"
+ :group 'editing)
+
+(defcustom outline-regexp nil
"*Regular expression to match the beginning of a heading.
Any line whose beginning matches this regexp is considered to start a heading.
The recommended way to set this is with a Local Variables: list
-in the file it applies to. See also outline-heading-end-regexp.")
+in the file it applies to. See also outline-heading-end-regexp."
+ :type '(choice regexp (const nil))
+ :group 'outlines)
;; Can't initialize this in the defvar above -- some major modes have
;; already assigned a local value to it.
(or (default-value 'outline-regexp)
(setq-default outline-regexp "[*\^L]+"))
-(defvar outline-heading-end-regexp "\n"
+(defcustom outline-heading-end-regexp "\n"
"*Regular expression to match the end of a heading line.
You can assume that point is at the beginning of a heading when this
regexp is searched for. The heading ends at the end of the match.
The recommended way to set this is with a `Local Variables:' list
-in the file it applies to.")
+in the file it applies to."
+ :type 'regexp
+ :group 'outlines)
(defvar outline-mode-prefix-map nil)
(if outline-mode-prefix-map
nil
(setq outline-mode-prefix-map (make-sparse-keymap))
+ (define-key outline-mode-prefix-map "@" 'outline-mark-subtree)
(define-key outline-mode-prefix-map "\C-n" 'outline-next-visible-heading)
(define-key outline-mode-prefix-map "\C-p" 'outline-previous-visible-heading)
(define-key outline-mode-prefix-map "\C-i" 'show-children)
(define-key outline-mode-map "\C-c" outline-mode-prefix-map)
(define-key outline-mode-map [menu-bar] outline-mode-menu-bar-map))
-(defvar outline-minor-mode nil
- "Non-nil if using Outline mode as a minor mode of some other mode.")
+(defcustom outline-minor-mode nil
+ "Non-nil if using Outline mode as a minor mode of some other mode."
+ :type 'boolean
+ :group 'outlines)
(make-variable-buffer-local 'outline-minor-mode)
-(put 'outline-minor-mode 'permanent-local t)
(or (assq 'outline-minor-mode minor-mode-alist)
(setq minor-mode-alist (append minor-mode-alist
(list '(outline-minor-mode " Outl")))))
(defvar outline-view-change-hook nil
"Normal hook to be run after outline visibility changes.")
-;;;autoload
+;;;###autoload
(defun outline-mode ()
"Set major mode for editing outlines with selective display.
Headings are lines which start with asterisks: one for major headings,
(make-local-variable 'line-move-ignore-invisible)
(setq line-move-ignore-invisible t)
;; Cause use of ellipses for invisible text.
- (setq buffer-invisibility-spec '((t . t)))
+ (add-to-invisibility-spec '(outline . t))
(make-local-variable 'paragraph-start)
(setq paragraph-start (concat paragraph-start "\\|\\("
outline-regexp "\\)"))
(add-hook 'change-major-mode-hook 'show-all)
(run-hooks 'text-mode-hook 'outline-mode-hook))
-(defvar outline-minor-mode-prefix "\C-c@"
+(defcustom outline-minor-mode-prefix "\C-c@"
"*Prefix key to use for Outline commands in Outline minor mode.
The value of this variable is checked as part of loading Outline mode.
-After that, changing the prefix key requires manipulating keymaps.")
+After that, changing the prefix key requires manipulating keymaps."
+ :type 'string
+ :group 'outlines)
(defvar outline-minor-mode-map nil)
(if outline-minor-mode-map
(cons (cons 'outline-minor-mode outline-minor-mode-map)
minor-mode-map-alist)))
-;;;autoload
+;;;###autoload
(defun outline-minor-mode (&optional arg)
"Toggle Outline minor mode.
With arg, turn Outline minor mode on if arg is positive, off otherwise.
(> (prefix-numeric-value arg) 0)))
(if outline-minor-mode
(progn
+ (make-local-hook 'change-major-mode-hook)
+ ;; Turn off this mode if we change major modes.
+ (add-hook 'change-major-mode-hook
+ '(lambda () (outline-minor-mode -1))
+ nil t)
(make-local-variable 'line-move-ignore-invisible)
(setq line-move-ignore-invisible t)
;; Cause use of ellipses for invisible text.
- (setq buffer-invisibility-spec '((t . t)))
+ (add-to-invisibility-spec '(outline . t))
(run-hooks 'outline-minor-mode-hook))
(setq line-move-ignore-invisible nil)
;; Cause use of ellipses for invisible text.
- (setq buffer-invisibility-spec t))
+ (remove-from-invisibility-spec '(outline . t)))
;; When turning off outline mode, get rid of any outline hiding.
(or outline-minor-mode
(show-all))
(force-mode-line-update))
\f
-(defvar outline-level 'outline-level
- "Function of no args to compute a header's nesting level in an outline.
-It can assume point is at the beginning of a header line.")
+(defcustom outline-level 'outline-level
+ "*Function of no args to compute a header's nesting level in an outline.
+It can assume point is at the beginning of a header line."
+ :type 'function
+ :group 'outlines)
;; This used to count columns rather than characters, but that made ^L
;; appear to be at level 2 instead of 1. Columns would be better for
(beginning-of-line)
(or (outline-on-heading-p)
(let (found)
- (while (not found)
- (setq found
- (and (re-search-backward (concat "^\\(" outline-regexp "\\)")
- nil t)
- (outline-visible))))
- found)
- (error "before first heading")))
+ (save-excursion
+ (while (not found)
+ (or (re-search-backward (concat "^\\(" outline-regexp "\\)")
+ nil t)
+ (error "before first heading"))
+ (setq found (and (outline-visible) (point)))))
+ (goto-char found)
+ found)))
(defun outline-on-heading-p ()
"Return t if point is on a (visible) heading line."
(interactive "p")
(outline-next-visible-heading (- arg)))
+(defun outline-mark-subtree ()
+ "Mark the current subtree in an outlined document.
+This puts point at the start of the current subtree, and mark at the end."
+ (interactive)
+ (let ((beg))
+ (if (outline-on-heading-p)
+ ;; we are already looking at a heading
+ (beginning-of-line)
+ ;; else go back to previous heading
+ (outline-previous-visible-heading 1))
+ (setq beg (point))
+ (outline-end-of-subtree)
+ (push-mark (point))
+ (goto-char beg)))
+\f
(defun outline-flag-region (from to flag)
"Hides or shows lines from FROM to TO, according to FLAG.
If FLAG is nil then text is shown, while if FLAG is t the text is hidden."
(outline-discard-overlays (point) to 'outline)
(if flag
(let ((o (make-overlay (point) to)))
- (overlay-put o 'invisible flag)
+ (overlay-put o 'invisible 'outline)
(overlay-put o 'outline t)))))
(run-hooks 'outline-view-change-hook))
(if (< end beg)
(setq beg (prog1 end (setq end beg))))
(save-excursion
- (goto-char beg)
- (while (< (point) end)
- (let ((overlays (overlays-at (point))))
- (while overlays
- (let ((o (car overlays)))
- (if (overlay-get o prop)
- ;; Either push this overlay outside beg...end
- ;; or split it to exclude beg...end
- ;; or delete it entirely (if it is contained in beg...end).
- (if (< (overlay-start o) beg)
- (if (> (overlay-end o) end)
- (let ((o1 (outline-copy-overlay o)))
- (move-overlay o1 (overlay-start o1) beg)
- (move-overlay o (overlay-start o) beg)))
- (if (> (overlay-end o) end)
- (move-overlay o end (overlay-end o))
- (delete-overlay o)))))
- (setq overlays (cdr overlays))))
- (goto-char (next-overlay-change (point))))))
+ (let ((overlays (overlays-in beg end))
+ o
+ o1)
+ (while overlays
+ (setq o (car overlays))
+ (if (overlay-get o prop)
+ ;; Either push this overlay outside beg...end
+ ;; or split it to exclude beg...end
+ ;; or delete it entirely (if it is contained in beg...end).
+ (if (< (overlay-start o) beg)
+ (if (> (overlay-end o) end)
+ (progn
+ (setq o1 (outline-copy-overlay o))
+ (move-overlay o1 (overlay-start o1) beg)
+ (move-overlay o end (overlay-end o)))
+ (move-overlay o (overlay-start o) beg))
+ (if (> (overlay-end o) end)
+ (move-overlay o end (overlay-end o))
+ (delete-overlay o))))
+ (setq overlays (cdr overlays))))))
;; Make a copy of overlay O, with the same beginning, end and properties.
(defun outline-copy-overlay (o)
(interactive "p")
(outline-back-to-heading)
(if (eq (funcall outline-level) 1)
- (error ""))
+ (error "Already at top level of the outline"))
(while (and (> (funcall outline-level) 1)
(> arg 0)
(not (bobp)))
(setq arg (1- arg)))
(progn
(setq arg 0)
- (error ""))))))
+ (error "No following same-level heading"))))))
(defun outline-get-next-sibling ()
"Move to next heading of the same level, and return point or nil if none."
(setq arg (1- arg)))
(progn
(setq arg 0)
- (error ""))))))
+ (error "No previous same-level heading"))))))
(defun outline-get-last-sibling ()
"Move to next heading of the same level, and return point or nil if none."