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