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