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