(generate-file-autoloads): Don't frob literal formfeeds into \f; just bind
[bpt/emacs.git] / lisp / textmodes / ooutline.el
CommitLineData
6594deb0
ER
1;;; outline.el --- outline mode commands for Emacs
2
476731da 3;; Copyright (C) 1986, 1993 Free Software Foundation, Inc.
26d1e4fd 4
9750e079
ER
5;; Maintainer: FSF
6
26d1e4fd
BP
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
e5167999 11;; the Free Software Foundation; either version 2, or (at your option)
26d1e4fd
BP
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to
21;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
edbd2f74
ER
23;;; Commentary:
24
25;; This package is a major mode for editing outline-format documents.
26;; An outline can be `abstracted' to show headers at any given level,
27;; with all stuff below hidden. See the Emacs manual for details.
28
e5167999
ER
29;;; Code:
30
26d1e4fd
BP
31;; Jan '86, Some new features added by Peter Desnoyers and rewritten by RMS.
32
33(defvar outline-regexp "[*\^l]+"
34 "*Regular expression to match the beginning of a heading.
35Any line whose beginning matches this regexp is considered to start a heading.
36The recommended way to set this is with a Local Variables: list
37in the file it applies to. See also outline-heading-end-regexp.")
38
8f1e8ff0 39(defvar outline-heading-end-regexp "[\n\^M]"
26d1e4fd
BP
40 "*Regular expression to match the end of a heading line.
41You can assume that point is at the beginning of a heading when this
42regexp is searched for. The heading ends at the end of the match.
43The recommended way to set this is with a \"Local Variables:\" list
44in the file it applies to.")
45
46(defvar outline-mode-map nil "")
47
48(if outline-mode-map
49 nil
50 (setq outline-mode-map (nconc (make-sparse-keymap) text-mode-map))
51 (define-key outline-mode-map "\C-c\C-n" 'outline-next-visible-heading)
52 (define-key outline-mode-map "\C-c\C-p" 'outline-previous-visible-heading)
53 (define-key outline-mode-map "\C-c\C-i" 'show-children)
54 (define-key outline-mode-map "\C-c\C-s" 'show-subtree)
384fc6ca 55 (define-key outline-mode-map "\C-c\C-d" 'hide-subtree)
26d1e4fd
BP
56 (define-key outline-mode-map "\C-c\C-u" 'outline-up-heading)
57 (define-key outline-mode-map "\C-c\C-f" 'outline-forward-same-level)
ee1a4f84
RS
58 (define-key outline-mode-map "\C-c\C-b" 'outline-backward-same-level)
59
60 (define-key outline-mode-map [menu-bar hide]
61 (cons "Hide" (make-sparse-keymap "Hide")))
62
63 (define-key outline-mode-map [menu-bar hide hide-subtree]
32e61280 64 '("Hide Subtree" . hide-subtree))
ee1a4f84 65 (define-key outline-mode-map [menu-bar hide hide-entry]
32e61280 66 '("Hide Entry" . hide-entry))
ee1a4f84 67 (define-key outline-mode-map [menu-bar hide hide-body]
32e61280 68 '("Hide Body" . hide-body))
ee1a4f84 69 (define-key outline-mode-map [menu-bar hide hide-leaves]
32e61280 70 '("Hide Leaves" . hide-leaves))
ee1a4f84
RS
71
72 (define-key outline-mode-map [menu-bar show]
73 (cons "Show" (make-sparse-keymap "Show")))
74
75 (define-key outline-mode-map [menu-bar show show-subtree]
32e61280 76 '("Show Subtree" . show-subtree))
ee1a4f84 77 (define-key outline-mode-map [menu-bar show show-children]
32e61280 78 '("Show Children" . show-children))
ee1a4f84 79 (define-key outline-mode-map [menu-bar show show-branches]
32e61280 80 '("Show Branches" . show-branches))
ee1a4f84 81 (define-key outline-mode-map [menu-bar show show-entry]
32e61280 82 '("Show Entry" . show-entry))
ee1a4f84 83 (define-key outline-mode-map [menu-bar show show-all]
32e61280 84 '("Show All" . show-all))
ee1a4f84
RS
85
86 (define-key outline-mode-map [menu-bar headings]
87 (cons "Headings" (make-sparse-keymap "Headings")))
88
89 (define-key outline-mode-map [menu-bar headings outline-backward-same-level]
90 '("Previous Same Level" . outline-backward-same-level))
91 (define-key outline-mode-map [menu-bar headings outline-forward-same-level]
92 '("Next Same Level" . outline-forward-same-level))
93 (define-key outline-mode-map [menu-bar headings outline-previous-visible-heading]
94 '("Previous" . outline-previous-visible-heading))
95 (define-key outline-mode-map [menu-bar headings outline-next-visible-heading]
96 '("Next" . outline-next-visible-heading))
97 (define-key outline-mode-map [menu-bar headings outline-up-heading]
98 '("Up" . outline-up-heading)))
26d1e4fd
BP
99
100(defvar outline-minor-mode nil
101 "Non-nil if using Outline mode as a minor mode of some other mode.")
326c43dc
RS
102(make-variable-buffer-local 'outline-minor-mode)
103(put 'outline-minor-mode 'permanent-local t)
8f22b9e0
RS
104(or (assq 'outline-minor-mode minor-mode-alist)
105 (setq minor-mode-alist (append minor-mode-alist
106 (list '(outline-minor-mode " Outl")))))
26d1e4fd 107
f9f9507e 108;;;###autoload
26d1e4fd
BP
109(defun outline-mode ()
110 "Set major mode for editing outlines with selective display.
111Headings are lines which start with asterisks: one for major headings,
112two for subheadings, etc. Lines not starting with asterisks are body lines.
113
114Body text or subheadings under a heading can be made temporarily
115invisible, or visible again. Invisible lines are attached to the end
116of the heading, so they move with it, if the line is killed and yanked
117back. A heading with text hidden under it is marked with an ellipsis (...).
118
119Commands:\\<outline-mode-map>
120\\[outline-next-visible-heading] outline-next-visible-heading move by visible headings
121\\[outline-previous-visible-heading] outline-previous-visible-heading
122\\[outline-forward-same-level] outline-forward-same-level similar but skip subheadings
123\\[outline-backward-same-level] outline-backward-same-level
124\\[outline-up-heading] outline-up-heading move from subheading to heading
125
126M-x hide-body make all text invisible (not headings).
127M-x show-all make everything in buffer visible.
128
129The remaining commands are used when point is on a heading line.
130They apply to some of the body or subheadings of that heading.
131\\[hide-subtree] hide-subtree make body and subheadings invisible.
132\\[show-subtree] show-subtree make body and subheadings visible.
133\\[show-children] show-children make direct subheadings visible.
134 No effect on body, or subheadings 2 or more levels down.
135 With arg N, affects subheadings N levels down.
136M-x hide-entry make immediately following body invisible.
137M-x show-entry make it visible.
138M-x hide-leaves make body under heading and under its subheadings invisible.
139 The subheadings remain visible.
140M-x show-branches make all subheadings at all levels visible.
141
142The variable `outline-regexp' can be changed to control what is a heading.
143A line is a heading if `outline-regexp' matches something at the
144beginning of the line. The longer the match, the deeper the level.
145
146Turning on outline mode calls the value of `text-mode-hook' and then of
147`outline-mode-hook', if they are non-nil."
148 (interactive)
149 (kill-all-local-variables)
150 (setq selective-display t)
151 (use-local-map outline-mode-map)
152 (setq mode-name "Outline")
153 (setq major-mode 'outline-mode)
154 (define-abbrev-table 'text-mode-abbrev-table ())
155 (setq local-abbrev-table text-mode-abbrev-table)
156 (set-syntax-table text-mode-syntax-table)
157 (make-local-variable 'paragraph-start)
158 (setq paragraph-start (concat paragraph-start "\\|^\\("
159 outline-regexp "\\)"))
160 ;; Inhibit auto-filling of header lines.
161 (make-local-variable 'auto-fill-inhibit-regexp)
162 (setq auto-fill-inhibit-regexp outline-regexp)
163 (make-local-variable 'paragraph-separate)
164 (setq paragraph-separate (concat paragraph-separate "\\|^\\("
165 outline-regexp "\\)"))
85111db5 166 (add-hooks 'change-major-mode-hook 'show-all)
26d1e4fd
BP
167 (run-hooks 'text-mode-hook 'outline-mode-hook))
168
6e301d24
RS
169(defvar outline-minor-mode-prefix "\C-c"
170 "*Prefix key to use for Outline commands in Outline minor mode.")
171
8f1e8ff0
RS
172(defvar outline-minor-mode-map nil)
173(if outline-minor-mode-map
174 nil
175 (setq outline-minor-mode-map (make-sparse-keymap))
ee1a4f84
RS
176 (define-key outline-minor-mode-map [menu-bar]
177 (lookup-key outline-mode-map [menu-bar]))
6e301d24 178 (define-key outline-minor-mode-map outline-minor-mode-prefix
8f1e8ff0
RS
179 (lookup-key outline-mode-map "\C-c")))
180
181(or (assq 'outline-minor-mode minor-mode-map-alist)
182 (setq minor-mode-map-alist
183 (cons (cons 'outline-minor-mode outline-minor-mode-map)
184 minor-mode-map-alist)))
185
34060080 186;;;###autoload
8f1e8ff0 187(defun outline-minor-mode (&optional arg)
326c43dc
RS
188 "Toggle Outline minor mode.
189With arg, turn Outline minor mode on if arg is positive, off otherwise.
190See the command `outline-mode' for more information on this mode."
26d1e4fd
BP
191 (interactive "P")
192 (setq outline-minor-mode
193 (if (null arg) (not outline-minor-mode)
194 (> (prefix-numeric-value arg) 0)))
195 (if outline-minor-mode
196 (progn
197 (setq selective-display t)
26d1e4fd 198 (run-hooks 'outline-minor-mode-hook))
671e87b3 199 (setq selective-display nil))
85111db5
RS
200 ;; When turning off outline mode, get rid of any ^M's.
201 (or outline-minor-mode
202 (outline-flag-region (point-min) (point-max) ?\n))
671e87b3 203 (set-buffer-modified-p (buffer-modified-p)))
26d1e4fd 204\f
476731da
RS
205(defvar outline-level 'outline-level
206 "Function of no args to compute a header's nesting level in an outline.
207It can assume point is at the beginning of a header line.")
208
26d1e4fd
BP
209(defun outline-level ()
210 "Return the depth to which a statement is nested in the outline.
211Point must be at the beginning of a header line. This is actually
212the column number of the end of what `outline-regexp matches'."
213 (save-excursion
214 (looking-at outline-regexp)
215 (save-excursion (goto-char (match-end 0)) (current-column))))
216
217(defun outline-next-preface ()
218 "Skip forward to just before the next heading line."
219 (if (re-search-forward (concat "[\n\^M]\\(" outline-regexp "\\)")
220 nil 'move)
221 (goto-char (match-beginning 0)))
222 (if (memq (preceding-char) '(?\n ?\^M))
223 (forward-char -1)))
224
225(defun outline-next-heading ()
226 "Move to the next (possibly invisible) heading line."
227 (interactive)
228 (if (re-search-forward (concat "[\n\^M]\\(" outline-regexp "\\)")
229 nil 'move)
230 (goto-char (1+ (match-beginning 0)))))
231
232(defun outline-back-to-heading ()
233 "Move to previous (possibly invisible) heading line,
234or to the beginning of this line if it is a heading line."
235 (beginning-of-line)
236 (or (outline-on-heading-p)
237 (re-search-backward (concat "^\\(" outline-regexp "\\)") nil 'move)))
238
239(defun outline-on-heading-p ()
240 "Return T if point is on a header line."
241 (save-excursion
242 (beginning-of-line)
243 (and (eq (preceding-char) ?\n)
244 (looking-at outline-regexp))))
245
246(defun outline-end-of-heading ()
247 (if (re-search-forward outline-heading-end-regexp nil 'move)
248 (forward-char -1)))
249
250(defun outline-next-visible-heading (arg)
251 "Move to the next visible heading line.
252With argument, repeats or can move backward if negative.
253A heading line is one that starts with a `*' (or that
254`outline-regexp' matches)."
255 (interactive "p")
256 (if (< arg 0)
257 (beginning-of-line)
258 (end-of-line))
259 (re-search-forward (concat "^\\(" outline-regexp "\\)") nil nil arg)
260 (beginning-of-line))
261
262(defun outline-previous-visible-heading (arg)
263 "Move to the previous heading line.
264With argument, repeats or can move forward if negative.
265A heading line is one that starts with a `*' (or that
266`outline-regexp' matches)."
267 (interactive "p")
268 (outline-next-visible-heading (- arg)))
269
270(defun outline-flag-region (from to flag)
271 "Hides or shows lines from FROM to TO, according to FLAG.
272If FLAG is `\\n' (newline character) then text is shown,
273while if FLAG is `\\^M' (control-M) the text is hidden."
05cf4426
RS
274 (let (buffer-read-only)
275 (subst-char-in-region from to
276 (if (= flag ?\n) ?\^M ?\n)
277 flag t)))
26d1e4fd
BP
278\f
279(defun hide-entry ()
280 "Hide the body directly following this heading."
281 (interactive)
282 (outline-back-to-heading)
283 (outline-end-of-heading)
284 (save-excursion
285 (outline-flag-region (point) (progn (outline-next-preface) (point)) ?\^M)))
286
287(defun show-entry ()
288 "Show the body directly following this heading."
289 (interactive)
290 (save-excursion
291 (outline-flag-region (point) (progn (outline-next-preface) (point)) ?\n)))
292
293(defun hide-body ()
294 "Hide all of buffer except headings."
295 (interactive)
296 (hide-region-body (point-min) (point-max)))
297
298(defun hide-region-body (start end)
299 "Hide all body lines in the region, but not headings."
300 (save-excursion
301 (save-restriction
302 (narrow-to-region start end)
303 (goto-char (point-min))
304 (if (outline-on-heading-p)
305 (outline-end-of-heading))
306 (while (not (eobp))
307 (outline-flag-region (point)
308 (progn (outline-next-preface) (point)) ?\^M)
309 (if (not (eobp))
310 (progn
311 (forward-char
312 (if (looking-at "[\n\^M][\n\^M]")
313 2 1))
314 (outline-end-of-heading)))))))
315
316(defun show-all ()
317 "Show all of the text in the buffer."
318 (interactive)
319 (outline-flag-region (point-min) (point-max) ?\n))
320
321(defun hide-subtree ()
322 "Hide everything after this heading at deeper levels."
323 (interactive)
324 (outline-flag-subtree ?\^M))
325
326(defun hide-leaves ()
327 "Hide all body after this heading at deeper levels."
328 (interactive)
329 (outline-back-to-heading)
330 (outline-end-of-heading)
331 (hide-region-body (point) (progn (outline-end-of-subtree) (point))))
332
333(defun show-subtree ()
334 "Show everything after this heading at deeper levels."
335 (interactive)
336 (outline-flag-subtree ?\n))
337
338(defun outline-flag-subtree (flag)
339 (save-excursion
340 (outline-back-to-heading)
341 (outline-end-of-heading)
342 (outline-flag-region (point)
343 (progn (outline-end-of-subtree) (point))
344 flag)))
345
346(defun outline-end-of-subtree ()
347 (outline-back-to-heading)
348 (let ((opoint (point))
349 (first t)
476731da 350 (level (funcall outline-level)))
26d1e4fd 351 (while (and (not (eobp))
476731da 352 (or first (> (funcall outline-level) level)))
26d1e4fd
BP
353 (setq first nil)
354 (outline-next-heading))
9d721a9e
RS
355 (if (eobp)
356 nil
357 ;; go to end of line before heading
358 (forward-char -1)
359 ;; skip preceding balnk line, if there is one
360 (if (memq (preceding-char) '(?\n ?\^M))
361 (forward-char -1)))))
26d1e4fd
BP
362\f
363(defun show-branches ()
364 "Show all subheadings of this heading, but not their bodies."
365 (interactive)
366 (show-children 1000))
367
368(defun show-children (&optional level)
369 "Show all direct subheadings of this heading.
370Prefix arg LEVEL is how many levels below the current level should be shown.
371Default is enough to cause the following heading to appear."
372 (interactive "P")
373 (setq level
374 (if level (prefix-numeric-value level)
375 (save-excursion
376 (beginning-of-line)
476731da 377 (let ((start-level (funcall outline-level)))
26d1e4fd 378 (outline-next-heading)
babf687a
RS
379 (if (eobp)
380 1
381 (max 1 (- (funcall outline-level) start-level)))))))
26d1e4fd
BP
382 (save-excursion
383 (save-restriction
384 (beginning-of-line)
476731da 385 (setq level (+ level (funcall outline-level)))
26d1e4fd
BP
386 (narrow-to-region (point)
387 (progn (outline-end-of-subtree) (1+ (point))))
388 (goto-char (point-min))
389 (while (and (not (eobp))
390 (progn
391 (outline-next-heading)
392 (not (eobp))))
476731da 393 (if (<= (funcall outline-level) level)
26d1e4fd
BP
394 (save-excursion
395 (outline-flag-region (save-excursion
396 (forward-char -1)
397 (if (memq (preceding-char) '(?\n ?\^M))
398 (forward-char -1))
399 (point))
400 (progn (outline-end-of-heading) (point))
401 ?\n)))))))
402\f
403(defun outline-up-heading (arg)
404 "Move to the heading line of which the present line is a subheading.
405With argument, move up ARG levels."
406 (interactive "p")
407 (outline-back-to-heading)
476731da 408 (if (eq (funcall outline-level) 1)
26d1e4fd 409 (error ""))
476731da 410 (while (and (> (funcall outline-level) 1)
26d1e4fd
BP
411 (> arg 0)
412 (not (bobp)))
476731da
RS
413 (let ((present-level (funcall outline-level)))
414 (while (not (< (funcall outline-level) present-level))
26d1e4fd
BP
415 (outline-previous-visible-heading 1))
416 (setq arg (- arg 1)))))
417
418(defun outline-forward-same-level (arg)
419 "Move forward to the ARG'th subheading from here of the same level as the
420present one. It stops at the first and last subheadings of a superior heading."
421 (interactive "p")
422 (outline-back-to-heading)
423 (while (> arg 0)
424 (let ((point-to-move-to (save-excursion
425 (outline-get-next-sibling))))
426 (if point-to-move-to
427 (progn
428 (goto-char point-to-move-to)
429 (setq arg (1- arg)))
430 (progn
431 (setq arg 0)
432 (error ""))))))
433
434(defun outline-get-next-sibling ()
435 "Position the point at the next heading of the same level,
436and return that position or nil if it cannot be found."
476731da 437 (let ((level (funcall outline-level)))
26d1e4fd 438 (outline-next-visible-heading 1)
476731da 439 (while (and (> (funcall outline-level) level)
26d1e4fd
BP
440 (not (eobp)))
441 (outline-next-visible-heading 1))
476731da 442 (if (< (funcall outline-level) level)
26d1e4fd
BP
443 nil
444 (point))))
445
446(defun outline-backward-same-level (arg)
447 "Move backward to the ARG'th subheading from here of the same level as the
448present one. It stops at the first and last subheadings of a superior heading."
449 (interactive "p")
450 (outline-back-to-heading)
451 (while (> arg 0)
452 (let ((point-to-move-to (save-excursion
453 (outline-get-last-sibling))))
454 (if point-to-move-to
455 (progn
456 (goto-char point-to-move-to)
457 (setq arg (1- arg)))
458 (progn
459 (setq arg 0)
460 (error ""))))))
461
462(defun outline-get-last-sibling ()
463 "Position the point at the previous heading of the same level,
464and return that position or nil if it cannot be found."
476731da 465 (let ((level (funcall outline-level)))
26d1e4fd 466 (outline-previous-visible-heading 1)
476731da 467 (while (and (> (funcall outline-level) level)
26d1e4fd
BP
468 (not (bobp)))
469 (outline-previous-visible-heading 1))
476731da 470 (if (< (funcall outline-level) level)
26d1e4fd
BP
471 nil
472 (point))))
473
8f1e8ff0
RS
474(provide 'outline)
475
6594deb0 476;;; outline.el ends here