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