(Fwhere_is_internal): Take just one keymap arg.
[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))
355 (forward-char -1)
356 (if (memq (preceding-char) '(?\n ?\^M))
357 (forward-char -1))))
358\f
359(defun show-branches ()
360 "Show all subheadings of this heading, but not their bodies."
361 (interactive)
362 (show-children 1000))
363
364(defun show-children (&optional level)
365 "Show all direct subheadings of this heading.
366Prefix arg LEVEL is how many levels below the current level should be shown.
367Default is enough to cause the following heading to appear."
368 (interactive "P")
369 (setq level
370 (if level (prefix-numeric-value level)
371 (save-excursion
372 (beginning-of-line)
476731da 373 (let ((start-level (funcall outline-level)))
26d1e4fd 374 (outline-next-heading)
babf687a
RS
375 (if (eobp)
376 1
377 (max 1 (- (funcall outline-level) start-level)))))))
26d1e4fd
BP
378 (save-excursion
379 (save-restriction
380 (beginning-of-line)
476731da 381 (setq level (+ level (funcall outline-level)))
26d1e4fd
BP
382 (narrow-to-region (point)
383 (progn (outline-end-of-subtree) (1+ (point))))
384 (goto-char (point-min))
385 (while (and (not (eobp))
386 (progn
387 (outline-next-heading)
388 (not (eobp))))
476731da 389 (if (<= (funcall outline-level) level)
26d1e4fd
BP
390 (save-excursion
391 (outline-flag-region (save-excursion
392 (forward-char -1)
393 (if (memq (preceding-char) '(?\n ?\^M))
394 (forward-char -1))
395 (point))
396 (progn (outline-end-of-heading) (point))
397 ?\n)))))))
398\f
399(defun outline-up-heading (arg)
400 "Move to the heading line of which the present line is a subheading.
401With argument, move up ARG levels."
402 (interactive "p")
403 (outline-back-to-heading)
476731da 404 (if (eq (funcall outline-level) 1)
26d1e4fd 405 (error ""))
476731da 406 (while (and (> (funcall outline-level) 1)
26d1e4fd
BP
407 (> arg 0)
408 (not (bobp)))
476731da
RS
409 (let ((present-level (funcall outline-level)))
410 (while (not (< (funcall outline-level) present-level))
26d1e4fd
BP
411 (outline-previous-visible-heading 1))
412 (setq arg (- arg 1)))))
413
414(defun outline-forward-same-level (arg)
415 "Move forward to the ARG'th subheading from here of the same level as the
416present one. It stops at the first and last subheadings of a superior heading."
417 (interactive "p")
418 (outline-back-to-heading)
419 (while (> arg 0)
420 (let ((point-to-move-to (save-excursion
421 (outline-get-next-sibling))))
422 (if point-to-move-to
423 (progn
424 (goto-char point-to-move-to)
425 (setq arg (1- arg)))
426 (progn
427 (setq arg 0)
428 (error ""))))))
429
430(defun outline-get-next-sibling ()
431 "Position the point at the next heading of the same level,
432and return that position or nil if it cannot be found."
476731da 433 (let ((level (funcall outline-level)))
26d1e4fd 434 (outline-next-visible-heading 1)
476731da 435 (while (and (> (funcall outline-level) level)
26d1e4fd
BP
436 (not (eobp)))
437 (outline-next-visible-heading 1))
476731da 438 (if (< (funcall outline-level) level)
26d1e4fd
BP
439 nil
440 (point))))
441
442(defun outline-backward-same-level (arg)
443 "Move backward to the ARG'th subheading from here of the same level as the
444present one. It stops at the first and last subheadings of a superior heading."
445 (interactive "p")
446 (outline-back-to-heading)
447 (while (> arg 0)
448 (let ((point-to-move-to (save-excursion
449 (outline-get-last-sibling))))
450 (if point-to-move-to
451 (progn
452 (goto-char point-to-move-to)
453 (setq arg (1- arg)))
454 (progn
455 (setq arg 0)
456 (error ""))))))
457
458(defun outline-get-last-sibling ()
459 "Position the point at the previous heading of the same level,
460and return that position or nil if it cannot be found."
476731da 461 (let ((level (funcall outline-level)))
26d1e4fd 462 (outline-previous-visible-heading 1)
476731da 463 (while (and (> (funcall outline-level) level)
26d1e4fd
BP
464 (not (bobp)))
465 (outline-previous-visible-heading 1))
476731da 466 (if (< (funcall outline-level) level)
26d1e4fd
BP
467 nil
468 (point))))
469
8f1e8ff0
RS
470(provide 'outline)
471
6594deb0 472;;; outline.el ends here