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