(mail-setup-hook, mail-aliases)
[bpt/emacs.git] / lisp / allout.el
CommitLineData
6a05d05f 1;;; allout.el --- extensive outline mode for use alone and with other modes
19b84ba3 2
0d30b337
TTN
3;; Copyright (C) 1992, 1993, 1994, 2001, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
1977b8f6 5
42d03dd0
JB
6;; Author: Ken Manheimer <klm@zope.com>
7;; Maintainer: Ken Manheimer <klm@zope.com>
c567ac01 8;; Created: Dec 1991 - first release to usenet
660a1df5 9;; Keywords: outlines mode wp languages
1977b8f6
RS
10
11;; This file is part of GNU Emacs.
12
59243403
RS
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
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
1977b8f6 18;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
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
b578f267 24;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
1977b8f6 27
6a05d05f 28;;; Commentary:
19b84ba3
RS
29
30;; Allout outline mode provides extensive outline formatting and
9179616f
DL
31;; and manipulation beyond standard emacs outline mode. It provides
32;; for structured editing of outlines, as well as navigation and
33;; exposure. It also provides for syntax-sensitive text like
34;; programming languages. (For an example, see the allout code
35;; itself, which is organized in ;; an outline framework.)
71296446 36;;
9179616f 37;; In addition to outline navigation and exposure, allout includes:
71296446 38;;
9179616f
DL
39;; - topic-oriented repositioning, cut, and paste
40;; - integral outline exposure-layout
41;; - incremental search with dynamic exposure and reconcealment of hidden text
42;; - automatic topic-number maintenance
43;; - "Hot-spot" operation, for single-keystroke maneuvering and
fd5359c6 44;; exposure control. (See the `allout-mode' docstring.)
71296446 45;;
9179616f 46;; and many other features.
71296446 47;;
9179616f 48;; The outline menubar additions provide quick reference to many of
aad94676 49;; the features, and see the docstring of the function `allout-init'
e126900f 50;; for instructions on priming your Emacs session for automatic
fd5359c6 51;; activation of `allout-mode'.
71296446 52;;
fd5359c6
MR
53;; See the docstring of the variables `allout-layout' and
54;; `allout-auto-activation' for details on automatic activation of
55;; allout `allout-mode' as a minor mode. (It has changed since allout
19b84ba3 56;; 3.x, for those of you that depend on the old method.)
c567ac01 57;;
353e2ef2
KH
58;; Note - the lines beginning with `;;;_' are outline topic headers.
59;; Just `ESC-x eval-current-buffer' to give it a whirl.
19b84ba3 60
42d03dd0 61;; Ken Manheimer klm@zope.com
c567ac01 62
6a05d05f
PJ
63;;; Code:
64
19b84ba3 65;;;_* Provide
19b84ba3
RS
66(provide 'allout)
67
68;;;_* USER CUSTOMIZATION VARIABLES:
4bef9110
SE
69(defgroup allout nil
70 "Extensive outline mode for use alone and with other modes."
fd5359c6 71 :prefix "allout-"
65970d64 72 :group 'editing
bf247b6e 73 :version "22.1")
19b84ba3
RS
74
75;;;_ + Layout, Mode, and Topic Header Configuration
76
fd5359c6
MR
77;;;_ = allout-auto-activation
78(defcustom allout-auto-activation nil
79 "*Regulates auto-activation modality of allout outlines - see `allout-init'.
19b84ba3 80
fd5359c6 81Setq-default by `allout-init' to regulate whether or not allout
19b84ba3 82outline mode is automatically activated when the buffer-specific
fd5359c6
MR
83variable `allout-layout' is non-nil, and whether or not the layout
84dictated by `allout-layout' should be imposed on mode activation.
19b84ba3 85
24190da5 86With value t, auto-mode-activation and auto-layout are enabled.
aad94676 87\(This also depends on `allout-find-file-hook' being installed in
95c12694 88`find-file-hook', which is also done by `allout-init'.)
19b84ba3
RS
89
90With value `ask', auto-mode-activation is enabled, and endorsement for
91performing auto-layout is asked of the user each time.
92
71296446 93With value `activate', only auto-mode-activation is enabled,
353e2ef2 94auto-layout is not.
19b84ba3 95
24190da5 96With value nil, neither auto-mode-activation nor auto-layout are
19b84ba3
RS
97enabled.
98
fd5359c6 99See the docstring for `allout-init' for the proper interface to
9179616f
DL
100this variable."
101 :type '(choice (const :tag "On" t)
102 (const :tag "Ask about layout" "ask")
103 (const :tag "Mode only" "activate")
104 (const :tag "Off" nil))
105 :group 'allout)
fd5359c6
MR
106;;;_ = allout-layout
107(defvar allout-layout nil
19b84ba3 108 "*Layout specification and provisional mode trigger for allout outlines.
1977b8f6 109
19b84ba3
RS
110Buffer-specific.
111
112A list value specifies a default layout for the current buffer, to be
aad94676
MR
113applied upon activation of `allout-mode'. Any non-nil value will
114automatically trigger `allout-mode', provided `allout-init'
353e2ef2 115has been called to enable it.
19b84ba3 116
fd5359c6
MR
117See the docstring for `allout-init' for details on setting up for
118auto-mode-activation, and for `allout-expose-topic' for the format of
19b84ba3
RS
119the layout specification.
120
121You can associate a particular outline layout with a file by setting
122this var via the file's local variables. For example, the following
41e798a9 123lines at the bottom of an Emacs Lisp file:
19b84ba3
RS
124
125;;;Local variables:
fd5359c6 126;;;allout-layout: \(0 : -1 -1 0)
19b84ba3
RS
127;;;End:
128
129will, modulo the above-mentioned conditions, cause the mode to be
130activated when the file is visited, followed by the equivalent of
fd5359c6 131`\(allout-expose-topic 0 : -1 -1 0)'. \(This is the layout used for
19b84ba3
RS
132the allout.el, itself.)
133
353e2ef2
KH
134Also, allout's mode-specific provisions will make topic prefixes default
135to the comment-start string, if any, of the language of the file. This
fd5359c6
MR
136is modulo the setting of `allout-use-mode-specific-leader', which see.")
137(make-variable-buffer-local 'allout-layout)
138;;;_ = allout-show-bodies
139(defcustom allout-show-bodies nil
9179616f
DL
140 "*If non-nil, show entire body when exposing a topic, rather than
141just the header."
142 :type 'boolean
143 :group 'allout)
fd5359c6 144(make-variable-buffer-local 'allout-show-bodies)
1977b8f6 145
fd5359c6
MR
146;;;_ = allout-header-prefix
147(defcustom allout-header-prefix "."
19b84ba3
RS
148 "*Leading string which helps distinguish topic headers.
149
150Outline topic header lines are identified by a leading topic
c567ac01
RS
151header prefix, which mostly have the value of this var at their front.
152\(Level 1 topics are exceptions. They consist of only a single
2265e017 153character, which is typically set to the `allout-primary-bullet'. Many
4bef9110
SE
154outlines start at level 2 to avoid this discrepancy."
155 :type 'string
156 :group 'allout)
fd5359c6
MR
157(make-variable-buffer-local 'allout-header-prefix)
158;;;_ = allout-primary-bullet
159(defcustom allout-primary-bullet "*"
19b84ba3
RS
160 "Bullet used for top-level outline topics.
161
162Outline topic header lines are identified by a leading topic header
c567ac01 163prefix, which is concluded by bullets that includes the value of this
fd5359c6 164var and the respective allout-*-bullets-string vars.
c567ac01 165
353e2ef2 166The value of an asterisk (`*') provides for backwards compatibility
e126900f 167with the original Emacs outline mode. See `allout-plain-bullets-string'
2265e017 168and `allout-distinctive-bullets-string' for the range of available
4bef9110
SE
169bullets."
170 :type 'string
171 :group 'allout)
fd5359c6
MR
172(make-variable-buffer-local 'allout-primary-bullet)
173;;;_ = allout-plain-bullets-string
174(defcustom allout-plain-bullets-string ".:,;"
19b84ba3
RS
175 "*The bullets normally used in outline topic prefixes.
176
fd5359c6 177See `allout-distinctive-bullets-string' for the other kind of
c567ac01 178bullets.
1977b8f6 179
353e2ef2 180DO NOT include the close-square-bracket, `]', as a bullet.
1977b8f6 181
c567ac01 182Outline mode has to be reactivated in order for changes to the value
4bef9110
SE
183of this var to take effect."
184 :type 'string
185 :group 'allout)
fd5359c6
MR
186(make-variable-buffer-local 'allout-plain-bullets-string)
187;;;_ = allout-distinctive-bullets-string
188(defcustom allout-distinctive-bullets-string "*+-=>([{}&!?#%\"X@$~_\\"
19b84ba3 189 "*Persistent outline header bullets used to distinguish special topics.
1977b8f6 190
9179616f
DL
191These bullets are used to distinguish topics from the run-of-the-mill
192ones. They are not used in the standard topic headers created by
71296446 193the topic-opening, shifting, and rebulleting \(eg, on topic shift,
9179616f
DL
194topic paste, blanket rebulleting) routines, but are offered among the
195choices for rebulleting. They are not altered by the above automatic
196rebulleting, so they can be used to characterize topics, eg:
197
198 `?' question topics
199 `\(' parenthetic comment \(with a matching close paren inside)
200 `[' meta-note \(with a matching close ] inside)
201 `\"' a quote
202 `=' value settings
203 `~' \"more or less\"
204
205... just for example. (`#' typically has a special meaning to the
fd5359c6 206software, according to the value of `allout-numbered-bullet'.)
9179616f 207
fd5359c6 208See `allout-plain-bullets-string' for the selection of
9179616f 209alternating bullets.
1977b8f6 210
fd5359c6 211You must run `set-allout-regexp' in order for outline mode to
9179616f 212reconcile to changes of this value.
19b84ba3 213
353e2ef2 214DO NOT include the close-square-bracket, `]', on either of the bullet
4bef9110
SE
215strings."
216 :type 'string
217 :group 'allout)
fd5359c6 218(make-variable-buffer-local 'allout-distinctive-bullets-string)
1977b8f6 219
fd5359c6
MR
220;;;_ = allout-use-mode-specific-leader
221(defcustom allout-use-mode-specific-leader t
19b84ba3
RS
222 "*When non-nil, use mode-specific topic-header prefixes.
223
fd5359c6 224Allout outline mode will use the mode-specific `allout-mode-leaders'
19b84ba3 225and/or comment-start string, if any, to lead the topic prefix string,
353e2ef2 226so topic headers look like comments in the programming language.
19b84ba3
RS
227
228String values are used as they stand.
229
24190da5 230Value t means to first check for assoc value in `allout-mode-leaders'
19b84ba3 231alist, then use comment-start string, if any, then use default \(`.').
9179616f 232\(See note about use of comment-start strings, below.)
19b84ba3 233
fd5359c6 234Set to the symbol for either of `allout-mode-leaders' or
19b84ba3
RS
235`comment-start' to use only one of them, respectively.
236
24190da5 237Value nil means to always use the default \(`.').
19b84ba3
RS
238
239comment-start strings that do not end in spaces are tripled, and an
353e2ef2 240`_' underscore is tacked on the end, to distinguish them from regular
19b84ba3 241comment strings. comment-start strings that do end in spaces are not
9179616f 242tripled, but an underscore is substituted for the space. [This
19b84ba3 243presumes that the space is for appearance, not comment syntax. You
fd5359c6 244can use `allout-mode-leaders' to override this behavior, when
4bef9110 245incorrect.]"
71296446 246 :type '(choice (const t) (const nil) string
fd5359c6 247 (const allout-mode-leaders)
4bef9110
SE
248 (const comment-start))
249 :group 'allout)
fd5359c6
MR
250;;;_ = allout-mode-leaders
251(defvar allout-mode-leaders '()
252 "Specific allout-prefix leading strings per major modes.
19b84ba3 253
9179616f 254Entries will be used instead or in lieu of mode-specific
fd5359c6 255comment-start strings. See also `allout-use-mode-specific-leader'.
19b84ba3
RS
256
257If you're constructing a string that will comment-out outline
258structuring so it can be included in program code, append an extra
259character, like an \"_\" underscore, to distinguish the lead string
260from regular comments that start at bol.")
261
fd5359c6
MR
262;;;_ = allout-old-style-prefixes
263(defcustom allout-old-style-prefixes nil
aad94676 264 "*When non-nil, use only old-and-crusty `outline-mode' `*' topic prefixes.
19b84ba3
RS
265
266Non-nil restricts the topic creation and modification
c567ac01 267functions to asterix-padded prefixes, so they look exactly
e126900f 268like the original Emacs-outline style prefixes.
1977b8f6 269
c567ac01 270Whatever the setting of this variable, both old and new style prefixes
4bef9110
SE
271are always respected by the topic maneuvering functions."
272 :type 'boolean
273 :group 'allout)
fd5359c6
MR
274(make-variable-buffer-local 'allout-old-style-prefixes)
275;;;_ = allout-stylish-prefixes - alternating bullets
276(defcustom allout-stylish-prefixes t
19b84ba3 277 "*Do fancy stuff with topic prefix bullets according to level, etc.
c567ac01 278
19b84ba3
RS
279Non-nil enables topic creation, modification, and repositioning
280functions to vary the topic bullet char (the char that marks the topic
281depth) just preceding the start of the topic text) according to level.
353e2ef2 282Otherwise, only asterisks (`*') and distinctive bullets are used.
19b84ba3
RS
283
284This is how an outline can look (but sans indentation) with stylish
285prefixes:
c567ac01
RS
286
287 * Top level
288 .* A topic
289 . + One level 3 subtopic
290 . . One level 4 subtopic
19b84ba3 291 . . A second 4 subtopic
c567ac01 292 . + Another level 3 subtopic
19b84ba3
RS
293 . #1 A numbered level 4 subtopic
294 . #2 Another
295 . ! Another level 4 subtopic with a different distinctive bullet
296 . #4 And another numbered level 4 subtopic
c567ac01 297
19b84ba3
RS
298This would be an outline with stylish prefixes inhibited (but the
299numbered and other distinctive bullets retained):
c567ac01
RS
300
301 * Top level
302 .* A topic
19b84ba3
RS
303 . * One level 3 subtopic
304 . * One level 4 subtopic
305 . * A second 4 subtopic
306 . * Another level 3 subtopic
307 . #1 A numbered level 4 subtopic
308 . #2 Another
309 . ! Another level 4 subtopic with a different distinctive bullet
310 . #4 And another numbered level 4 subtopic
c567ac01
RS
311
312Stylish and constant prefixes (as well as old-style prefixes) are
313always respected by the topic maneuvering functions, regardless of
314this variable setting.
315
2265e017 316The setting of this var is not relevant when `allout-old-style-prefixes'
4bef9110
SE
317is non-nil."
318 :type 'boolean
319 :group 'allout)
fd5359c6 320(make-variable-buffer-local 'allout-stylish-prefixes)
1977b8f6 321
fd5359c6
MR
322;;;_ = allout-numbered-bullet
323(defcustom allout-numbered-bullet "#"
19b84ba3
RS
324 "*String designating bullet of topics that have auto-numbering; nil for none.
325
a0776d6b 326Topics having this bullet have automatic maintenance of a sibling
19b84ba3 327sequence-number tacked on, just after the bullet. Conventionally set
c567ac01 328to \"#\", you can set it to a bullet of your choice. A nil value
4bef9110
SE
329disables numbering maintenance."
330 :type '(choice (const nil) string)
331 :group 'allout)
fd5359c6
MR
332(make-variable-buffer-local 'allout-numbered-bullet)
333;;;_ = allout-file-xref-bullet
334(defcustom allout-file-xref-bullet "@"
335 "*Bullet signifying file cross-references, for `allout-resolve-xref'.
19b84ba3 336
9179616f 337Set this var to the bullet you want to use for file cross-references."
4bef9110
SE
338 :type '(choice (const nil) string)
339 :group 'allout)
c567ac01 340
fd5359c6
MR
341;;;_ = allout-presentation-padding
342(defcustom allout-presentation-padding 2
9179616f
DL
343 "*Presentation-format white-space padding factor, for greater indent."
344 :type 'integer
345 :group 'allout)
346
fd5359c6 347(make-variable-buffer-local 'allout-presentation-padding)
9179616f 348
fd5359c6
MR
349;;;_ = allout-abbreviate-flattened-numbering
350(defcustom allout-abbreviate-flattened-numbering nil
351 "*If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
9179616f
DL
352numbers to minimal amount with some context. Otherwise, entire
353numbers are always used."
354 :type 'boolean
355 :group 'allout)
356
c567ac01 357;;;_ + LaTeX formatting
fd5359c6
MR
358;;;_ - allout-number-pages
359(defcustom allout-number-pages nil
4bef9110
SE
360 "*Non-nil turns on page numbering for LaTeX formatting of an outline."
361 :type 'boolean
362 :group 'allout)
fd5359c6
MR
363;;;_ - allout-label-style
364(defcustom allout-label-style "\\large\\bf"
4bef9110
SE
365 "*Font and size of labels for LaTeX formatting of an outline."
366 :type 'string
367 :group 'allout)
fd5359c6
MR
368;;;_ - allout-head-line-style
369(defcustom allout-head-line-style "\\large\\sl "
4bef9110
SE
370 "*Font and size of entries for LaTeX formatting of an outline."
371 :type 'string
372 :group 'allout)
fd5359c6
MR
373;;;_ - allout-body-line-style
374(defcustom allout-body-line-style " "
4bef9110
SE
375 "*Font and size of entries for LaTeX formatting of an outline."
376 :type 'string
377 :group 'allout)
fd5359c6
MR
378;;;_ - allout-title-style
379(defcustom allout-title-style "\\Large\\bf"
4bef9110
SE
380 "*Font and size of titles for LaTeX formatting of an outline."
381 :type 'string
382 :group 'allout)
fd5359c6
MR
383;;;_ - allout-title
384(defcustom allout-title '(or buffer-file-name (current-buffer-name))
c567ac01 385 "*Expression to be evaluated to determine the title for LaTeX
4bef9110
SE
386formatted copy."
387 :type 'sexp
388 :group 'allout)
fd5359c6
MR
389;;;_ - allout-line-skip
390(defcustom allout-line-skip ".05cm"
4bef9110
SE
391 "*Space between lines for LaTeX formatting of an outline."
392 :type 'string
393 :group 'allout)
fd5359c6
MR
394;;;_ - allout-indent
395(defcustom allout-indent ".3cm"
4bef9110
SE
396 "*LaTeX formatted depth-indent spacing."
397 :type 'string
398 :group 'allout)
c567ac01
RS
399
400;;;_ + Miscellaneous customization
401
fd5359c6
MR
402;;;_ = allout-command-prefix
403(defcustom allout-command-prefix "\C-c"
9179616f
DL
404 "*Key sequence to be used as prefix for outline mode command key bindings."
405 :type 'string
406 :group 'allout)
407
fd5359c6
MR
408;;;_ = allout-keybindings-list
409;;; You have to reactivate allout-mode - `(allout-mode t)' - to
c567ac01 410;;; institute changes to this var.
fd5359c6 411(defvar allout-keybindings-list ()
2265e017 412 "*List of `allout-mode' key / function bindings, for `allout-mode-map'.
19b84ba3 413
2265e017 414String or vector key will be prefaced with `allout-command-prefix',
9179616f 415unless optional third, non-nil element is present.")
fd5359c6 416(setq allout-keybindings-list
1977b8f6
RS
417 '(
418 ; Motion commands:
fd5359c6
MR
419 ("\C-n" allout-next-visible-heading)
420 ("\C-p" allout-previous-visible-heading)
421 ("\C-u" allout-up-current-level)
422 ("\C-f" allout-forward-current-level)
423 ("\C-b" allout-backward-current-level)
424 ("\C-a" allout-beginning-of-current-entry)
425 ("\C-e" allout-end-of-current-entry)
1977b8f6 426 ; Exposure commands:
fd5359c6
MR
427 ("\C-i" allout-show-children)
428 ("\C-s" allout-show-current-subtree)
429 ("\C-h" allout-hide-current-subtree)
430 ("\C-o" allout-show-current-entry)
431 ("!" allout-show-all)
1977b8f6 432 ; Alteration commands:
fd5359c6
MR
433 (" " allout-open-sibtopic)
434 ("." allout-open-subtopic)
435 ("," allout-open-supertopic)
436 ("'" allout-shift-in)
437 (">" allout-shift-in)
438 ("<" allout-shift-out)
439 ("\C-m" allout-rebullet-topic)
440 ("*" allout-rebullet-current-heading)
441 ("#" allout-number-siblings)
442 ("\C-k" allout-kill-line t)
443 ("\C-y" allout-yank t)
444 ("\M-y" allout-yank-pop t)
445 ("\C-k" allout-kill-topic)
1977b8f6 446 ; Miscellaneous commands:
fd5359c6
MR
447 ;([?\C-\ ] allout-mark-topic)
448 ("@" allout-resolve-xref)
449 ("=c" allout-copy-exposed-to-buffer)
450 ("=i" allout-indented-exposed-to-buffer)
451 ("=t" allout-latexify-exposed)
452 ("=p" allout-flatten-exposed-to-buffer)))
453
454;;;_ = allout-isearch-dynamic-expose
455(defcustom allout-isearch-dynamic-expose t
9179616f
DL
456 "*Non-nil enable dynamic exposure of hidden incremental-search
457targets as they're encountered."
4bef9110
SE
458 :type 'boolean
459 :group 'allout)
fd5359c6 460(make-variable-buffer-local 'allout-isearch-dynamic-expose)
c567ac01 461
fd5359c6
MR
462;;;_ = allout-use-hanging-indents
463(defcustom allout-use-hanging-indents t
19b84ba3
RS
464 "*If non-nil, topic body text auto-indent defaults to indent of the header.
465Ie, it is indented to be just past the header prefix. This is
466relevant mostly for use with indented-text-mode, or other situations
467where auto-fill occurs.
c567ac01 468
353e2ef2 469\[This feature no longer depends in any way on the `filladapt.el'
4bef9110
SE
470lisp-archive package.\]"
471 :type 'boolean
472 :group 'allout)
fd5359c6 473(make-variable-buffer-local 'allout-use-hanging-indents)
c567ac01 474
fd5359c6
MR
475;;;_ = allout-reindent-bodies
476(defcustom allout-reindent-bodies (if allout-use-hanging-indents
8d118843 477 'text)
19b84ba3 478 "*Non-nil enables auto-adjust of topic body hanging indent with depth shifts.
1977b8f6 479
8d118843
RS
480When active, topic body lines that are indented even with or beyond
481their topic header are reindented to correspond with depth shifts of
482the header.
483
24190da5 484A value of t enables reindent in non-programming-code buffers, ie
8d118843 485those that do not have the variable `comment-start' set. A value of
4bef9110
SE
486`force' enables reindent whether or not `comment-start' is set."
487 :type '(choice (const nil) (const t) (const text) (const force))
488 :group 'allout)
8d118843 489
fd5359c6 490(make-variable-buffer-local 'allout-reindent-bodies)
c567ac01 491
fd5359c6
MR
492;;;_ = allout-inhibit-protection
493(defcustom allout-inhibit-protection nil
19b84ba3
RS
494 "*Non-nil disables warnings and confirmation-checks for concealed-text edits.
495
e126900f 496Outline mode uses Emacs change-triggered functions to detect unruly
19b84ba3
RS
497changes to concealed regions. Set this var non-nil to disable the
498protection, potentially increasing text-entry responsiveness a bit.
c567ac01 499
2265e017 500This var takes effect at `allout-mode' activation, so you may have to
19b84ba3 501deactivate and then reactivate the mode if you want to toggle the
4bef9110
SE
502behavior."
503 :type 'boolean
504 :group 'allout)
c567ac01 505
19b84ba3 506;;;_* CODE - no user customizations below.
c567ac01 507
9179616f
DL
508;;;_ #1 Internal Outline Formatting and Configuration
509;;;_ : Version
fd5359c6
MR
510;;;_ = allout-version
511(defvar allout-version
65970d64 512 (let ((rcs-rev "$Revision$"))
19b84ba3
RS
513 (condition-case err
514 (save-match-data
8d118843 515 (string-match "Revision: \\([0-9]+\\.[0-9]+\\)" rcs-rev)
19b84ba3 516 (substring rcs-rev (match-beginning 1) (match-end 1)))
9179616f 517 ('error rcs-rev)))
8d118843 518 "Revision number of currently loaded outline package. \(allout.el)")
fd5359c6
MR
519;;;_ > allout-version
520(defun allout-version (&optional here)
19b84ba3
RS
521 "Return string describing the loaded outline version."
522 (interactive "P")
fd5359c6 523 (let ((msg (concat "Allout Outline Mode v " allout-version)))
eac9cf5f 524 (if here (insert msg))
19b84ba3
RS
525 (message "%s" msg)
526 msg))
9179616f 527;;;_ : Topic header format
fd5359c6
MR
528;;;_ = allout-regexp
529(defvar allout-regexp ""
c567ac01 530 "*Regular expression to match the beginning of a heading line.
19b84ba3 531
c567ac01
RS
532Any line whose beginning matches this regexp is considered a
533heading. This var is set according to the user configuration vars
2265e017 534by `set-allout-regexp'.")
fd5359c6
MR
535(make-variable-buffer-local 'allout-regexp)
536;;;_ = allout-bullets-string
537(defvar allout-bullets-string ""
19b84ba3
RS
538 "A string dictating the valid set of outline topic bullets.
539
fd5359c6
MR
540This var should *not* be set by the user - it is set by `set-allout-regexp',
541and is produced from the elements of `allout-plain-bullets-string'
542and `allout-distinctive-bullets-string'.")
543(make-variable-buffer-local 'allout-bullets-string)
544;;;_ = allout-bullets-string-len
545(defvar allout-bullets-string-len 0
2265e017 546 "Length of current buffers' `allout-plain-bullets-string'.")
fd5359c6
MR
547(make-variable-buffer-local 'allout-bullets-string-len)
548;;;_ = allout-line-boundary-regexp
549(defvar allout-line-boundary-regexp ()
aad94676 550 "`allout-regexp' with outline style beginning-of-line anchor.
19b84ba3 551
a4e104bf 552\(Ie, C-j, *or* C-m, for prefixes of hidden topics). This is properly
2265e017 553set when `allout-regexp' is produced by `set-allout-regexp', so
c567ac01 554that (match-beginning 2) and (match-end 2) delimit the prefix.")
fd5359c6
MR
555(make-variable-buffer-local 'allout-line-boundary-regexp)
556;;;_ = allout-bob-regexp
557(defvar allout-bob-regexp ()
2265e017 558 "Like `allout-line-boundary-regexp', for headers at beginning of buffer.
9179616f 559\(match-beginning 2) and \(match-end 2) delimit the prefix.")
fd5359c6
MR
560(make-variable-buffer-local 'allout-bob-regexp)
561;;;_ = allout-header-subtraction
562(defvar allout-header-subtraction (1- (length allout-header-prefix))
563 "Allout-header prefix length to subtract when computing topic depth.")
564(make-variable-buffer-local 'allout-header-subtraction)
565;;;_ = allout-plain-bullets-string-len
566(defvar allout-plain-bullets-string-len (length allout-plain-bullets-string)
2265e017 567 "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.")
fd5359c6
MR
568(make-variable-buffer-local 'allout-plain-bullets-string-len)
569
570
571;;;_ X allout-reset-header-lead (header-lead)
572(defun allout-reset-header-lead (header-lead)
c567ac01 573 "*Reset the leading string used to identify topic headers."
1977b8f6 574 (interactive "sNew lead string: ")
fd5359c6
MR
575 (setq allout-header-prefix header-lead)
576 (setq allout-header-subtraction (1- (length allout-header-prefix)))
577 (set-allout-regexp))
578;;;_ X allout-lead-with-comment-string (header-lead)
579(defun allout-lead-with-comment-string (&optional header-lead)
19b84ba3
RS
580 "*Set the topic-header leading string to specified string.
581
582Useful when for encapsulating outline structure in programming
583language comments. Returns the leading string."
1977b8f6
RS
584
585 (interactive "P")
586 (if (not (stringp header-lead))
587 (setq header-lead (read-string
588 "String prefix for topic headers: ")))
fd5359c6
MR
589 (setq allout-reindent-bodies nil)
590 (allout-reset-header-lead header-lead)
1977b8f6 591 header-lead)
fd5359c6
MR
592;;;_ > allout-infer-header-lead ()
593(defun allout-infer-header-lead ()
594 "Determine appropriate `allout-header-prefix'.
19b84ba3
RS
595
596Works according to settings of:
597
8d118843 598 `comment-start'
fd5359c6
MR
599 `allout-header-prefix' (default)
600 `allout-use-mode-specific-leader'
601and `allout-mode-leaders'.
19b84ba3 602
fd5359c6 603Apply this via \(re)activation of `allout-mode', rather than
8d118843 604invoking it directly."
fd5359c6
MR
605 (let* ((use-leader (and (boundp 'allout-use-mode-specific-leader)
606 (if (or (stringp allout-use-mode-specific-leader)
607 (memq allout-use-mode-specific-leader
608 '(allout-mode-leaders
19b84ba3
RS
609 comment-start
610 t)))
fd5359c6 611 allout-use-mode-specific-leader
19b84ba3
RS
612 ;; Oops - garbled value, equate with effect of 't:
613 t)))
614 (leader
615 (cond
616 ((not use-leader) nil)
617 ;; Use the explicitly designated leader:
618 ((stringp use-leader) use-leader)
fd5359c6 619 (t (or (and (memq use-leader '(t allout-mode-leaders))
19b84ba3 620 ;; Get it from outline mode leaders?
fd5359c6
MR
621 (cdr (assq major-mode allout-mode-leaders)))
622 ;; ... didn't get from allout-mode-leaders...
19b84ba3
RS
623 (and (memq use-leader '(t comment-start))
624 comment-start
625 ;; Use comment-start, maybe tripled, and with
353e2ef2 626 ;; underscore:
19b84ba3
RS
627 (concat
628 (if (string= " "
629 (substring comment-start
630 (1- (length comment-start))))
631 ;; Use comment-start, sans trailing space:
632 (substring comment-start 0 -1)
633 (concat comment-start comment-start comment-start))
634 ;; ... and append underscore, whichever:
635 "_")))))))
636 (if (not leader)
637 nil
fd5359c6 638 (if (string= leader allout-header-prefix)
19b84ba3 639 nil ; no change, nothing to do.
fd5359c6
MR
640 (setq allout-header-prefix leader)
641 allout-header-prefix))))
642;;;_ > allout-infer-body-reindent ()
643(defun allout-infer-body-reindent ()
644 "Determine proper setting for `allout-reindent-bodies'.
8d118843 645
fd5359c6 646Depends on default setting of `allout-reindent-bodies' \(which see)
8d118843
RS
647and presence of setting for `comment-start', to tell whether the
648file is programming code."
fd5359c6 649 (if (and allout-reindent-bodies
8d118843 650 comment-start
fd5359c6
MR
651 (not (eq 'force allout-reindent-bodies)))
652 (setq allout-reindent-bodies nil)))
653;;;_ > set-allout-regexp ()
654(defun set-allout-regexp ()
19b84ba3
RS
655 "Generate proper topic-header regexp form for outline functions.
656
fd5359c6
MR
657Works with respect to `allout-plain-bullets-string' and
658`allout-distinctive-bullets-string'."
1977b8f6
RS
659
660 (interactive)
fd5359c6
MR
661 ;; Derive allout-bullets-string from user configured components:
662 (setq allout-bullets-string "")
663 (let ((strings (list 'allout-plain-bullets-string
664 'allout-distinctive-bullets-string
665 'allout-primary-bullet))
1977b8f6
RS
666 cur-string
667 cur-len
c567ac01 668 cur-char
1977b8f6
RS
669 cur-char-string
670 index
671 new-string)
672 (while strings
673 (setq new-string "") (setq index 0)
674 (setq cur-len (length (setq cur-string (symbol-value (car strings)))))
675 (while (< index cur-len)
676 (setq cur-char (aref cur-string index))
fd5359c6
MR
677 (setq allout-bullets-string
678 (concat allout-bullets-string
1977b8f6
RS
679 (cond
680 ; Single dash would denote a
681 ; sequence, repeated denotes
682 ; a dash:
683 ((eq cur-char ?-) "--")
684 ; literal close-square-bracket
685 ; doesn't work right in the
686 ; expr, exclude it:
687 ((eq cur-char ?\]) "")
688 (t (regexp-quote (char-to-string cur-char))))))
689 (setq index (1+ index)))
690 (setq strings (cdr strings)))
691 )
fd5359c6
MR
692 ;; Derive next for repeated use in allout-pending-bullet:
693 (setq allout-plain-bullets-string-len (length allout-plain-bullets-string))
694 (setq allout-header-subtraction (1- (length allout-header-prefix)))
695 ;; Produce the new allout-regexp:
696 (setq allout-regexp (concat "\\(\\"
697 allout-header-prefix
1977b8f6 698 "[ \t]*["
fd5359c6 699 allout-bullets-string
1977b8f6 700 "]\\)\\|\\"
fd5359c6 701 allout-primary-bullet
1977b8f6 702 "+\\|\^l"))
fd5359c6
MR
703 (setq allout-line-boundary-regexp
704 (concat "\\([\n\r]\\)\\(" allout-regexp "\\)"))
705 (setq allout-bob-regexp
706 (concat "\\(\\`\\)\\(" allout-regexp "\\)"))
1977b8f6 707 )
9179616f 708;;;_ : Key bindings
fd5359c6
MR
709;;;_ = allout-mode-map
710(defvar allout-mode-map nil "Keybindings for (allout) outline minor mode.")
711;;;_ > produce-allout-mode-map (keymap-alist &optional base-map)
712(defun produce-allout-mode-map (keymap-list &optional base-map)
e126900f 713 "Produce keymap for use as allout-mode-map, from KEYMAP-LIST.
19b84ba3
RS
714
715Built on top of optional BASE-MAP, or empty sparse map if none specified.
fd5359c6 716See doc string for allout-keybindings-list for format of binding list."
9179616f 717 (let ((map (or base-map (make-sparse-keymap)))
fd5359c6 718 (pref (list allout-command-prefix)))
9179616f
DL
719 (mapcar (function
720 (lambda (cell)
721 (let ((add-pref (null (cdr (cdr cell))))
722 (key-suff (list (car cell))))
723 (apply 'define-key
724 (list map
725 (apply 'concat (if add-pref
726 (append pref key-suff)
727 key-suff))
728 (car (cdr cell)))))))
19b84ba3
RS
729 keymap-list)
730 map))
95c12694 731
9179616f 732;;;_ : Menu bar
95c12694
RS
733(defvar allout-mode-exposure-menu)
734(defvar allout-mode-editing-menu)
735(defvar allout-mode-navigation-menu)
736(defvar allout-mode-misc-menu)
fd5359c6 737(defun produce-allout-mode-menubar-entries ()
9179616f 738 (require 'easymenu)
fd5359c6
MR
739 (easy-menu-define allout-mode-exposure-menu
740 allout-mode-map
9179616f
DL
741 "Allout outline exposure menu."
742 '("Exposure"
fd5359c6
MR
743 ["Show Entry" allout-show-current-entry t]
744 ["Show Children" allout-show-children t]
745 ["Show Subtree" allout-show-current-subtree t]
746 ["Hide Subtree" allout-hide-current-subtree t]
747 ["Hide Leaves" allout-hide-current-leaves t]
9179616f 748 "----"
fd5359c6
MR
749 ["Show All" allout-show-all t]))
750 (easy-menu-define allout-mode-editing-menu
751 allout-mode-map
9179616f
DL
752 "Allout outline editing menu."
753 '("Headings"
fd5359c6
MR
754 ["Open Sibling" allout-open-sibtopic t]
755 ["Open Subtopic" allout-open-subtopic t]
756 ["Open Supertopic" allout-open-supertopic t]
9179616f 757 "----"
fd5359c6
MR
758 ["Shift Topic In" allout-shift-in t]
759 ["Shift Topic Out" allout-shift-out t]
760 ["Rebullet Topic" allout-rebullet-topic t]
761 ["Rebullet Heading" allout-rebullet-current-heading t]
762 ["Number Siblings" allout-number-siblings t]))
763 (easy-menu-define allout-mode-navigation-menu
764 allout-mode-map
9179616f
DL
765 "Allout outline navigation menu."
766 '("Navigation"
fd5359c6 767 ["Next Visible Heading" allout-next-visible-heading t]
9179616f 768 ["Previous Visible Heading"
fd5359c6 769 allout-previous-visible-heading t]
9179616f 770 "----"
fd5359c6
MR
771 ["Up Level" allout-up-current-level t]
772 ["Forward Current Level" allout-forward-current-level t]
9179616f 773 ["Backward Current Level"
fd5359c6 774 allout-backward-current-level t]
9179616f
DL
775 "----"
776 ["Beginning of Entry"
fd5359c6
MR
777 allout-beginning-of-current-entry t]
778 ["End of Entry" allout-end-of-current-entry t]
779 ["End of Subtree" allout-end-of-current-subtree t]))
780 (easy-menu-define allout-mode-misc-menu
781 allout-mode-map
9179616f
DL
782 "Allout outlines miscellaneous bindings."
783 '("Misc"
fd5359c6 784 ["Version" allout-version t]
9179616f 785 "----"
fd5359c6 786 ["Duplicate Exposed" allout-copy-exposed-to-buffer t]
9179616f 787 ["Duplicate Exposed, numbered"
71296446 788 allout-flatten-exposed-to-buffer t]
9179616f 789 ["Duplicate Exposed, indented"
71296446 790 allout-indented-exposed-to-buffer t]
9179616f 791 "----"
fd5359c6
MR
792 ["Set Header Lead" allout-reset-header-lead t]
793 ["Set New Exposure" allout-expose-topic t])))
9179616f 794;;;_ : Mode-Specific Variable Maintenance Utilities
fd5359c6
MR
795;;;_ = allout-mode-prior-settings
796(defvar allout-mode-prior-settings nil
aad94676 797 "Internal `allout-mode' use; settings to be resumed on mode deactivation.")
fd5359c6
MR
798(make-variable-buffer-local 'allout-mode-prior-settings)
799;;;_ > allout-resumptions (name &optional value)
800(defun allout-resumptions (name &optional value)
1977b8f6 801
2265e017 802 "Registers or resumes settings over `allout-mode' activation/deactivation.
19b84ba3
RS
803
804First arg is NAME of variable affected. Optional second arg is list
fd5359c6 805containing allout-mode-specific VALUE to be imposed on named
19b84ba3
RS
806variable, and to be registered. (It's a list so you can specify
807registrations of null values.) If no value is specified, the
808registered value is returned (encapsulated in the list, so the caller
809can distinguish nil vs no value), and the registration is popped
c567ac01 810from the list."
1977b8f6 811
fd5359c6 812 (let ((on-list (assq name allout-mode-prior-settings))
353e2ef2 813 prior-capsule ; By `capsule' i mean a list
1977b8f6
RS
814 ; containing a value, so we can
815 ; distinguish nil from no value.
816 )
817
818 (if value
819
820 ;; Registering:
821 (progn
822 (if on-list
823 nil ; Already preserved prior value - don't mess with it.
824 ;; Register the old value, or nil if previously unbound:
fd5359c6 825 (setq allout-mode-prior-settings
1977b8f6
RS
826 (cons (list name
827 (if (boundp name) (list (symbol-value name))))
fd5359c6 828 allout-mode-prior-settings)))
c567ac01
RS
829 ; And impose the new value, locally:
830 (progn (make-local-variable name)
831 (set name (car value))))
1977b8f6
RS
832
833 ;; Relinquishing:
834 (if (not on-list)
835
836 ;; Oops, not registered - leave it be:
837 nil
838
839 ;; Some registration:
840 ; reestablish it:
841 (setq prior-capsule (car (cdr on-list)))
842 (if prior-capsule
843 (set name (car prior-capsule)) ; Some prior value - reestablish it.
844 (makunbound name)) ; Previously unbound - demolish var.
845 ; Remove registration:
846 (let (rebuild)
fd5359c6
MR
847 (while allout-mode-prior-settings
848 (if (not (eq (car allout-mode-prior-settings)
1977b8f6
RS
849 on-list))
850 (setq rebuild
fd5359c6 851 (cons (car allout-mode-prior-settings)
1977b8f6 852 rebuild)))
fd5359c6
MR
853 (setq allout-mode-prior-settings
854 (cdr allout-mode-prior-settings)))
855 (setq allout-mode-prior-settings rebuild)))))
1977b8f6 856 )
9179616f 857;;;_ : Mode-specific incidentals
fd5359c6
MR
858;;;_ = allout-during-write-cue nil
859(defvar allout-during-write-cue nil
19b84ba3 860 "Used to inhibit outline change-protection during file write.
c567ac01 861
fd5359c6
MR
862See also `allout-post-command-business', `allout-write-file-hook',
863`allout-before-change-protect', and `allout-post-command-business'
19b84ba3 864functions.")
fd5359c6
MR
865;;;_ = allout-pre-was-isearching nil
866(defvar allout-pre-was-isearching nil
9179616f 867 "Cue for isearch-dynamic-exposure mechanism, implemented in
fd5359c6
MR
868allout-pre- and -post-command-hooks.")
869(make-variable-buffer-local 'allout-pre-was-isearching)
870;;;_ = allout-isearch-prior-pos nil
871(defvar allout-isearch-prior-pos nil
539d7736 872 "Cue for isearch-dynamic-exposure tracking, used by `allout-isearch-expose'.")
fd5359c6 873(make-variable-buffer-local 'allout-isearch-prior-pos)
fd5359c6
MR
874;;;_ = allout-override-protect nil
875(defvar allout-override-protect nil
2265e017 876 "Used in `allout-mode' for regulate of concealed-text protection mechanism.
19b84ba3
RS
877
878Allout outline mode regulates alteration of concealed text to protect
a0776d6b 879against inadvertent, unnoticed changes. This is for use by specific,
19b84ba3
RS
880native outline functions to temporarily override that protection.
881It's automatically reset to nil after every buffer modification.")
fd5359c6
MR
882(make-variable-buffer-local 'allout-override-protect)
883;;;_ > allout-unprotected (expr)
539d7736
JB
884(defmacro allout-unprotected (expression)
885 "Evaluate EXPRESSION with `allout-override-protect' let-bound to t."
fd5359c6 886 `(let ((allout-override-protect t))
539d7736 887 ,expression))
fd5359c6
MR
888;;;_ = allout-undo-aggregation
889(defvar allout-undo-aggregation 30
c567ac01 890 "Amount of successive self-insert actions to bunch together per undo.
19b84ba3 891
c567ac01 892This is purely a kludge variable, regulating the compensation for a bug in
539d7736 893the way that `before-change-functions' and undo interact.")
fd5359c6 894(make-variable-buffer-local 'allout-undo-aggregation)
19b84ba3 895;;;_ = file-var-bug hack
fd5359c6 896(defvar allout-v18/19-file-var-hack nil
c567ac01 897 "Horrible hack used to prevent invalid multiple triggering of outline
2265e017 898mode from prop-line file-var activation. Used by `allout-mode' function
c567ac01 899to track repeats.")
fd5359c6
MR
900;;;_ > allout-write-file-hook ()
901(defun allout-write-file-hook ()
95c12694 902 "In `allout-mode', run as a `write-contents-functions' activity.
19b84ba3 903
aad94676 904Currently just sets `allout-during-write-cue', so outline change-protection
353e2ef2 905knows to keep inactive during file write."
fd5359c6 906 (setq allout-during-write-cue t)
19b84ba3
RS
907 nil)
908
909;;;_ #2 Mode activation
fd5359c6
MR
910;;;_ = allout-mode
911(defvar allout-mode () "Allout outline mode minor-mode flag.")
912(make-variable-buffer-local 'allout-mode)
913;;;_ > allout-mode-p ()
914(defmacro allout-mode-p ()
2265e017 915 "Return t if `allout-mode' is active in current buffer."
fd5359c6
MR
916 'allout-mode)
917;;;_ = allout-explicitly-deactivated
918(defvar allout-explicitly-deactivated nil
aad94676 919 "Non-nil if `allout-mode' was last deliberately deactivated.
2265e017 920So `allout-post-command-business' should not reactivate it...")
fd5359c6
MR
921(make-variable-buffer-local 'allout-explicitly-deactivated)
922;;;_ > allout-init (&optional mode)
aad94676 923;;;###autoload
fd5359c6 924(defun allout-init (&optional mode)
2265e017 925 "Prime `allout-mode' to enable/disable auto-activation, wrt `allout-layout'.
19b84ba3 926
8d118843 927MODE is one of the following symbols:
19b84ba3 928
353e2ef2
KH
929 - nil \(or no argument) deactivate auto-activation/layout;
930 - `activate', enable auto-activation only;
931 - `ask', enable auto-activation, and enable auto-layout but with
a0776d6b 932 confirmation for layout operation solicited from user each time;
353e2ef2 933 - `report', just report and return the current auto-activation state;
8d118843
RS
934 - anything else \(eg, t) for auto-activation and auto-layout, without
935 any confirmation check.
19b84ba3 936
e126900f 937Use this function to setup your Emacs session for automatic activation
19b84ba3 938of allout outline mode, contingent to the buffer-specific setting of
fd5359c6
MR
939the `allout-layout' variable. (See `allout-layout' and
940`allout-expose-topic' docstrings for more details on auto layout).
19b84ba3 941
aad94676 942`allout-init' works by setting up (or removing)
95c12694 943`allout-find-file-hook' in `find-file-hook', and giving
aad94676 944`allout-auto-activation' a suitable setting.
19b84ba3 945
e126900f
JB
946To prime your Emacs session for full auto-outline operation, include
947the following two lines in your Emacs init file:
19b84ba3
RS
948
949\(require 'allout)
fd5359c6 950\(allout-init t)"
19b84ba3 951
65970d64
RS
952 (interactive
953 (let ((m (completing-read
954 (concat "Select outline auto setup mode "
955 "(empty for report, ? for options) ")
956 '(("nil")("full")("activate")("deactivate")
957 ("ask") ("report") (""))
958 nil
959 t)))
960 (if (string= m "") 'report
961 (intern-soft m))))
8d118843
RS
962 (let
963 ;; convenience aliases, for consistent ref to respective vars:
fd5359c6
MR
964 ((hook 'allout-find-file-hook)
965 (curr-mode 'allout-auto-activation))
353e2ef2 966
8d118843 967 (cond ((not mode)
95c12694 968 (setq find-file-hook (delq hook find-file-hook))
8d118843
RS
969 (if (interactive-p)
970 (message "Allout outline mode auto-activation inhibited.")))
971 ((eq mode 'report)
95c12694 972 (if (memq hook find-file-hook)
9471aeec
MR
973 ;; Just punt and use the reports from each of the modes:
974 (allout-init (symbol-value curr-mode))
975 (allout-init nil)
976 (message "Allout outline mode auto-activation inhibited.")))
95c12694 977 (t (add-hook 'find-file-hook hook)
353e2ef2 978 (set curr-mode ; `set', not `setq'!
8d118843
RS
979 (cond ((eq mode 'activate)
980 (message
981 "Outline mode auto-activation enabled.")
982 'activate)
983 ((eq mode 'report)
984 ;; Return the current mode setting:
fd5359c6 985 (allout-init mode))
8d118843
RS
986 ((eq mode 'ask)
987 (message
988 (concat "Outline mode auto-activation and "
989 "-layout \(upon confirmation) enabled."))
990 'ask)
991 ((message
992 "Outline mode auto-activation and -layout enabled.")
993 'full)))))))
71296446 994
fd5359c6
MR
995;;;_ > allout-setup-menubar ()
996(defun allout-setup-menubar ()
aad94676 997 "Populate the current buffer's menubar with `allout-mode' stuff."
fd5359c6
MR
998 (let ((menus (list allout-mode-exposure-menu
999 allout-mode-editing-menu
1000 allout-mode-navigation-menu
1001 allout-mode-misc-menu))
9179616f
DL
1002 cur)
1003 (while menus
1004 (setq cur (car menus)
1005 menus (cdr menus))
1006 (easy-menu-add cur))))
fd5359c6 1007;;;_ > allout-mode (&optional toggle)
19b84ba3 1008;;;_ : Defun:
fd5359c6 1009(defun allout-mode (&optional toggle)
c567ac01 1010;;;_ . Doc string:
19b84ba3
RS
1011 "Toggle minor mode for controlling exposure and editing of text outlines.
1012
9179616f
DL
1013Optional arg forces mode to re-initialize iff arg is positive num or
1014symbol. Allout outline mode always runs as a minor mode.
19b84ba3 1015
aad94676 1016Allout outline mode provides extensive outline oriented formatting and
9179616f
DL
1017manipulation. It enables structural editing of outlines, as well as
1018navigation and exposure. It also is specifically aimed at
1019accommodating syntax-sensitive text like programming languages. \(For
1020an example, see the allout code itself, which is organized as an allout
1021outline.)
19b84ba3 1022
9179616f 1023In addition to outline navigation and exposure, allout includes:
19b84ba3 1024
9179616f
DL
1025 - topic-oriented repositioning, cut, and paste
1026 - integral outline exposure-layout
1027 - incremental search with dynamic exposure and reconcealment of hidden text
1028 - automatic topic-number maintenance
1029 - \"Hot-spot\" operation, for single-keystroke maneuvering and
fd5359c6 1030 exposure control. \(See the allout-mode docstring.)
9179616f
DL
1031
1032and many other features.
19b84ba3
RS
1033
1034Below is a description of the bindings, and then explanation of
2265e017 1035special `allout-mode' features and terminology. See also the outline
9179616f 1036menubar additions for quick reference to many of the features, and see
f134d28b 1037the docstring of the function `allout-init' for instructions on
e126900f 1038priming your Emacs session for automatic activation of `allout-mode'.
9179616f 1039
19b84ba3 1040
fd5359c6
MR
1041The bindings are dictated by the `allout-keybindings-list' and
1042`allout-command-prefix' variables.
19b84ba3
RS
1043
1044 Navigation: Exposure Control:
1045 ---------- ----------------
fd5359c6
MR
1046C-c C-n allout-next-visible-heading | C-c C-h allout-hide-current-subtree
1047C-c C-p allout-previous-visible-heading | C-c C-i allout-show-children
1048C-c C-u allout-up-current-level | C-c C-s allout-show-current-subtree
1049C-c C-f allout-forward-current-level | C-c C-o allout-show-current-entry
1050C-c C-b allout-backward-current-level | ^U C-c C-s allout-show-all
1051C-c C-e allout-end-of-current-entry | allout-hide-current-leaves
1052C-c C-a allout-beginning-of-current-entry, alternately, goes to hot-spot
19b84ba3
RS
1053
1054 Topic Header Production:
1055 -----------------------
fd5359c6
MR
1056C-c<SP> allout-open-sibtopic Create a new sibling after current topic.
1057C-c . allout-open-subtopic ... an offspring of current topic.
1058C-c , allout-open-supertopic ... a sibling of the current topic's parent.
19b84ba3
RS
1059
1060 Topic Level and Prefix Adjustment:
1061 ---------------------------------
fd5359c6
MR
1062C-c > allout-shift-in Shift current topic and all offspring deeper.
1063C-c < allout-shift-out ... less deep.
1064C-c<CR> allout-rebullet-topic Reconcile bullets of topic and its offspring
19b84ba3
RS
1065 - distinctive bullets are not changed, others
1066 alternated according to nesting depth.
b5ea1dfd 1067C-c * allout-rebullet-current-heading Prompt for alternate bullet for
19b84ba3 1068 current topic.
fd5359c6 1069C-c # allout-number-siblings Number bullets of topic and siblings - the
1977b8f6
RS
1070 offspring are not affected. With repeat
1071 count, revoke numbering.
1072
19b84ba3
RS
1073 Topic-oriented Killing and Yanking:
1074 ----------------------------------
fd5359c6
MR
1075C-c C-k allout-kill-topic Kill current topic, including offspring.
1076C-k allout-kill-line Like kill-line, but reconciles numbering, etc.
1077C-y allout-yank Yank, adjusting depth of yanked topic to
1977b8f6 1078 depth of heading if yanking into bare topic
19b84ba3 1079 heading (ie, prefix sans text).
fd5359c6 1080M-y allout-yank-pop Is to allout-yank as yank-pop is to yank
1977b8f6 1081
19b84ba3
RS
1082 Misc commands:
1083 -------------
19b84ba3
RS
1084M-x outlineify-sticky Activate outline mode for current buffer,
1085 and establish a default file-var setting
fd5359c6
MR
1086 for `allout-layout'.
1087C-c C-SPC allout-mark-topic
1088C-c = c allout-copy-exposed-to-buffer
9179616f
DL
1089 Duplicate outline, sans concealed text, to
1090 buffer with name derived from derived from
1091 that of current buffer - \"*XXX exposed*\".
fd5359c6 1092C-c = p allout-flatten-exposed-to-buffer
9179616f
DL
1093 Like above 'copy-exposed', but convert topic
1094 prefixes to section.subsection... numeric
1095 format.
e126900f 1096ESC ESC (allout-init t) Setup Emacs session for outline mode
19b84ba3 1097 auto-activation.
1977b8f6 1098
19b84ba3 1099 HOT-SPOT Operation
c567ac01 1100
19b84ba3
RS
1101Hot-spot operation provides a means for easy, single-keystroke outline
1102navigation and exposure control.
c567ac01 1103
fd5359c6 1104\\<allout-mode-map>
19b84ba3
RS
1105When the text cursor is positioned directly on the bullet character of
1106a topic, regular characters (a to z) invoke the commands of the
fd5359c6 1107corresponding allout-mode keymap control chars. For example, \"f\"
19b84ba3 1108would invoke the command typically bound to \"C-c C-f\"
fd5359c6 1109\(\\[allout-forward-current-level] `allout-forward-current-level').
19b84ba3
RS
1110
1111Thus, by positioning the cursor on a topic bullet, you can execute
c567ac01 1112the outline navigation and manipulation commands with a single
19b84ba3
RS
1113keystroke. Non-literal chars never get this special translation, so
1114you can use them to get away from the hot-spot, and back to normal
1115operation.
c567ac01 1116
fd5359c6 1117Note that the command `allout-beginning-of-current-entry' \(\\[allout-beginning-of-current-entry]\)
c567ac01 1118will move to the hot-spot when the cursor is already located at the
fd5359c6 1119beginning of the current entry, so you can simply hit \\[allout-beginning-of-current-entry]
c567ac01 1120twice in a row to get to the hot-spot.
1977b8f6 1121
19b84ba3 1122 Terminology
1977b8f6 1123
c567ac01
RS
1124Topic hierarchy constituents - TOPICS and SUBTOPICS:
1125
e126900f 1126TOPIC: A basic, coherent component of an Emacs outline. It can
c567ac01
RS
1127 contain other topics, and it can be subsumed by other topics,
1128CURRENT topic:
1129 The visible topic most immediately containing the cursor.
19b84ba3
RS
1130DEPTH: The degree of nesting of a topic; it increases with
1131 containment. Also called the:
c567ac01
RS
1132LEVEL: The same as DEPTH.
1133
1134ANCESTORS:
1135 The topics that contain a topic.
1136PARENT: A topic's immediate ancestor. It has a depth one less than
1137 the topic.
1138OFFSPRING:
19b84ba3
RS
1139 The topics contained by a topic;
1140SUBTOPIC:
1141 An immediate offspring of a topic;
c567ac01
RS
1142CHILDREN:
1143 The immediate offspring of a topic.
1144SIBLINGS:
19b84ba3 1145 Topics having the same parent and depth.
353e2ef2 1146
c567ac01
RS
1147Topic text constituents:
1148
1149HEADER: The first line of a topic, include the topic PREFIX and header
353e2ef2 1150 text.
8ff67d13 1151PREFIX: The leading text of a topic which distinguishes it from
c567ac01
RS
1152 normal text. It has a strict form, which consists of a
1153 prefix-lead string, padding, and a bullet. The bullet may be
1154 followed by a number, indicating the ordinal number of the
1155 topic among its siblings, a space, and then the header text.
1156
1157 The relative length of the PREFIX determines the nesting depth
1158 of the topic.
1159PREFIX-LEAD:
353e2ef2 1160 The string at the beginning of a topic prefix, normally a `.'.
c567ac01 1161 It can be customized by changing the setting of
2265e017 1162 `allout-header-prefix' and then reinitializing `allout-mode'.
c567ac01
RS
1163
1164 By setting the prefix-lead to the comment-string of a
aad94676 1165 programming language, you can embed outline structuring in
c567ac01 1166 program code without interfering with the language processing
fd5359c6 1167 of that code. See `allout-use-mode-specific-leader'
19b84ba3 1168 docstring for more detail.
c567ac01
RS
1169PREFIX-PADDING:
1170 Spaces or asterisks which separate the prefix-lead and the
1171 bullet, according to the depth of the topic.
1172BULLET: A character at the end of the topic prefix, it must be one of
fd5359c6
MR
1173 the characters listed on `allout-plain-bullets-string' or
1174 `allout-distinctive-bullets-string'. (See the documentation
c567ac01
RS
1175 for these variables for more details.) The default choice of
1176 bullet when generating varies in a cycle with the depth of the
1177 topic.
1178ENTRY: The text contained in a topic before any offspring.
1179BODY: Same as ENTRY.
1180
1181
1182EXPOSURE:
1183 The state of a topic which determines the on-screen visibility
353e2ef2 1184 of its offspring and contained text.
c567ac01
RS
1185CONCEALED:
1186 Topics and entry text whose display is inhibited. Contiguous
353e2ef2
KH
1187 units of concealed text is represented by `...' ellipses.
1188 (Ref the `selective-display' var.)
c567ac01
RS
1189
1190 Concealed topics are effectively collapsed within an ancestor.
1191CLOSED: A topic whose immediate offspring and body-text is concealed.
353e2ef2 1192OPEN: A topic that is not closed, though its offspring or body may be."
c567ac01 1193;;;_ . Code
1977b8f6
RS
1194 (interactive "P")
1195
c567ac01 1196 (let* ((active (and (not (equal major-mode 'outline))
fd5359c6 1197 (allout-mode-p)))
353e2ef2 1198 ; Massage universal-arg `toggle' val:
c567ac01 1199 (toggle (and toggle
19b84ba3
RS
1200 (or (and (listp toggle)(car toggle))
1201 toggle)))
a0776d6b 1202 ; Activation specifically demanded?
c567ac01 1203 (explicit-activation (or
19b84ba3
RS
1204 ;;
1205 (and toggle
1206 (or (symbolp toggle)
1207 (and (natnump toggle)
1208 (not (zerop toggle)))))))
fd5359c6
MR
1209 ;; allout-mode already called once during this complex command?
1210 (same-complex-command (eq allout-v18/19-file-var-hack
19b84ba3
RS
1211 (car command-history)))
1212 do-layout
1213 )
c567ac01 1214
19b84ba3 1215 ; See comments below re v19.18,.19 bug.
fd5359c6 1216 (setq allout-v18/19-file-var-hack (car command-history))
c567ac01 1217
1977b8f6
RS
1218 (cond
1219
19b84ba3 1220 ;; Provision for v19.18, 19.19 bug -
c567ac01
RS
1221 ;; Emacs v 19.18, 19.19 file-var code invokes prop-line-designated
1222 ;; modes twice when file is visited. We have to avoid toggling mode
1223 ;; off on second invocation, so we detect it as best we can, and
1224 ;; skip everything.
1225 ((and same-complex-command ; Still in same complex command
aad94676 1226 ; as last time `allout-mode' invoked.
19b84ba3
RS
1227 active ; Already activated.
1228 (not explicit-activation) ; Prop-line file-vars don't have args.
1229 (string-match "^19.1[89]" ; Bug only known to be in v19.18 and
1230 emacs-version)); 19.19.
c567ac01 1231 t)
353e2ef2 1232
19b84ba3 1233 ;; Deactivation:
c567ac01 1234 ((and (not explicit-activation)
19b84ba3
RS
1235 (or active toggle))
1236 ; Activation not explicitly
1237 ; requested, and either in
1238 ; active state or *de*activation
1239 ; specifically requested:
fd5359c6 1240 (setq allout-explicitly-deactivated t)
c567ac01 1241
fd5359c6 1242 (if allout-old-style-prefixes
c567ac01 1243 (progn
fd5359c6
MR
1244 (allout-resumptions 'allout-primary-bullet)
1245 (allout-resumptions 'allout-old-style-prefixes)))
1246 (allout-resumptions 'selective-display)
9179616f 1247 (if (and (boundp 'before-change-functions) before-change-functions)
fd5359c6 1248 (allout-resumptions 'before-change-functions))
95c12694
RS
1249 (setq write-contents-functions
1250 (delq 'allout-write-file-hook
1251 write-contents-functions))
fd5359c6
MR
1252 (allout-resumptions 'paragraph-start)
1253 (allout-resumptions 'paragraph-separate)
1254 (allout-resumptions (if (string-match "^18" emacs-version)
19b84ba3
RS
1255 'auto-fill-hook
1256 'auto-fill-function))
fd5359c6
MR
1257 (allout-resumptions 'allout-former-auto-filler)
1258 (setq allout-mode nil))
1977b8f6 1259
19b84ba3 1260 ;; Activation:
1977b8f6 1261 ((not active)
fd5359c6
MR
1262 (setq allout-explicitly-deactivated nil)
1263 (if allout-old-style-prefixes
c567ac01 1264 (progn ; Inhibit all the fancy formatting:
fd5359c6
MR
1265 (allout-resumptions 'allout-primary-bullet '("*"))
1266 (allout-resumptions 'allout-old-style-prefixes '(()))))
19b84ba3 1267
fd5359c6
MR
1268 (allout-infer-header-lead)
1269 (allout-infer-body-reindent)
19b84ba3 1270
fd5359c6 1271 (set-allout-regexp)
19b84ba3
RS
1272
1273 ; Produce map from current version
fd5359c6 1274 ; of allout-keybindings-list:
c567ac01
RS
1275 (if (boundp 'minor-mode-map-alist)
1276
1277 (progn ; V19, and maybe lucid and
19b84ba3 1278 ; epoch, minor-mode key bindings:
fd5359c6
MR
1279 (setq allout-mode-map
1280 (produce-allout-mode-map allout-keybindings-list))
1281 (produce-allout-mode-menubar-entries)
1282 (fset 'allout-mode-map allout-mode-map)
19b84ba3
RS
1283 ; Include on minor-mode-map-alist,
1284 ; if not already there:
fd5359c6 1285 (if (not (member '(allout-mode . allout-mode-map)
19b84ba3
RS
1286 minor-mode-map-alist))
1287 (setq minor-mode-map-alist
fd5359c6 1288 (cons '(allout-mode . allout-mode-map)
19b84ba3
RS
1289 minor-mode-map-alist))))
1290
19b84ba3 1291 ; and add them:
fd5359c6 1292 (use-local-map (produce-allout-mode-map allout-keybindings-list
19b84ba3 1293 (current-local-map)))
c567ac01 1294 )
353e2ef2 1295
19b84ba3 1296 ; selective-display is the
e126900f 1297 ; Emacs conditional exposure
19b84ba3 1298 ; mechanism:
fd5359c6
MR
1299 (allout-resumptions 'selective-display '(t))
1300 (if allout-inhibit-protection
c567ac01 1301 t
fd5359c6
MR
1302 (allout-resumptions 'before-change-functions
1303 '(allout-before-change-protect)))
1304 (add-hook 'pre-command-hook 'allout-pre-command-business)
1305 (add-hook 'post-command-hook 'allout-post-command-business)
19b84ba3
RS
1306 ; Temporarily set by any outline
1307 ; functions that can be trusted to
1308 ; deal properly with concealed text.
95c12694 1309 (add-hook 'write-contents-functions 'allout-write-file-hook)
19b84ba3
RS
1310 ; Custom auto-fill func, to support
1311 ; respect for topic headline,
1312 ; hanging-indents, etc:
c567ac01 1313 (let* ((fill-func-var (if (string-match "^18" emacs-version)
19b84ba3
RS
1314 'auto-fill-hook
1315 'auto-fill-function))
1316 (fill-func (symbol-value fill-func-var)))
fd5359c6
MR
1317 ;; Register prevailing fill func for use by allout-auto-fill:
1318 (allout-resumptions 'allout-former-auto-filler (list fill-func))
1319 ;; Register allout-auto-fill to be used if filling is active:
1320 (allout-resumptions fill-func-var '(allout-auto-fill)))
c567ac01 1321 ;; Paragraphs are broken by topic headlines.
1977b8f6 1322 (make-local-variable 'paragraph-start)
fd5359c6 1323 (allout-resumptions 'paragraph-start
9179616f 1324 (list (concat paragraph-start "\\|^\\("
fd5359c6 1325 allout-regexp "\\)")))
1977b8f6 1326 (make-local-variable 'paragraph-separate)
fd5359c6 1327 (allout-resumptions 'paragraph-separate
9179616f 1328 (list (concat paragraph-separate "\\|^\\("
fd5359c6 1329 allout-regexp "\\)")))
c567ac01 1330
fd5359c6 1331 (or (assq 'allout-mode minor-mode-alist)
c567ac01 1332 (setq minor-mode-alist
aad94676 1333 (cons '(allout-mode " Allout") minor-mode-alist)))
19b84ba3 1334
fd5359c6 1335 (allout-setup-menubar)
9179616f 1336
fd5359c6 1337 (if allout-layout
19b84ba3 1338 (setq do-layout t))
1977b8f6 1339
4185451d 1340 (if allout-isearch-dynamic-expose
fd5359c6 1341 (allout-enwrap-isearch))
19b84ba3 1342
fd5359c6
MR
1343 (run-hooks 'allout-mode-hook)
1344 (setq allout-mode t))
19b84ba3
RS
1345
1346 ;; Reactivation:
8d118843 1347 ((setq do-layout t)
fd5359c6 1348 (allout-infer-body-reindent))
c567ac01 1349 ) ; cond
19b84ba3
RS
1350
1351 (if (and do-layout
fd5359c6
MR
1352 allout-auto-activation
1353 (listp allout-layout)
1354 (and (not (eq allout-auto-activation 'activate))
1355 (if (eq allout-auto-activation 'ask)
19b84ba3
RS
1356 (if (y-or-n-p (format "Expose %s with layout '%s'? "
1357 (buffer-name)
fd5359c6 1358 allout-layout))
19b84ba3 1359 t
8d118843 1360 (message "Skipped %s layout." (buffer-name))
19b84ba3
RS
1361 nil)
1362 t)))
1363 (save-excursion
1364 (message "Adjusting '%s' exposure..." (buffer-name))
1365 (goto-char 0)
fd5359c6 1366 (allout-this-or-next-heading)
8d118843 1367 (condition-case err
353e2ef2 1368 (progn
fd5359c6 1369 (apply 'allout-expose-topic (list allout-layout))
8d118843
RS
1370 (message "Adjusting '%s' exposure... done." (buffer-name)))
1371 ;; Problem applying exposure - notify user, but don't
1372 ;; interrupt, eg, file visit:
1373 (error (message "%s" (car (cdr err)))
1374 (sit-for 1)))))
fd5359c6 1375 allout-mode
c567ac01 1376 ) ; let*
19b84ba3 1377 ) ; defun
fd5359c6 1378;;;_ > allout-minor-mode
9179616f 1379;;; XXX released verion doesn't do this?
fd5359c6 1380(defalias 'allout-minor-mode 'allout-mode)
1977b8f6 1381
fd5359c6 1382;;;_ #3 Internal Position State-Tracking - "allout-recent-*" funcs
19b84ba3 1383;;; All the basic outline functions that directly do string matches to
1977b8f6 1384;;; evaluate heading prefix location set the variables
fd5359c6
MR
1385;;; `allout-recent-prefix-beginning' and `allout-recent-prefix-end'
1386;;; when successful. Functions starting with `allout-recent-' all
19b84ba3
RS
1387;;; use this state, providing the means to avoid redundant searches
1388;;; for just-established data. This optimization can provide
1389;;; significant speed improvement, but it must be employed carefully.
fd5359c6
MR
1390;;;_ = allout-recent-prefix-beginning
1391(defvar allout-recent-prefix-beginning 0
c567ac01 1392 "Buffer point of the start of the last topic prefix encountered.")
fd5359c6
MR
1393(make-variable-buffer-local 'allout-recent-prefix-beginning)
1394;;;_ = allout-recent-prefix-end
1395(defvar allout-recent-prefix-end 0
c567ac01 1396 "Buffer point of the end of the last topic prefix encountered.")
fd5359c6
MR
1397(make-variable-buffer-local 'allout-recent-prefix-end)
1398;;;_ = allout-recent-end-of-subtree
1399(defvar allout-recent-end-of-subtree 0
2265e017 1400 "Buffer point last returned by `allout-end-of-current-subtree'.")
fd5359c6
MR
1401(make-variable-buffer-local 'allout-recent-end-of-subtree)
1402;;;_ > allout-prefix-data (beg end)
539d7736 1403(defmacro allout-prefix-data (beginning end)
fd5359c6
MR
1404 "Register allout-prefix state data - BEGINNING and END of prefix.
1405
1406For reference by `allout-recent' funcs. Returns BEGINNING."
1407 `(setq allout-recent-prefix-end ,end
539d7736 1408 allout-recent-prefix-beginning ,beginning))
fd5359c6
MR
1409;;;_ > allout-recent-depth ()
1410(defmacro allout-recent-depth ()
19b84ba3 1411 "Return depth of last heading encountered by an outline maneuvering function.
c567ac01
RS
1412
1413All outline functions which directly do string matches to assess
2265e017
MR
1414headings set the variables `allout-recent-prefix-beginning' and
1415`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01
RS
1416to return the current depth."
1417
fd5359c6
MR
1418 '(max 1 (- allout-recent-prefix-end
1419 allout-recent-prefix-beginning
1420 allout-header-subtraction)))
1421;;;_ > allout-recent-prefix ()
1422(defmacro allout-recent-prefix ()
2265e017 1423 "Like `allout-recent-depth', but returns text of last encountered prefix.
c567ac01
RS
1424
1425All outline functions which directly do string matches to assess
2265e017
MR
1426headings set the variables `allout-recent-prefix-beginning' and
1427`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01 1428to return the current depth."
fd5359c6
MR
1429 '(buffer-substring allout-recent-prefix-beginning
1430 allout-recent-prefix-end))
1431;;;_ > allout-recent-bullet ()
1432(defmacro allout-recent-bullet ()
1433 "Like allout-recent-prefix, but returns bullet of last encountered prefix.
c567ac01
RS
1434
1435All outline functions which directly do string matches to assess
2265e017
MR
1436headings set the variables `allout-recent-prefix-beginning' and
1437`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01 1438to return the current depth of the most recently matched topic."
fd5359c6
MR
1439 '(buffer-substring (1- allout-recent-prefix-end)
1440 allout-recent-prefix-end))
c567ac01 1441
19b84ba3 1442;;;_ #4 Navigation
c567ac01
RS
1443
1444;;;_ - Position Assessment
1445;;;_ : Location Predicates
fd5359c6
MR
1446;;;_ > allout-on-current-heading-p ()
1447(defun allout-on-current-heading-p ()
19b84ba3
RS
1448 "Return non-nil if point is on current visible topics' header line.
1449
1450Actually, returns prefix beginning point."
1977b8f6
RS
1451 (save-excursion
1452 (beginning-of-line)
fd5359c6
MR
1453 (and (looking-at allout-regexp)
1454 (allout-prefix-data (match-beginning 0) (match-end 0)))))
1455;;;_ > allout-on-heading-p ()
1456(defalias 'allout-on-heading-p 'allout-on-current-heading-p)
1457;;;_ > allout-e-o-prefix-p ()
1458(defun allout-e-o-prefix-p ()
19b84ba3 1459 "True if point is located where current topic prefix ends, heading begins."
c567ac01 1460 (and (save-excursion (beginning-of-line)
fd5359c6
MR
1461 (looking-at allout-regexp))
1462 (= (point)(save-excursion (allout-end-of-prefix)(point)))))
1463;;;_ > allout-hidden-p ()
1464(defmacro allout-hidden-p ()
1977b8f6 1465 "True if point is in hidden text."
c567ac01
RS
1466 '(save-excursion
1467 (and (re-search-backward "[\n\r]" () t)
1468 (= ?\r (following-char)))))
fd5359c6
MR
1469;;;_ > allout-visible-p ()
1470(defmacro allout-visible-p ()
c567ac01 1471 "True if point is not in hidden text."
1977b8f6 1472 (interactive)
fd5359c6 1473 '(not (allout-hidden-p)))
c567ac01 1474;;;_ : Location attributes
fd5359c6
MR
1475;;;_ > allout-depth ()
1476(defsubst allout-depth ()
2265e017 1477 "Like `allout-current-depth', but respects hidden as well as visible topics."
9179616f 1478 (save-excursion
fd5359c6
MR
1479 (if (allout-goto-prefix)
1480 (allout-recent-depth)
9179616f
DL
1481 (progn
1482 ;; Oops, no prefix, zero prefix data:
fd5359c6 1483 (allout-prefix-data (point)(point))
9179616f
DL
1484 ;; ... and return 0:
1485 0))))
fd5359c6
MR
1486;;;_ > allout-current-depth ()
1487(defmacro allout-current-depth ()
19b84ba3 1488 "Return nesting depth of visible topic most immediately containing point."
c567ac01 1489 '(save-excursion
fd5359c6 1490 (if (allout-back-to-current-heading)
c567ac01 1491 (max 1
fd5359c6
MR
1492 (- allout-recent-prefix-end
1493 allout-recent-prefix-beginning
1494 allout-header-subtraction))
c567ac01 1495 0)))
fd5359c6
MR
1496;;;_ > allout-get-current-prefix ()
1497(defun allout-get-current-prefix ()
c567ac01 1498 "Topic prefix of the current topic."
1977b8f6 1499 (save-excursion
fd5359c6
MR
1500 (if (allout-goto-prefix)
1501 (allout-recent-prefix))))
1502;;;_ > allout-get-bullet ()
1503(defun allout-get-bullet ()
c567ac01 1504 "Return bullet of containing topic (visible or not)."
1977b8f6 1505 (save-excursion
fd5359c6
MR
1506 (and (allout-goto-prefix)
1507 (allout-recent-bullet))))
1508;;;_ > allout-current-bullet ()
1509(defun allout-current-bullet ()
c567ac01 1510 "Return bullet of current (visible) topic heading, or none if none found."
1977b8f6
RS
1511 (condition-case err
1512 (save-excursion
fd5359c6
MR
1513 (allout-back-to-current-heading)
1514 (buffer-substring (- allout-recent-prefix-end 1)
1515 allout-recent-prefix-end))
1977b8f6 1516 ;; Quick and dirty provision, ostensibly for missing bullet:
9179616f 1517 ('args-out-of-range nil))
1977b8f6 1518 )
fd5359c6
MR
1519;;;_ > allout-get-prefix-bullet (prefix)
1520(defun allout-get-prefix-bullet (prefix)
c567ac01 1521 "Return the bullet of the header prefix string PREFIX."
1977b8f6
RS
1522 ;; Doesn't make sense if we're old-style prefixes, but this just
1523 ;; oughtn't be called then, so forget about it...
fd5359c6 1524 (if (string-match allout-regexp prefix)
1977b8f6 1525 (substring prefix (1- (match-end 0)) (match-end 0))))
fd5359c6
MR
1526;;;_ > allout-sibling-index (&optional depth)
1527(defun allout-sibling-index (&optional depth)
9179616f
DL
1528 "Item number of this prospective topic among its siblings.
1529
e126900f 1530If optional arg DEPTH is greater than current depth, then we're
9179616f
DL
1531opening a new level, and return 0.
1532
1533If less than this depth, ascend to that depth and count..."
1534
1535 (save-excursion
1536 (cond ((and depth (<= depth 0) 0))
fd5359c6 1537 ((or (not depth) (= depth (allout-depth)))
9179616f 1538 (let ((index 1))
fd5359c6 1539 (while (allout-previous-sibling (allout-recent-depth) nil)
9179616f
DL
1540 (setq index (1+ index)))
1541 index))
fd5359c6
MR
1542 ((< depth (allout-recent-depth))
1543 (allout-ascend-to-depth depth)
1544 (allout-sibling-index))
9179616f 1545 (0))))
fd5359c6
MR
1546;;;_ > allout-topic-flat-index ()
1547(defun allout-topic-flat-index ()
9179616f
DL
1548 "Return a list indicating point's numeric section.subsect.subsubsect...
1549Outermost is first."
fd5359c6
MR
1550 (let* ((depth (allout-depth))
1551 (next-index (allout-sibling-index depth))
9179616f
DL
1552 (rev-sibls nil))
1553 (while (> next-index 0)
1554 (setq rev-sibls (cons next-index rev-sibls))
1555 (setq depth (1- depth))
fd5359c6 1556 (setq next-index (allout-sibling-index depth)))
9179616f
DL
1557 rev-sibls)
1558 )
1977b8f6 1559
c567ac01 1560;;;_ - Navigation macros
fd5359c6
MR
1561;;;_ > allout-next-heading ()
1562(defsubst allout-next-heading ()
c567ac01
RS
1563 "Move to the heading for the topic \(possibly invisible) before this one.
1564
1565Returns the location of the heading, or nil if none found."
1566
9179616f 1567 (if (and (bobp) (not (eobp)))
c567ac01
RS
1568 (forward-char 1))
1569
fd5359c6
MR
1570 (if (re-search-forward allout-line-boundary-regexp nil 0)
1571 (allout-prefix-data ; Got valid location state - set vars:
9179616f 1572 (goto-char (or (match-beginning 2)
fd5359c6
MR
1573 allout-recent-prefix-beginning))
1574 (or (match-end 2) allout-recent-prefix-end))))
1575;;;_ : allout-this-or-next-heading
1576(defun allout-this-or-next-heading ()
8d118843 1577 "Position cursor on current or next heading."
fd5359c6
MR
1578 ;; A throwaway non-macro that is defined after allout-next-heading
1579 ;; and usable by allout-mode.
1580 (if (not (allout-goto-prefix)) (allout-next-heading)))
1581;;;_ > allout-previous-heading ()
1582(defmacro allout-previous-heading ()
19b84ba3 1583 "Move to the prior \(possibly invisible) heading line.
c567ac01
RS
1584
1585Return the location of the beginning of the heading, or nil if not found."
1586
1587 '(if (bobp)
1588 nil
fd5359c6 1589 (allout-goto-prefix)
c567ac01
RS
1590 (if
1591 ;; searches are unbounded and return nil if failed:
fd5359c6
MR
1592 (or (re-search-backward allout-line-boundary-regexp nil 0)
1593 (looking-at allout-bob-regexp))
19b84ba3 1594 (progn ; Got valid location state - set vars:
fd5359c6 1595 (allout-prefix-data
c567ac01 1596 (goto-char (or (match-beginning 2)
fd5359c6
MR
1597 allout-recent-prefix-beginning))
1598 (or (match-end 2) allout-recent-prefix-end))))))
c567ac01
RS
1599
1600;;;_ - Subtree Charting
1601;;;_ " These routines either produce or assess charts, which are
1602;;; nested lists of the locations of topics within a subtree.
1603;;;
1604;;; Use of charts enables efficient navigation of subtrees, by
1605;;; requiring only a single regexp-search based traversal, to scope
1606;;; out the subtopic locations. The chart then serves as the basis
9179616f
DL
1607;;; for assessment or adjustment of the subtree, without redundant
1608;;; traversal of the structure.
c567ac01 1609
fd5359c6
MR
1610;;;_ > allout-chart-subtree (&optional levels orig-depth prev-depth)
1611(defun allout-chart-subtree (&optional levels orig-depth prev-depth)
19b84ba3
RS
1612 "Produce a location \"chart\" of subtopics of the containing topic.
1613
a0776d6b 1614Optional argument LEVELS specifies the depth \(relative to start
e126900f 1615depth) for the chart.
19b84ba3 1616
aad94676 1617Charts are used to capture outline structure, so that outline altering
19b84ba3
RS
1618routines need assess the structure only once, and then use the chart
1619for their elaborate manipulations.
1620
1621Topics are entered in the chart so the last one is at the car.
1622The entry for each topic consists of an integer indicating the point
1623at the beginning of the topic. Charts for offspring consists of a
1624list containing, recursively, the charts for the respective subtopics.
1625The chart for a topics' offspring precedes the entry for the topic
1626itself.
1627
539d7736 1628\(fn &optional LEVELS)"
e126900f
JB
1629
1630 ;; The other function parameters are for internal recursion, and should
1631 ;; not be specified by external callers. ORIG-DEPTH is depth of topic at
1632 ;; starting point, and PREV-DEPTH is depth of prior topic."
19b84ba3 1633
353e2ef2 1634 (let ((original (not orig-depth)) ; `orig-depth' set only in recursion.
19b84ba3
RS
1635 chart curr-depth)
1636
1637 (if original ; Just starting?
1638 ; Register initial settings and
1639 ; position to first offspring:
fd5359c6 1640 (progn (setq orig-depth (allout-depth))
19b84ba3 1641 (or prev-depth (setq prev-depth (1+ orig-depth)))
fd5359c6 1642 (allout-next-heading)))
c567ac01 1643
19b84ba3
RS
1644 ;; Loop over the current levels' siblings. Besides being more
1645 ;; efficient than tail-recursing over a level, it avoids exceeding
e126900f 1646 ;; the typically quite constrained Emacs max-lisp-eval-depth.
9179616f 1647 ;;
19b84ba3
RS
1648 ;; Probably would speed things up to implement loop-based stack
1649 ;; operation rather than recursing for lower levels. Bah.
9179616f 1650
c567ac01 1651 (while (and (not (eobp))
19b84ba3 1652 ; Still within original topic?
fd5359c6 1653 (< orig-depth (setq curr-depth (allout-recent-depth)))
19b84ba3
RS
1654 (cond ((= prev-depth curr-depth)
1655 ;; Register this one and move on:
1656 (setq chart (cons (point) chart))
1657 (if (and levels (<= levels 1))
1658 ;; At depth limit - skip sublevels:
fd5359c6 1659 (or (allout-next-sibling curr-depth)
19b84ba3
RS
1660 ;; or no more siblings - proceed to
1661 ;; next heading at lesser depth:
e6a9aec7 1662 (while (and (<= curr-depth
fd5359c6
MR
1663 (allout-recent-depth))
1664 (allout-next-heading))))
1665 (allout-next-heading)))
19b84ba3
RS
1666
1667 ((and (< prev-depth curr-depth)
1668 (or (not levels)
1669 (> levels 0)))
1670 ;; Recurse on deeper level of curr topic:
1671 (setq chart
fd5359c6 1672 (cons (allout-chart-subtree (and levels
19b84ba3
RS
1673 (1- levels))
1674 orig-depth
1675 curr-depth)
1676 chart))
1677 ;; ... then continue with this one.
1678 )
1679
1680 ;; ... else nil if we've ascended back to prev-depth.
1681
1682 )))
1683
1684 (if original ; We're at the last sibling on
1685 ; the original level. Position
1686 ; to the end of it:
c567ac01 1687 (progn (and (not (eobp)) (forward-char -1))
9179616f 1688 (and (memq (preceding-char) '(?\n ?\r))
c567ac01
RS
1689 (memq (aref (buffer-substring (max 1 (- (point) 3))
1690 (point))
1691 1)
9179616f 1692 '(?\n ?\r))
19b84ba3 1693 (forward-char -1))
fd5359c6 1694 (setq allout-recent-end-of-subtree (point))))
353e2ef2 1695
c567ac01
RS
1696 chart ; (nreverse chart) not necessary,
1697 ; and maybe not preferable.
1698 ))
fd5359c6
MR
1699;;;_ > allout-chart-siblings (&optional start end)
1700(defun allout-chart-siblings (&optional start end)
c567ac01 1701 "Produce a list of locations of this and succeeding sibling topics.
fd5359c6 1702Effectively a top-level chart of siblings. See `allout-chart-subtree'
c567ac01
RS
1703for an explanation of charts."
1704 (save-excursion
fd5359c6 1705 (if (allout-goto-prefix)
c567ac01 1706 (let ((chart (list (point))))
fd5359c6 1707 (while (allout-next-sibling)
c567ac01 1708 (setq chart (cons (point) chart)))
19b84ba3 1709 (if chart (setq chart (nreverse chart)))))))
fd5359c6
MR
1710;;;_ > allout-chart-to-reveal (chart depth)
1711(defun allout-chart-to-reveal (chart depth)
c567ac01 1712
19b84ba3 1713 "Return a flat list of hidden points in subtree CHART, up to DEPTH.
c567ac01 1714
19b84ba3 1715Note that point can be left at any of the points on chart, or at the
c567ac01
RS
1716start point."
1717
1718 (let (result here)
1719 (while (and (or (eq depth t) (> depth 0))
1720 chart)
1721 (setq here (car chart))
1722 (if (listp here)
fd5359c6 1723 (let ((further (allout-chart-to-reveal here (or (eq depth t)
c567ac01
RS
1724 (1- depth)))))
1725 ;; We're on the start of a subtree - recurse with it, if there's
1726 ;; more depth to go:
1727 (if further (setq result (append further result)))
1728 (setq chart (cdr chart)))
1729 (goto-char here)
1730 (if (= (preceding-char) ?\r)
1731 (setq result (cons here result)))
1732 (setq chart (cdr chart))))
1733 result))
fd5359c6 1734;;;_ X allout-chart-spec (chart spec &optional exposing)
e126900f
JB
1735;; (defun allout-chart-spec (chart spec &optional exposing)
1736;; "Not yet \(if ever) implemented.
1737
1738;; Produce exposure directives given topic/subtree CHART and an exposure SPEC.
1739
1740;; Exposure spec indicates the locations to be exposed and the prescribed
1741;; exposure status. Optional arg EXPOSING is an integer, with 0
1742;; indicating pending concealment, anything higher indicating depth to
1743;; which subtopic headers should be exposed, and negative numbers
1744;; indicating (negative of) the depth to which subtopic headers and
1745;; bodies should be exposed.
1746
1747;; The produced list can have two types of entries. Bare numbers
1748;; indicate points in the buffer where topic headers that should be
1749;; exposed reside.
1750
1751;; - bare negative numbers indicates that the topic starting at the
1752;; point which is the negative of the number should be opened,
1753;; including their entries.
1754;; - bare positive values indicate that this topic header should be
1755;; opened.
1756;; - Lists signify the beginning and end points of regions that should
1757;; be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
1758;; exposure:"
1759;; (while spec
1760;; (cond ((listp spec)
1761;; )
1762;; )
1763;; (setq spec (cdr spec)))
1764;; )
c567ac01
RS
1765
1766;;;_ - Within Topic
fd5359c6
MR
1767;;;_ > allout-goto-prefix ()
1768(defun allout-goto-prefix ()
9179616f 1769 "Put point at beginning of immediately containing outline topic.
19b84ba3 1770
9179616f 1771Goes to most immediate subsequent topic if none immediately containing.
19b84ba3
RS
1772
1773Not sensitive to topic visibility.
c567ac01 1774
d27081f5 1775Returns the point at the beginning of the prefix, or nil if none."
c567ac01 1776
19b84ba3
RS
1777 (let (done)
1778 (while (and (not done)
1779 (re-search-backward "[\n\r]" nil 1))
1780 (forward-char 1)
fd5359c6
MR
1781 (if (looking-at allout-regexp)
1782 (setq done (allout-prefix-data (match-beginning 0)
19b84ba3
RS
1783 (match-end 0)))
1784 (forward-char -1)))
1785 (if (bobp)
fd5359c6
MR
1786 (cond ((looking-at allout-regexp)
1787 (allout-prefix-data (match-beginning 0)(match-end 0)))
1788 ((allout-next-heading))
19b84ba3
RS
1789 (done))
1790 done)))
fd5359c6
MR
1791;;;_ > allout-end-of-prefix ()
1792(defun allout-end-of-prefix (&optional ignore-decorations)
19b84ba3
RS
1793 "Position cursor at beginning of header text.
1794
1795If optional IGNORE-DECORATIONS is non-nil, put just after bullet,
1796otherwise skip white space between bullet and ensuing text."
c567ac01 1797
fd5359c6 1798 (if (not (allout-goto-prefix))
1977b8f6
RS
1799 nil
1800 (let ((match-data (match-data)))
1801 (goto-char (match-end 0))
c567ac01
RS
1802 (if ignore-decorations
1803 t
1804 (while (looking-at "[0-9]") (forward-char 1))
1805 (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1)))
9179616f 1806 (store-match-data match-data))
1977b8f6 1807 ;; Reestablish where we are:
fd5359c6
MR
1808 (allout-current-depth)))
1809;;;_ > allout-current-bullet-pos ()
1810(defun allout-current-bullet-pos ()
c567ac01
RS
1811 "Return position of current \(visible) topic's bullet."
1812
fd5359c6 1813 (if (not (allout-current-depth))
c567ac01
RS
1814 nil
1815 (1- (match-end 0))))
fd5359c6
MR
1816;;;_ > allout-back-to-current-heading ()
1817(defun allout-back-to-current-heading ()
19b84ba3
RS
1818 "Move to heading line of current topic, or beginning if already on the line."
1819
1977b8f6 1820 (beginning-of-line)
fd5359c6
MR
1821 (prog1 (or (allout-on-current-heading-p)
1822 (and (re-search-backward (concat "^\\(" allout-regexp "\\)")
1977b8f6
RS
1823 nil
1824 'move)
fd5359c6
MR
1825 (allout-prefix-data (match-beginning 1)(match-end 1))))
1826 (if (interactive-p) (allout-end-of-prefix))))
1827;;;_ > allout-back-to-heading ()
1828(defalias 'allout-back-to-heading 'allout-back-to-current-heading)
1829;;;_ > allout-pre-next-preface ()
1830(defun allout-pre-next-preface ()
1977b8f6
RS
1831 "Skip forward to just before the next heading line.
1832
c567ac01 1833Returns that character position."
1977b8f6 1834
fd5359c6 1835 (if (re-search-forward allout-line-boundary-regexp nil 'move)
c567ac01 1836 (prog1 (goto-char (match-beginning 0))
fd5359c6
MR
1837 (allout-prefix-data (match-beginning 2)(match-end 2)))))
1838;;;_ > allout-end-of-current-subtree ()
1839(defun allout-end-of-current-subtree ()
c567ac01 1840 "Put point at the end of the last leaf in the currently visible topic."
1977b8f6 1841 (interactive)
fd5359c6
MR
1842 (allout-back-to-current-heading)
1843 (let ((level (allout-recent-depth)))
1844 (allout-next-heading)
1977b8f6 1845 (while (and (not (eobp))
fd5359c6
MR
1846 (> (allout-recent-depth) level))
1847 (allout-next-heading))
c567ac01 1848 (and (not (eobp)) (forward-char -1))
9179616f 1849 (and (memq (preceding-char) '(?\n ?\r))
c567ac01 1850 (memq (aref (buffer-substring (max 1 (- (point) 3)) (point)) 1)
9179616f 1851 '(?\n ?\r))
c567ac01 1852 (forward-char -1))
fd5359c6
MR
1853 (setq allout-recent-end-of-subtree (point))))
1854;;;_ > allout-beginning-of-current-entry ()
1855(defun allout-beginning-of-current-entry ()
19b84ba3 1856 "When not already there, position point at beginning of current topic's body.
c567ac01
RS
1857
1858If already there, move cursor to bullet for hot-spot operation.
2265e017 1859\(See `allout-mode' doc string for details on hot-spot operation.)"
1977b8f6 1860 (interactive)
c567ac01 1861 (let ((start-point (point)))
fd5359c6 1862 (allout-end-of-prefix)
c567ac01
RS
1863 (if (and (interactive-p)
1864 (= (point) start-point))
fd5359c6
MR
1865 (goto-char (allout-current-bullet-pos)))))
1866;;;_ > allout-end-of-current-entry ()
1867(defun allout-end-of-current-entry ()
c567ac01 1868 "Position the point at the end of the current topics' entry."
1977b8f6 1869 (interactive)
fd5359c6
MR
1870 (allout-show-entry)
1871 (prog1 (allout-pre-next-preface)
1977b8f6 1872 (if (and (not (bobp))(looking-at "^$"))
19b84ba3 1873 (forward-char -1))))
fd5359c6
MR
1874;;;_ > allout-end-of-current-heading ()
1875(defun allout-end-of-current-heading ()
9179616f 1876 (interactive)
fd5359c6 1877 (allout-beginning-of-current-entry)
9179616f
DL
1878 (forward-line -1)
1879 (end-of-line))
fd5359c6 1880(defalias 'allout-end-of-heading 'allout-end-of-current-heading)
1977b8f6 1881
c567ac01 1882;;;_ - Depth-wise
fd5359c6
MR
1883;;;_ > allout-ascend-to-depth (depth)
1884(defun allout-ascend-to-depth (depth)
c567ac01 1885 "Ascend to depth DEPTH, returning depth if successful, nil if not."
fd5359c6 1886 (if (and (> depth 0)(<= depth (allout-depth)))
1977b8f6 1887 (let ((last-good (point)))
fd5359c6 1888 (while (and (< depth (allout-depth))
1977b8f6 1889 (setq last-good (point))
fd5359c6
MR
1890 (allout-beginning-of-level)
1891 (allout-previous-heading)))
1892 (if (= (allout-recent-depth) depth)
1893 (progn (goto-char allout-recent-prefix-beginning)
1977b8f6 1894 depth)
65970d64 1895 (goto-char last-good)))))
fd5359c6
MR
1896;;;_ > allout-ascend ()
1897(defun allout-ascend ()
9179616f 1898 "Ascend one level, returning t if successful, nil if not."
65970d64
RS
1899 (if (allout-beginning-of-level)
1900 (allout-previous-heading)))
fd5359c6
MR
1901;;;_ > allout-descend-to-depth (depth)
1902(defun allout-descend-to-depth (depth)
19b84ba3
RS
1903 "Descend to depth DEPTH within current topic.
1904
1905Returning depth if successful, nil if not."
1977b8f6 1906 (let ((start-point (point))
fd5359c6 1907 (start-depth (allout-depth)))
1977b8f6 1908 (while
fd5359c6
MR
1909 (and (> (allout-depth) 0)
1910 (not (= depth (allout-recent-depth))) ; ... not there yet
1911 (allout-next-heading) ; ... go further
1912 (< start-depth (allout-recent-depth)))) ; ... still in topic
1913 (if (and (> (allout-depth) 0)
1914 (= (allout-recent-depth) depth))
1977b8f6
RS
1915 depth
1916 (goto-char start-point)
1917 nil))
1918 )
fd5359c6 1919;;;_ > allout-up-current-level (arg &optional dont-complain)
65970d64 1920(defun allout-up-current-level (arg &optional dont-complain interactive)
19b84ba3
RS
1921 "Move out ARG levels from current visible topic.
1922
1923Positions on heading line of containing topic. Error if unable to
1924ascend that far, or nil if unable to ascend but optional arg
1925DONT-COMPLAIN is non-nil."
65970d64 1926 (interactive "p\np")
fd5359c6
MR
1927 (allout-back-to-current-heading)
1928 (let ((present-level (allout-recent-depth))
19b84ba3
RS
1929 (last-good (point))
1930 failed
1931 return)
1977b8f6 1932 ;; Loop for iterating arg:
fd5359c6 1933 (while (and (> (allout-recent-depth) 1)
1977b8f6 1934 (> arg 0)
19b84ba3
RS
1935 (not (bobp))
1936 (not failed))
1937 (setq last-good (point))
1977b8f6 1938 ;; Loop for going back over current or greater depth:
fd5359c6
MR
1939 (while (and (not (< (allout-recent-depth) present-level))
1940 (or (allout-previous-visible-heading 1)
19b84ba3 1941 (not (setq failed present-level)))))
fd5359c6 1942 (setq present-level (allout-current-depth))
1977b8f6 1943 (setq arg (- arg 1)))
19b84ba3
RS
1944 (if (or failed
1945 (> arg 0))
1946 (progn (goto-char last-good)
65970d64 1947 (if interactive (allout-end-of-prefix))
19b84ba3 1948 (if (not dont-complain)
6a05d05f 1949 (error "Can't ascend past outermost level")
65970d64 1950 (if interactive (allout-end-of-prefix))
19b84ba3 1951 nil))
65970d64 1952 (if interactive (allout-end-of-prefix))
fd5359c6 1953 allout-recent-prefix-beginning)))
1977b8f6 1954
c567ac01 1955;;;_ - Linear
fd5359c6
MR
1956;;;_ > allout-next-sibling (&optional depth backward)
1957(defun allout-next-sibling (&optional depth backward)
2265e017 1958 "Like `allout-forward-current-level', but respects invisible topics.
1977b8f6 1959
c567ac01 1960Traverse at optional DEPTH, or current depth if none specified.
1977b8f6 1961
c567ac01 1962Go backward if optional arg BACKWARD is non-nil.
1977b8f6 1963
c567ac01 1964Return depth if successful, nil otherwise."
1977b8f6
RS
1965
1966 (if (and backward (bobp))
1967 nil
fd5359c6 1968 (let ((start-depth (or depth (allout-depth)))
1977b8f6 1969 (start-point (point))
c567ac01 1970 last-depth)
1977b8f6 1971 (while (and (not (if backward (bobp) (eobp)))
fd5359c6
MR
1972 (if backward (allout-previous-heading)
1973 (allout-next-heading))
1974 (> (setq last-depth (allout-recent-depth)) start-depth)))
1977b8f6 1975 (if (and (not (eobp))
fd5359c6
MR
1976 (and (> (or last-depth (allout-depth)) 0)
1977 (= (allout-recent-depth) start-depth)))
1978 allout-recent-prefix-beginning
1977b8f6 1979 (goto-char start-point)
fd5359c6 1980 (if depth (allout-depth) start-depth)
c567ac01 1981 nil))))
fd5359c6
MR
1982;;;_ > allout-previous-sibling (&optional depth backward)
1983(defun allout-previous-sibling (&optional depth backward)
aad94676 1984 "Like `allout-forward-current-level', but backwards & respect invisible topics.
1977b8f6 1985
c567ac01 1986Optional DEPTH specifies depth to traverse, default current depth.
1977b8f6 1987
c567ac01 1988Optional BACKWARD reverses direction.
1977b8f6 1989
c567ac01 1990Return depth if successful, nil otherwise."
fd5359c6 1991 (allout-next-sibling depth (not backward))
1977b8f6 1992 )
fd5359c6
MR
1993;;;_ > allout-snug-back ()
1994(defun allout-snug-back ()
539d7736 1995 "Position cursor at end of previous topic.
19b84ba3
RS
1996
1997Presumes point is at the start of a topic prefix."
c567ac01
RS
1998 (if (or (bobp) (eobp))
1999 nil
2000 (forward-char -1))
9179616f 2001 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
c567ac01
RS
2002 nil
2003 (forward-char -1)
9179616f 2004 (if (or (bobp) (not (memq (preceding-char) '(?\n ?\r))))
c567ac01
RS
2005 (forward-char -1)))
2006 (point))
fd5359c6
MR
2007;;;_ > allout-beginning-of-level ()
2008(defun allout-beginning-of-level ()
c567ac01 2009 "Go back to the first sibling at this level, visible or not."
fd5359c6
MR
2010 (allout-end-of-level 'backward))
2011;;;_ > allout-end-of-level (&optional backward)
2012(defun allout-end-of-level (&optional backward)
c567ac01 2013 "Go to the last sibling at this level, visible or not."
1977b8f6 2014
fd5359c6
MR
2015 (let ((depth (allout-depth)))
2016 (while (allout-previous-sibling depth nil))
2017 (prog1 (allout-recent-depth)
65970d64 2018 (allout-end-of-prefix))))
fd5359c6
MR
2019;;;_ > allout-next-visible-heading (arg)
2020(defun allout-next-visible-heading (arg)
19b84ba3 2021 "Move to the next ARG'th visible heading line, backward if arg is negative.
c567ac01 2022
19b84ba3 2023Move as far as possible in indicated direction \(beginning or end of
9179616f 2024buffer) if headings are exhausted."
1977b8f6 2025
1977b8f6 2026 (interactive "p")
c567ac01
RS
2027 (let* ((backward (if (< arg 0) (setq arg (* -1 arg))))
2028 (step (if backward -1 1))
19b84ba3 2029 (start-point (point))
c567ac01
RS
2030 prev got)
2031
2032 (while (> arg 0) ; limit condition
2033 (while (and (not (if backward (bobp)(eobp))) ; boundary condition
19b84ba3
RS
2034 ;; Move, skipping over all those concealed lines:
2035 (< -1 (forward-line step))
fd5359c6 2036 (not (setq got (looking-at allout-regexp)))))
c567ac01
RS
2037 ;; Register this got, it may be the last:
2038 (if got (setq prev got))
2039 (setq arg (1- arg)))
2040 (cond (got ; Last move was to a prefix:
fd5359c6
MR
2041 (allout-prefix-data (match-beginning 0) (match-end 0))
2042 (allout-end-of-prefix))
c567ac01 2043 (prev ; Last move wasn't, but prev was:
fd5359c6 2044 (allout-prefix-data (match-beginning 0) (match-end 0)))
c567ac01 2045 ((not backward) (end-of-line) nil))))
fd5359c6
MR
2046;;;_ > allout-previous-visible-heading (arg)
2047(defun allout-previous-visible-heading (arg)
c567ac01 2048 "Move to the previous heading line.
1977b8f6 2049
c567ac01 2050With argument, repeats or can move forward if negative.
2265e017 2051A heading line is one that starts with a `*' (or that `allout-regexp'
c567ac01 2052matches)."
1977b8f6 2053 (interactive "p")
fd5359c6
MR
2054 (allout-next-visible-heading (- arg)))
2055;;;_ > allout-forward-current-level (arg)
65970d64 2056(defun allout-forward-current-level (arg &optional interactive)
19b84ba3 2057 "Position point at the next heading of the same level.
1977b8f6 2058
19b84ba3 2059Takes optional repeat-count, goes backward if count is negative.
1977b8f6 2060
19b84ba3 2061Returns resulting position, else nil if none found."
65970d64 2062 (interactive "p\np")
fd5359c6 2063 (let ((start-depth (allout-current-depth))
19b84ba3
RS
2064 (start-point (point))
2065 (start-arg arg)
2066 (backward (> 0 arg))
2067 last-depth
2068 (last-good (point))
2069 at-boundary)
2070 (if (= 0 start-depth)
2071 (error "No siblings, not in a topic..."))
2072 (if backward (setq arg (* -1 arg)))
2073 (while (not (or (zerop arg)
2074 at-boundary))
2075 (while (and (not (if backward (bobp) (eobp)))
fd5359c6
MR
2076 (if backward (allout-previous-visible-heading 1)
2077 (allout-next-visible-heading 1))
2078 (> (setq last-depth (allout-recent-depth)) start-depth)))
19b84ba3
RS
2079 (if (and last-depth (= last-depth start-depth)
2080 (not (if backward (bobp) (eobp))))
2081 (setq last-good (point)
2082 arg (1- arg))
2083 (setq at-boundary t)))
2084 (if (and (not (eobp))
2085 (= arg 0)
fd5359c6
MR
2086 (and (> (or last-depth (allout-depth)) 0)
2087 (= (allout-recent-depth) start-depth)))
2088 allout-recent-prefix-beginning
19b84ba3 2089 (goto-char last-good)
65970d64 2090 (if (not interactive)
19b84ba3 2091 nil
fd5359c6 2092 (allout-end-of-prefix)
6a05d05f 2093 (error "Hit %s level %d topic, traversed %d of %d requested"
19b84ba3 2094 (if backward "first" "last")
fd5359c6 2095 (allout-recent-depth)
19b84ba3
RS
2096 (- (abs start-arg) arg)
2097 (abs start-arg))))))
fd5359c6 2098;;;_ > allout-backward-current-level (arg)
65970d64 2099(defun allout-backward-current-level (arg &optional interactive)
fd5359c6 2100 "Inverse of `allout-forward-current-level'."
65970d64
RS
2101 (interactive "p\np")
2102 (if interactive
19b84ba3 2103 (let ((current-prefix-arg (* -1 arg)))
fd5359c6
MR
2104 (call-interactively 'allout-forward-current-level))
2105 (allout-forward-current-level (* -1 arg))))
c567ac01 2106
19b84ba3 2107;;;_ #5 Alteration
c567ac01
RS
2108
2109;;;_ - Fundamental
fd5359c6
MR
2110;;;_ > allout-before-change-protect (beg end)
2111(defun allout-before-change-protect (beg end)
19b84ba3
RS
2112 "Outline before-change hook, regulates changes to concealed text.
2113
2114Reveal concealed text that would be changed by current command, and
c567ac01
RS
2115offer user choice to commit or forego the change. Unchanged text is
2116reconcealed. User has option to have changed text reconcealed.
2117
2118Undo commands are specially treated - the user is not prompted for
2119choice, the undoes are always committed (based on presumption that the
2120things being undone were already subject to this regulation routine),
2121and undoes always leave the changed stuff exposed.
2122
2123Changes to concealed regions are ignored while file is being written.
2124\(This is for the sake of functions that do change the file during
2125writes, like crypt and zip modes.)
2126
9179616f 2127Locally bound in outline buffers to `before-change-functions', which
e126900f 2128in Emacs 19 is run before any change to the buffer.
c567ac01 2129
353e2ef2 2130Any functions which set [`this-command' to `undo', or which set]
fd5359c6 2131`allout-override-protect' non-nil (as does, eg, allout-flag-chars)
c567ac01 2132are exempt from this restriction."
fd5359c6
MR
2133 (if (and (allout-mode-p)
2134 ; allout-override-protect
c567ac01
RS
2135 ; set by functions that know what
2136 ; they're doing, eg outline internals:
fd5359c6
MR
2137 (not allout-override-protect)
2138 (not allout-during-write-cue)
c567ac01
RS
2139 (save-match-data ; Preserve operation position state.
2140 ; Both beginning and end chars must
2141 ; be exposed:
2142 (save-excursion (if (memq this-command '(newline open-line))
e126900f 2143 ;; Compensate for stupid Emacs {new,
c567ac01
RS
2144 ;; open-}line display optimization:
2145 (setq beg (1+ beg)
2146 end (1+ end)))
2147 (goto-char beg)
fd5359c6 2148 (or (allout-hidden-p)
c567ac01
RS
2149 (and (not (= beg end))
2150 (goto-char end)
fd5359c6 2151 (allout-hidden-p))))))
c567ac01
RS
2152 (save-match-data
2153 (if (equal this-command 'undo)
2154 ;; Allow undo without inhibition.
e126900f 2155 ;; - Undoing new and open-line hits stupid Emacs redisplay
c567ac01
RS
2156 ;; optimization (em 19 cmds.c, ~ line 200).
2157 ;; - Presumably, undoing what was properly protected when
2158 ;; done.
2159 ;; - Undo may be users' only recourse in protection faults.
2160 ;; So, expose what getting changed:
2161 (progn (message "Undo! - exposing concealed target...")
fd5359c6
MR
2162 (if (allout-hidden-p)
2163 (allout-show-children))
19b84ba3 2164 (message "Undo!"))
c567ac01 2165 (let (response
fd5359c6
MR
2166 (rehide-completely (save-excursion (allout-goto-prefix)
2167 (allout-hidden-p)))
c567ac01 2168 rehide-place)
353e2ef2 2169
c567ac01
RS
2170 (save-excursion
2171 (if (condition-case err
2172 ;; Condition case to catch keyboard quits during reads.
2173 (progn
2174 ; Give them a peek where
2175 (save-excursion
2176 (if (eolp) (setq rehide-place
fd5359c6
MR
2177 (allout-goto-prefix)))
2178 (allout-show-entry))
c567ac01
RS
2179 ; Present the message, but...
2180 ; leave the cursor at the location
2181 ; until they respond:
2182 ; Then interpret the response:
2183 (while
353e2ef2 2184 (progn
c567ac01
RS
2185 (message (concat "Change inside concealed"
2186 " region - do it? "
2187 "(n or 'y'/'r'eclose)"))
2188 (setq response (read-char))
2189 (not
2190 (cond ((memq response '(?r ?R))
2191 (setq response 'reclose))
2192 ((memq response '(?y ?Y ? ))
2193 (setq response t))
2194 ((memq response '(?n ?N 127))
2195 (setq response nil)
2196 t)
2197 ((eq response ??)
2198 (message
353e2ef2 2199 "`r' means `yes, then reclose'")
c567ac01
RS
2200 nil)
2201 (t (message "Please answer y, n, or r")
2202 (sit-for 1)
2203 nil)))))
2204 response)
9179616f 2205 ('quit nil))
c567ac01
RS
2206 ; Continue:
2207 (if (eq response 'reclose)
2208 (save-excursion
2209 (if rehide-place (goto-char rehide-place))
2210 (if rehide-completely
fd5359c6
MR
2211 (allout-hide-current-entry-completely)
2212 (allout-hide-current-entry)))
2213 (if (allout-ascend-to-depth (1- (allout-recent-depth)))
2214 (allout-show-children)
2215 (allout-show-to-offshoot)))
c567ac01
RS
2216 ; Prevent:
2217 (if rehide-completely
2218 (save-excursion
2219 (if rehide-place (goto-char rehide-place))
fd5359c6
MR
2220 (allout-hide-current-entry-completely))
2221 (allout-hide-current-entry))
b4fb325f 2222 (error "Change within concealed region prevented"))))))
c567ac01
RS
2223 ) ; if
2224 ) ; defun
fd5359c6
MR
2225;;;_ = allout-post-goto-bullet
2226(defvar allout-post-goto-bullet nil
2227 "Outline internal var, for `allout-pre-command-business' hot-spot operation.
19b84ba3
RS
2228
2229When set, tells post-processing to reposition on topic bullet, and
2265e017 2230then unset it. Set by `allout-pre-command-business' when implementing
19b84ba3
RS
2231hot-spot operation, where literal characters typed over a topic bullet
2232are mapped to the command of the corresponding control-key on the
2265e017 2233`allout-mode-map'.")
fd5359c6
MR
2234(make-variable-buffer-local 'allout-post-goto-bullet)
2235;;;_ > allout-post-command-business ()
2236(defun allout-post-command-business ()
2265e017 2237 "Outline `post-command-hook' function.
c567ac01 2238
2265e017 2239- Null `allout-override-protect', so it's not left open.
c567ac01 2240
2265e017 2241- Implement (and clear) `allout-post-goto-bullet', for hot-spot
c567ac01
RS
2242 outline commands.
2243
539d7736
JB
2244- Massages `buffer-undo-list' so successive, standard character self-inserts
2245 are aggregated. This kludge compensates for lack of undo bunching when
2265e017 2246 `before-change-functions' is used."
c567ac01
RS
2247
2248 ; Apply any external change func:
fd5359c6 2249 (if (not (allout-mode-p)) ; In allout-mode.
19b84ba3 2250 nil
fd5359c6
MR
2251 (setq allout-override-protect nil)
2252 (if allout-isearch-dynamic-expose
2253 (allout-isearch-rectification))
2254 (if allout-during-write-cue
2255 ;; Was used by allout-before-change-protect, done with it now:
2256 (setq allout-during-write-cue nil))
19b84ba3
RS
2257 ;; Undo bunching business:
2258 (if (and (listp buffer-undo-list) ; Undo history being kept.
2259 (equal this-command 'self-insert-command)
2260 (equal last-command 'self-insert-command))
2261 (let* ((prev-stuff (cdr buffer-undo-list))
2262 (before-prev-stuff (cdr (cdr prev-stuff)))
2263 cur-cell cur-from cur-to
2264 prev-cell prev-from prev-to)
2265 (if (and before-prev-stuff ; Goes back far enough to bother,
2266 (not (car prev-stuff)) ; and break before current,
2267 (not (car before-prev-stuff)) ; !and break before prev!
2268 (setq prev-cell (car (cdr prev-stuff))) ; contents now,
2269 (setq cur-cell (car buffer-undo-list)) ; contents prev.
2270
2271 ;; cur contents denote a single char insertion:
2272 (numberp (setq cur-from (car cur-cell)))
2273 (numberp (setq cur-to (cdr cur-cell)))
2274 (= 1 (- cur-to cur-from))
2275
2276 ;; prev contents denote fewer than aggregate-limit
2277 ;; insertions:
2278 (numberp (setq prev-from (car prev-cell)))
2279 (numberp (setq prev-to (cdr prev-cell)))
c567ac01 2280 ; Below threshold:
fd5359c6 2281 (> allout-undo-aggregation (- prev-to prev-from)))
19b84ba3
RS
2282 (setq buffer-undo-list
2283 (cons (cons prev-from cur-to)
2284 (cdr (cdr (cdr buffer-undo-list))))))))
2285 ;; Implement -post-goto-bullet, if set: (must be after undo business)
fd5359c6
MR
2286 (if (and allout-post-goto-bullet
2287 (allout-current-bullet-pos))
2288 (progn (goto-char (allout-current-bullet-pos))
2289 (setq allout-post-goto-bullet nil)))
19b84ba3 2290 ))
fd5359c6
MR
2291;;;_ > allout-pre-command-business ()
2292(defun allout-pre-command-business ()
2265e017 2293 "Outline `pre-command-hook' function for outline buffers.
58edceeb 2294Implements special behavior when cursor is on bullet character.
c567ac01 2295
58edceeb
JB
2296When the cursor is on the bullet character, self-insert characters are
2297reinterpreted as the corresponding control-character in the
2298`allout-mode-map'. The `allout-mode' `post-command-hook' insures that
2299the cursor which has moved as a result of such reinterpretation is
2300positioned on the bullet character of the destination topic.
c567ac01 2301
9179616f
DL
2302The upshot is that you can get easy, single (ie, unmodified) key
2303outline maneuvering operations by positioning the cursor on the bullet
58edceeb
JB
2304char. When in this mode you can use regular cursor-positioning
2305command/keystrokes to relocate the cursor off of a bullet character to
2306return to regular interpretation of self-insert characters."
fd5359c6
MR
2307 (if (not (allout-mode-p))
2308 ;; Shouldn't be invoked if not in allout allout-mode, but just in case:
9179616f
DL
2309 nil
2310 ;; Register isearch status:
2311 (if (and (boundp 'isearch-mode) isearch-mode)
fd5359c6
MR
2312 (setq allout-pre-was-isearching t)
2313 (setq allout-pre-was-isearching nil))
9179616f
DL
2314 ;; Hot-spot navigation provisions:
2315 (if (and (eq this-command 'self-insert-command)
fd5359c6 2316 (eq (point)(allout-current-bullet-pos)))
9179616f
DL
2317 (let* ((this-key-num (cond
2318 ((numberp last-command-char)
2319 last-command-char)
4185451d 2320 ((fboundp 'char-to-int)
9179616f
DL
2321 (char-to-int last-command-char))
2322 (t 0)))
2323 mapped-binding)
2324 (if (zerop this-key-num)
2325 nil
c567ac01
RS
2326 ; Map upper-register literals
2327 ; to lower register:
9179616f
DL
2328 (if (<= 96 this-key-num)
2329 (setq this-key-num (- this-key-num 32)))
c567ac01 2330 ; Check if we have a literal:
9179616f
DL
2331 (if (and (<= 64 this-key-num)
2332 (>= 96 this-key-num))
2333 (setq mapped-binding
fd5359c6
MR
2334 (lookup-key 'allout-mode-map
2335 (concat allout-command-prefix
9179616f
DL
2336 (char-to-string (- this-key-num
2337 64))))))
2338 (if mapped-binding
fd5359c6 2339 (setq allout-post-goto-bullet t
9179616f 2340 this-command mapped-binding)))))))
fd5359c6
MR
2341;;;_ > allout-find-file-hook ()
2342(defun allout-find-file-hook ()
2265e017 2343 "Activate `allout-mode' when `allout-auto-activation' & `allout-layout' are non-nil.
fd5359c6
MR
2344
2345See `allout-init' for setup instructions."
2346 (if (and allout-auto-activation
2347 (not (allout-mode-p))
2348 allout-layout)
2349 (allout-mode t)))
2350;;;_ > allout-isearch-rectification
2351(defun allout-isearch-rectification ()
9179616f
DL
2352 "Rectify outline exposure before, during, or after isearch.
2353
2265e017 2354Called as part of `allout-post-command-business'."
9179616f 2355
4185451d 2356 (let ((isearching isearch-mode))
fd5359c6
MR
2357 (cond ((and isearching (not allout-pre-was-isearching))
2358 (allout-isearch-expose 'start))
2359 ((and isearching allout-pre-was-isearching)
2360 (allout-isearch-expose 'continue))
2361 ((and (not isearching) allout-pre-was-isearching)
2362 (allout-isearch-expose 'final))
9179616f 2363 ;; Not and wasn't isearching:
4185451d 2364 (t (setq allout-isearch-prior-pos nil)))))
fd5359c6
MR
2365;;;_ = allout-isearch-was-font-lock
2366(defvar allout-isearch-was-font-lock
9179616f 2367 (and (boundp 'font-lock-mode) font-lock-mode))
12435002 2368
fd5359c6
MR
2369;;;_ > allout-flag-region (from to flag)
2370(defmacro allout-flag-region (from to flag)
539d7736 2371 "Hide or show lines from FROM to TO, via Emacs `selective-display' FLAG char.
12435002
GM
2372Ie, text following flag C-m \(carriage-return) is hidden until the
2373next C-j (newline) char.
2374
2375Returns the endpoint of the region."
2376 `(let ((buffer-read-only nil)
fd5359c6 2377 (allout-override-protect t))
12435002
GM
2378 (subst-char-in-region ,from ,to
2379 (if (= ,flag ?\n) ?\r ?\n)
2380 ,flag t)))
2381
fd5359c6
MR
2382;;;_ > allout-isearch-expose (mode)
2383(defun allout-isearch-expose (mode)
e126900f 2384 "MODE is either 'clear, 'start, 'continue, or 'final."
fd5359c6 2385 ;; allout-isearch-prior-pos encodes exposure status of prior pos:
9179616f
DL
2386 ;; (pos was-vis header-pos end-pos)
2387 ;; pos - point of concern
2388 ;; was-vis - t, else 'topic if entire topic was exposed, 'entry otherwise
2389 ;; Do reclosure or prior pos, as necessary:
2390 (if (eq mode 'start)
fd5359c6 2391 (setq allout-isearch-was-font-lock (and (boundp 'font-lock-mode)
9179616f
DL
2392 font-lock-mode)
2393 font-lock-mode nil)
2394 (if (eq mode 'final)
fd5359c6
MR
2395 (setq font-lock-mode allout-isearch-was-font-lock))
2396 (if (and allout-isearch-prior-pos
2397 (listp allout-isearch-prior-pos))
9179616f 2398 ;; Conceal prior peek:
fd5359c6
MR
2399 (allout-flag-region (car (cdr allout-isearch-prior-pos))
2400 (car (cdr (cdr allout-isearch-prior-pos)))
9179616f 2401 ?\r)))
fd5359c6
MR
2402 (if (allout-visible-p)
2403 (setq allout-isearch-prior-pos nil)
9179616f 2404 (if (not (eq mode 'final))
fd5359c6 2405 (setq allout-isearch-prior-pos (cons (point) (allout-show-entry)))
40987d96 2406 (if isearch-mode-end-hook-quit
9179616f 2407 nil
fd5359c6 2408 (setq allout-isearch-prior-pos nil)
4185451d 2409 (allout-show-children)))))
fd5359c6
MR
2410;;;_ > allout-enwrap-isearch ()
2411(defun allout-enwrap-isearch ()
539d7736 2412 "Impose `isearch-abort' wrapper for dynamic exposure in isearch.
9179616f
DL
2413
2414The function checks to ensure that the rebinding is done only once."
4185451d 2415 (add-hook 'isearch-mode-end-hook 'allout-isearch-rectification))
9179616f
DL
2416
2417;;; Prevent unnecessary font-lock while isearching!
2418(defvar isearch-was-font-locking nil)
2419(defun isearch-inhibit-font-lock ()
aad94676 2420 "Inhibit `font-lock-mode' while isearching - for use on `isearch-mode-hook'."
fd5359c6 2421 (if (and (allout-mode-p) (boundp 'font-lock-mode) font-lock-mode)
9179616f
DL
2422 (setq isearch-was-font-locking t
2423 font-lock-mode nil)))
2424(add-hook 'isearch-mode-hook 'isearch-inhibit-font-lock)
2425(defun isearch-reenable-font-lock ()
539d7736 2426 "Reenable font-lock after isearching - for use on `isearch-mode-end-hook'."
9179616f 2427 (if (and (boundp 'font-lock-mode) font-lock-mode)
fd5359c6 2428 (if (and (allout-mode-p) isearch-was-font-locking)
9179616f
DL
2429 (setq isearch-was-font-locking nil
2430 font-lock-mode t))))
2431(add-hook 'isearch-mode-end-hook 'isearch-reenable-font-lock)
c567ac01
RS
2432
2433;;;_ - Topic Format Assessment
fd5359c6
MR
2434;;;_ > allout-solicit-alternate-bullet (depth &optional current-bullet)
2435(defun allout-solicit-alternate-bullet (depth &optional current-bullet)
1977b8f6 2436
19b84ba3
RS
2437 "Prompt for and return a bullet char as an alternative to the current one.
2438
2439Offer one suitable for current depth DEPTH as default."
1977b8f6 2440
9179616f 2441 (let* ((default-bullet (or (and (stringp current-bullet) current-bullet)
fd5359c6
MR
2442 (allout-bullet-for-depth depth)))
2443 (sans-escapes (regexp-sans-escapes allout-bullets-string))
9179616f
DL
2444 choice)
2445 (save-excursion
fd5359c6 2446 (goto-char (allout-current-bullet-pos))
9179616f
DL
2447 (setq choice (solicit-char-in-string
2448 (format "Select bullet: %s ('%s' default): "
2449 sans-escapes
2450 default-bullet)
2451 sans-escapes
2452 t)))
2453 (message "")
1977b8f6
RS
2454 (if (string= choice "") default-bullet choice))
2455 )
fd5359c6
MR
2456;;;_ > allout-distinctive-bullet (bullet)
2457(defun allout-distinctive-bullet (bullet)
e126900f 2458 "True if BULLET is one of those on `allout-distinctive-bullets-string'."
fd5359c6
MR
2459 (string-match (regexp-quote bullet) allout-distinctive-bullets-string))
2460;;;_ > allout-numbered-type-prefix (&optional prefix)
2461(defun allout-numbered-type-prefix (&optional prefix)
c567ac01 2462 "True if current header prefix bullet is numbered bullet."
fd5359c6
MR
2463 (and allout-numbered-bullet
2464 (string= allout-numbered-bullet
1977b8f6 2465 (if prefix
fd5359c6
MR
2466 (allout-get-prefix-bullet prefix)
2467 (allout-get-bullet)))))
2468;;;_ > allout-bullet-for-depth (&optional depth)
2469(defun allout-bullet-for-depth (&optional depth)
19b84ba3 2470 "Return outline topic bullet suited to optional DEPTH, or current depth."
1977b8f6 2471 ;; Find bullet in plain-bullets-string modulo DEPTH.
fd5359c6
MR
2472 (if allout-stylish-prefixes
2473 (char-to-string (aref allout-plain-bullets-string
1977b8f6 2474 (% (max 0 (- depth 2))
fd5359c6
MR
2475 allout-plain-bullets-string-len)))
2476 allout-primary-bullet)
1977b8f6
RS
2477 )
2478
c567ac01 2479;;;_ - Topic Production
fd5359c6
MR
2480;;;_ > allout-make-topic-prefix (&optional prior-bullet
2481(defun allout-make-topic-prefix (&optional prior-bullet
1977b8f6
RS
2482 new
2483 depth
2484 solicit
2485 number-control
2486 index)
2487 ;; Depth null means use current depth, non-null means we're either
2488 ;; opening a new topic after current topic, lower or higher, or we're
2489 ;; changing level of current topic.
2490 ;; Solicit dominates specified bullet-char.
c567ac01 2491;;;_ . Doc string:
19b84ba3 2492 "Generate a topic prefix suitable for optional arg DEPTH, or current depth.
c567ac01
RS
2493
2494All the arguments are optional.
2495
2496PRIOR-BULLET indicates the bullet of the prefix being changed, or
2497nil if none. This bullet may be preserved (other options
2265e017 2498notwithstanding) if it is on the `allout-distinctive-bullets-string',
c567ac01
RS
2499for instance.
2500
2501Second arg NEW indicates that a new topic is being opened after the
2502topic at point, if non-nil. Default bullet for new topics, eg, may
2503be set (contingent to other args) to numbered bullets if previous
2504sibling is one. The implication otherwise is that the current topic
2505is being adjusted - shifted or rebulleted - and we don't consider
2506bullet or previous sibling.
2507
2508Third arg DEPTH forces the topic prefix to that depth, regardless of
2509the current topics' depth.
2510
9179616f
DL
2511If SOLICIT is non-nil, then the choice of bullet is solicited from
2512user. If it's a character, then that character is offered as the
2513default, otherwise the one suited to the context \(according to
2514distinction or depth) is offered. \(This overrides other options,
2515including, eg, a distinctive PRIOR-BULLET.) If non-nil, then the
2516context-specific bullet is used.
c567ac01 2517
fd5359c6 2518Fifth arg, NUMBER-CONTROL, matters only if `allout-numbered-bullet'
c567ac01
RS
2519is non-nil *and* soliciting was not explicitly invoked. Then
2520NUMBER-CONTROL non-nil forces prefix to either numbered or
2521denumbered format, depending on the value of the sixth arg, INDEX.
2522
2523\(Note that NUMBER-CONTROL does *not* apply to level 1 topics. Sorry...)
2524
2525If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
2526the prefix of the topic is forced to be numbered. Non-nil
2527NUMBER-CONTROL and nil INDEX forces non-numbered format on the
2528bullet. Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
2529that the index for the numbered prefix will be derived, by counting
2530siblings back to start of level. If INDEX is a number, then that
2531number is used as the index for the numbered prefix (allowing, eg,
a0776d6b 2532sequential renumbering to not require this function counting back the
c567ac01
RS
2533index for each successive sibling)."
2534;;;_ . Code:
1977b8f6
RS
2535 ;; The options are ordered in likely frequence of use, most common
2536 ;; highest, least lowest. Ie, more likely to be doing prefix
2537 ;; adjustments than soliciting, and yet more than numbering.
2538 ;; Current prefix is least dominant, but most likely to be commonly
2539 ;; specified...
2540
2541 (let* (body
2542 numbering
2543 denumbering
fd5359c6
MR
2544 (depth (or depth (allout-depth)))
2545 (header-lead allout-header-prefix)
1977b8f6
RS
2546 (bullet-char
2547
2548 ;; Getting value for bullet char is practically the whole job:
2549
2550 (cond
2551 ; Simplest situation - level 1:
fd5359c6 2552 ((<= depth 1) (setq header-lead "") allout-primary-bullet)
1977b8f6 2553 ; Simple, too: all asterisks:
fd5359c6 2554 (allout-old-style-prefixes
1977b8f6
RS
2555 ;; Cheat - make body the whole thing, null out header-lead and
2556 ;; bullet-char:
2557 (setq body (make-string depth
fd5359c6 2558 (string-to-char allout-primary-bullet)))
1977b8f6
RS
2559 (setq header-lead "")
2560 "")
2561
2562 ;; (Neither level 1 nor old-style, so we're space padding.
2563 ;; Sneak it in the condition of the next case, whatever it is.)
2564
2565 ;; Solicitation overrides numbering and other cases:
2566 ((progn (setq body (make-string (- depth 2) ?\ ))
2567 ;; The actual condition:
2568 solicit)
fd5359c6 2569 (let* ((got (allout-solicit-alternate-bullet depth solicit)))
1977b8f6 2570 ;; Gotta check whether we're numbering and got a numbered bullet:
fd5359c6 2571 (setq numbering (and allout-numbered-bullet
1977b8f6 2572 (not (and number-control (not index)))
fd5359c6 2573 (string= got allout-numbered-bullet)))
1977b8f6
RS
2574 ;; Now return what we got, regardless:
2575 got))
2576
2577 ;; Numbering invoked through args:
fd5359c6 2578 ((and allout-numbered-bullet number-control)
1977b8f6 2579 (if (setq numbering (not (setq denumbering (not index))))
fd5359c6 2580 allout-numbered-bullet
19b84ba3 2581 (if (and prior-bullet
fd5359c6 2582 (not (string= allout-numbered-bullet
19b84ba3
RS
2583 prior-bullet)))
2584 prior-bullet
fd5359c6 2585 (allout-bullet-for-depth depth))))
1977b8f6
RS
2586
2587 ;;; Neither soliciting nor controlled numbering ;;;
2588 ;;; (may be controlled denumbering, tho) ;;;
2589
2590 ;; Check wrt previous sibling:
2591 ((and new ; only check for new prefixes
fd5359c6
MR
2592 (<= depth (allout-depth))
2593 allout-numbered-bullet ; ... & numbering enabled
1977b8f6
RS
2594 (not denumbering)
2595 (let ((sibling-bullet
2596 (save-excursion
2597 ;; Locate correct sibling:
fd5359c6
MR
2598 (or (>= depth (allout-depth))
2599 (allout-ascend-to-depth depth))
2600 (allout-get-bullet))))
1977b8f6 2601 (if (and sibling-bullet
fd5359c6 2602 (string= allout-numbered-bullet sibling-bullet))
1977b8f6
RS
2603 (setq numbering sibling-bullet)))))
2604
2605 ;; Distinctive prior bullet?
2606 ((and prior-bullet
fd5359c6 2607 (allout-distinctive-bullet prior-bullet)
1977b8f6 2608 ;; Either non-numbered:
fd5359c6
MR
2609 (or (not (and allout-numbered-bullet
2610 (string= prior-bullet allout-numbered-bullet)))
1977b8f6
RS
2611 ;; or numbered, and not denumbering:
2612 (setq numbering (not denumbering)))
2613 ;; Here 'tis:
2614 prior-bullet))
2615
2616 ;; Else, standard bullet per depth:
fd5359c6 2617 ((allout-bullet-for-depth depth)))))
1977b8f6
RS
2618
2619 (concat header-lead
2620 body
2621 bullet-char
2622 (if numbering
2623 (format "%d" (cond ((and index (numberp index)) index)
fd5359c6
MR
2624 (new (1+ (allout-sibling-index depth)))
2625 ((allout-sibling-index))))))
1977b8f6
RS
2626 )
2627 )
539d7736
JB
2628;;;_ > allout-open-topic (relative-depth &optional before use-sib-bullet)
2629(defun allout-open-topic (relative-depth &optional before use-sib-bullet)
e126900f 2630 "Open a new topic at depth RELATIVE-DEPTH.
19b84ba3
RS
2631
2632New topic is situated after current one, unless optional flag BEFORE
2633is non-nil, or unless current line is complete empty (not even
2634whitespace), in which case open is done on current line.
c567ac01 2635
539d7736 2636If USE-SIB-BULLET is true, use the bullet of the prior sibling.
9179616f 2637
c567ac01
RS
2638Nuances:
2639
2640- Creation of new topics is with respect to the visible topic
2641 containing the cursor, regardless of intervening concealed ones.
2642
2643- New headers are generally created after/before the body of a
2644 topic. However, they are created right at cursor location if the
2645 cursor is on a blank line, even if that breaks the current topic
2646 body. This is intentional, to provide a simple means for
2647 deliberately dividing topic bodies.
2648
2649- Double spacing of topic lists is preserved. Also, the first
2650 level two topic is created double-spaced (and so would be
2651 subsequent siblings, if that's left intact). Otherwise,
2652 single-spacing is used.
2653
2654- Creation of sibling or nested topics is with respect to the topic
2655 you're starting from, even when creating backwards. This way you
2656 can easily create a sibling in front of the current topic without
a0776d6b 2657 having to go to its preceding sibling, and then open forward
c567ac01 2658 from there."
1977b8f6 2659
fd5359c6 2660 (let* ((depth (+ (allout-current-depth) relative-depth))
1977b8f6
RS
2661 (opening-on-blank (if (looking-at "^\$")
2662 (not (setq before nil))))
2663 opening-numbered ; Will get while computing ref-topic, below
9179616f
DL
2664 ref-depth ; Will get while computing ref-topic, below
2665 ref-bullet ; Will get while computing ref-topic, next
1977b8f6
RS
2666 (ref-topic (save-excursion
2667 (cond ((< relative-depth 0)
fd5359c6 2668 (allout-ascend-to-depth depth))
1977b8f6 2669 ((>= relative-depth 1) nil)
fd5359c6
MR
2670 (t (allout-back-to-current-heading)))
2671 (setq ref-depth (allout-recent-depth))
9179616f 2672 (setq ref-bullet
fd5359c6
MR
2673 (if (> allout-recent-prefix-end 1)
2674 (allout-recent-bullet)
9179616f 2675 ""))
1977b8f6
RS
2676 (setq opening-numbered
2677 (save-excursion
fd5359c6 2678 (and allout-numbered-bullet
1977b8f6 2679 (or (<= relative-depth 0)
fd5359c6
MR
2680 (allout-descend-to-depth depth))
2681 (if (allout-numbered-type-prefix)
2682 allout-numbered-bullet))))
1977b8f6
RS
2683 (point)))
2684 dbl-space
c567ac01 2685 doing-beginning)
1977b8f6
RS
2686
2687 (if (not opening-on-blank)
2688 ; Positioning and vertical
2689 ; padding - only if not
2690 ; opening-on-blank:
353e2ef2 2691 (progn
1977b8f6
RS
2692 (goto-char ref-topic)
2693 (setq dbl-space ; Determine double space action:
c567ac01
RS
2694 (or (and (<= relative-depth 0) ; not descending;
2695 (save-excursion
a0776d6b 2696 ;; at b-o-b or preceded by a blank line?
c567ac01
RS
2697 (or (> 0 (forward-line -1))
2698 (looking-at "^\\s-*$")
2699 (bobp)))
1977b8f6 2700 (save-excursion
c567ac01 2701 ;; succeeded by a blank line?
fd5359c6 2702 (allout-end-of-current-subtree)
c567ac01 2703 (bolp)))
1977b8f6
RS
2704 (and (= ref-depth 1)
2705 (or before
2706 (= depth 1)
2707 (save-excursion
2708 ;; Don't already have following
2709 ;; vertical padding:
fd5359c6 2710 (not (allout-pre-next-preface)))))))
1977b8f6
RS
2711
2712 ; Position to prior heading,
c567ac01
RS
2713 ; if inserting backwards, and
2714 ; not going outwards:
2715 (if (and before (>= relative-depth 0))
fd5359c6 2716 (progn (allout-back-to-current-heading)
1977b8f6 2717 (setq doing-beginning (bobp))
c567ac01 2718 (if (not (bobp))
fd5359c6 2719 (allout-previous-heading)))
c567ac01 2720 (if (and before (bobp))
fd5359c6 2721 (allout-unprotected (open-line 1))))
1977b8f6 2722
c567ac01 2723 (if (<= relative-depth 0)
1977b8f6
RS
2724 ;; Not going inwards, don't snug up:
2725 (if doing-beginning
fd5359c6 2726 (allout-unprotected (open-line (if dbl-space 2 1)))
c567ac01
RS
2727 (if before
2728 (progn (end-of-line)
fd5359c6 2729 (allout-pre-next-preface)
c567ac01
RS
2730 (while (= ?\r (following-char))
2731 (forward-char 1))
2732 (if (not (looking-at "^$"))
fd5359c6
MR
2733 (allout-unprotected (open-line 1))))
2734 (allout-end-of-current-subtree)))
1977b8f6
RS
2735 ;; Going inwards - double-space if first offspring is,
2736 ;; otherwise snug up.
2737 (end-of-line) ; So we skip any concealed progeny.
fd5359c6 2738 (allout-pre-next-preface)
1977b8f6
RS
2739 (if (bolp)
2740 ;; Blank lines between current header body and next
2741 ;; header - get to last substantive (non-white-space)
2742 ;; line in body:
2743 (re-search-backward "[^ \t\n]" nil t))
2744 (if (save-excursion
fd5359c6
MR
2745 (allout-next-heading)
2746 (if (> (allout-recent-depth) ref-depth)
1977b8f6
RS
2747 ;; This is an offspring.
2748 (progn (forward-line -1)
2749 (looking-at "^\\s-*$"))))
2750 (progn (forward-line 1)
fd5359c6 2751 (allout-unprotected (open-line 1))))
1977b8f6
RS
2752 (end-of-line))
2753 ;;(if doing-beginning (goto-char doing-beginning))
c567ac01
RS
2754 (if (not (bobp))
2755 (progn (if (and (not (> depth ref-depth))
2756 (not before))
fd5359c6 2757 (allout-unprotected (open-line 1))
c567ac01 2758 (if (> depth ref-depth)
fd5359c6 2759 (allout-unprotected (newline 1))
c567ac01 2760 (if dbl-space
fd5359c6 2761 (allout-unprotected (open-line 1))
c567ac01 2762 (if (not before)
fd5359c6 2763 (allout-unprotected (newline 1))))))
c567ac01 2764 (if dbl-space
fd5359c6 2765 (allout-unprotected (newline 1)))
c567ac01
RS
2766 (if (and (not (eobp))
2767 (not (bolp)))
2768 (forward-char 1))))
1977b8f6 2769 ))
fd5359c6 2770 (insert (concat (allout-make-topic-prefix opening-numbered
eac9cf5f
PJ
2771 t
2772 depth)
2773 " "))
1977b8f6
RS
2774
2775 ;;(if doing-beginning (save-excursion (newline (if dbl-space 2 1))))
2776
2777
539d7736 2778 (allout-rebullet-heading (and use-sib-bullet ref-bullet);;; solicit
9179616f
DL
2779 depth ;;; depth
2780 nil ;;; number-control
2781 nil ;;; index
1977b8f6
RS
2782 t) (end-of-line)
2783 )
2784 )
c567ac01
RS
2785;;;_ . open-topic contingencies
2786;;;_ ; base topic - one from which open was issued
2787;;;_ , beginning char
a0776d6b 2788;;;_ , amount of space before will be used, unless opening in place
c567ac01
RS
2789;;;_ , end char will be used, unless opening before (and it still may)
2790;;;_ ; absolute depth of new topic
2791;;;_ ! insert in place - overrides most stuff
2792;;;_ ; relative depth of new re base
2793;;;_ ; before or after base topic
2794;;;_ ; spacing around topic, if any, prior to new topic and at same depth
2795;;;_ ; buffer boundaries - special provisions for beginning and end ob
2796;;;_ ; level 1 topics have special provisions also - double space.
2797;;;_ ; location of new topic
fd5359c6
MR
2798;;;_ > allout-open-subtopic (arg)
2799(defun allout-open-subtopic (arg)
c567ac01
RS
2800 "Open new topic header at deeper level than the current one.
2801
2802Negative universal arg means to open deeper, but place the new topic
2803prior to the current one."
1977b8f6 2804 (interactive "p")
fd5359c6
MR
2805 (allout-open-topic 1 (> 0 arg)))
2806;;;_ > allout-open-sibtopic (arg)
2807(defun allout-open-sibtopic (arg)
19b84ba3
RS
2808 "Open new topic header at same level as the current one.
2809
9179616f
DL
2810Positive universal arg means to use the bullet of the prior sibling.
2811
19b84ba3 2812Negative universal arg means to place the new topic prior to the current
c567ac01 2813one."
1977b8f6 2814 (interactive "p")
fd5359c6
MR
2815 (allout-open-topic 0 (> 0 arg) (< 1 arg)))
2816;;;_ > allout-open-supertopic (arg)
2817(defun allout-open-supertopic (arg)
c567ac01 2818 "Open new topic header at shallower level than the current one.
19b84ba3 2819
c567ac01
RS
2820Negative universal arg means to open shallower, but place the new
2821topic prior to the current one."
1977b8f6
RS
2822
2823 (interactive "p")
fd5359c6 2824 (allout-open-topic -1 (> 0 arg)))
c567ac01
RS
2825
2826;;;_ - Outline Alteration
2827;;;_ : Topic Modification
fd5359c6
MR
2828;;;_ = allout-former-auto-filler
2829(defvar allout-former-auto-filler nil
2265e017 2830 "Name of modal fill function being wrapped by `allout-auto-fill'.")
fd5359c6
MR
2831;;;_ > allout-auto-fill ()
2832(defun allout-auto-fill ()
aad94676 2833 "`allout-mode' autofill function.
19b84ba3
RS
2834
2835Maintains outline hanging topic indentation if
fd5359c6
MR
2836`allout-use-hanging-indents' is set."
2837 (let ((fill-prefix (if allout-use-hanging-indents
c567ac01
RS
2838 ;; Check for topic header indentation:
2839 (save-excursion
2840 (beginning-of-line)
fd5359c6 2841 (if (looking-at allout-regexp)
c567ac01
RS
2842 ;; ... construct indentation to account for
2843 ;; length of topic prefix:
fd5359c6 2844 (make-string (progn (allout-end-of-prefix)
c567ac01
RS
2845 (current-column))
2846 ?\ ))))))
fd5359c6 2847 (if (or allout-former-auto-filler allout-use-hanging-indents)
c567ac01 2848 (do-auto-fill))))
fd5359c6
MR
2849;;;_ > allout-reindent-body (old-depth new-depth &optional number)
2850(defun allout-reindent-body (old-depth new-depth &optional number)
e126900f 2851 "Reindent body lines which were indented at OLD-DEPTH to NEW-DEPTH.
c567ac01
RS
2852
2853Optional arg NUMBER indicates numbering is being added, and it must
a0776d6b 2854be accommodated.
c567ac01
RS
2855
2856Note that refill of indented paragraphs is not done."
1977b8f6
RS
2857
2858 (save-excursion
fd5359c6 2859 (allout-end-of-prefix)
c567ac01
RS
2860 (let* ((new-margin (current-column))
2861 excess old-indent-begin old-indent-end
2862 curr-ind
2863 ;; We want the column where the header-prefix text started
2864 ;; *before* the prefix was changed, so we infer it relative
2865 ;; to the new margin and the shift in depth:
2866 (old-margin (+ old-depth (- new-margin new-depth))))
353e2ef2 2867
c567ac01 2868 ;; Process lines up to (but excluding) next topic header:
fd5359c6 2869 (allout-unprotected
c567ac01
RS
2870 (save-match-data
2871 (while
2872 (and (re-search-forward "[\n\r]\\(\\s-*\\)"
2873 nil
2874 t)
2875 ;; Register the indent data, before we reset the
353e2ef2 2876 ;; match data with a subsequent `looking-at':
c567ac01
RS
2877 (setq old-indent-begin (match-beginning 1)
2878 old-indent-end (match-end 1))
fd5359c6 2879 (not (looking-at allout-regexp)))
c567ac01
RS
2880 (if (> 0 (setq excess (- (current-column)
2881 old-margin)))
2882 ;; Text starts left of old margin - don't adjust:
2883 nil
2884 ;; Text was hanging at or right of old left margin -
2885 ;; reindent it, preserving its existing indentation
2886 ;; beyond the old margin:
2887 (delete-region old-indent-begin old-indent-end)
2888 (indent-to (+ new-margin excess)))))))))
fd5359c6
MR
2889;;;_ > allout-rebullet-current-heading (arg)
2890(defun allout-rebullet-current-heading (arg)
9179616f
DL
2891 "Solicit new bullet for current visible heading."
2892 (interactive "p")
2893 (let ((initial-col (current-column))
fd5359c6 2894 (on-bullet (eq (point)(allout-current-bullet-pos)))
9179616f
DL
2895 (backwards (if (< arg 0)
2896 (setq arg (* arg -1)))))
2897 (while (> arg 0)
fd5359c6
MR
2898 (save-excursion (allout-back-to-current-heading)
2899 (allout-end-of-prefix)
2900 (allout-rebullet-heading t ;;; solicit
9179616f
DL
2901 nil ;;; depth
2902 nil ;;; number-control
2903 nil ;;; index
2904 t)) ;;; do-successors
2905 (setq arg (1- arg))
2906 (if (<= arg 0)
2907 nil
2908 (setq initial-col nil) ; Override positioning back to init col
2909 (if (not backwards)
fd5359c6
MR
2910 (allout-next-visible-heading 1)
2911 (allout-goto-prefix)
2912 (allout-next-visible-heading -1))))
9179616f 2913 (message "Done.")
fd5359c6 2914 (cond (on-bullet (goto-char (allout-current-bullet-pos)))
9179616f 2915 (initial-col (move-to-column initial-col)))))
fd5359c6
MR
2916;;;_ > allout-rebullet-heading (&optional solicit ...)
2917(defun allout-rebullet-heading (&optional solicit
1977b8f6
RS
2918 new-depth
2919 number-control
2920 index
2921 do-successors)
2922
c567ac01 2923 "Adjust bullet of current topic prefix.
1977b8f6 2924
9179616f
DL
2925If SOLICIT is non-nil, then the choice of bullet is solicited from
2926user. If it's a character, then that character is offered as the
2927default, otherwise the one suited to the context \(according to
2928distinction or depth) is offered. If non-nil, then the
2929context-specific bullet is just used.
1977b8f6 2930
e126900f 2931Second arg NEW-DEPTH forces the topic prefix to that depth, regardless
9179616f 2932of the topic's current depth.
1977b8f6 2933
c567ac01 2934Third arg NUMBER-CONTROL can force the prefix to or away from
fd5359c6 2935numbered form. It has effect only if `allout-numbered-bullet' is
c567ac01
RS
2936non-nil and soliciting was not explicitly invoked (via first arg).
2937Its effect, numbering or denumbering, then depends on the setting
45435c0e 2938of the fourth arg, INDEX.
1977b8f6 2939
45435c0e 2940If NUMBER-CONTROL is non-nil and fourth arg INDEX is nil, then the
c567ac01
RS
2941prefix of the topic is forced to be non-numbered. Null index and
2942non-nil NUMBER-CONTROL forces denumbering. Non-nil INDEX (and
2943non-nil NUMBER-CONTROL) forces a numbered-prefix form. If non-nil
2944INDEX is a number, then that number is used for the numbered
2945prefix. Non-nil and non-number means that the index for the
2265e017 2946numbered prefix will be derived by `allout-make-topic-prefix'.
1977b8f6 2947
c567ac01
RS
2948Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
2949siblings.
1977b8f6 2950
fd5359c6
MR
2951Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
2952and `allout-numbered-bullet', which all affect the behavior of
c567ac01 2953this function."
1977b8f6 2954
fd5359c6 2955 (let* ((current-depth (allout-depth))
1977b8f6 2956 (new-depth (or new-depth current-depth))
fd5359c6
MR
2957 (mb allout-recent-prefix-beginning)
2958 (me allout-recent-prefix-end)
1977b8f6 2959 (current-bullet (buffer-substring (- me 1) me))
fd5359c6 2960 (new-prefix (allout-make-topic-prefix current-bullet
1977b8f6
RS
2961 nil
2962 new-depth
2963 solicit
2964 number-control
2965 index)))
2966
c567ac01 2967 ;; Is new one is identical to old?
1977b8f6
RS
2968 (if (and (= current-depth new-depth)
2969 (string= current-bullet
2970 (substring new-prefix (1- (length new-prefix)))))
c567ac01 2971 ;; Nothing to do:
1977b8f6
RS
2972 t
2973
2974 ;; New prefix probably different from old:
c567ac01 2975 ; get rid of old one:
fd5359c6 2976 (allout-unprotected (delete-region mb me))
1977b8f6 2977 (goto-char mb)
c567ac01
RS
2978 ; Dispense with number if
2979 ; numbered-bullet prefix:
fd5359c6
MR
2980 (if (and allout-numbered-bullet
2981 (string= allout-numbered-bullet current-bullet)
1977b8f6 2982 (looking-at "[0-9]+"))
fd5359c6 2983 (allout-unprotected
c567ac01 2984 (delete-region (match-beginning 0)(match-end 0))))
1977b8f6 2985
c567ac01 2986 ; Put in new prefix:
fd5359c6 2987 (allout-unprotected (insert new-prefix))
1977b8f6 2988
c567ac01 2989 ;; Reindent the body if elected and margin changed:
fd5359c6 2990 (if (and allout-reindent-bodies
c567ac01 2991 (not (= new-depth current-depth)))
fd5359c6 2992 (allout-reindent-body current-depth new-depth))
1977b8f6 2993
c567ac01
RS
2994 ;; Recursively rectify successive siblings of orig topic if
2995 ;; caller elected for it:
2996 (if do-successors
2997 (save-excursion
fd5359c6 2998 (while (allout-next-sibling new-depth nil)
c567ac01
RS
2999 (setq index
3000 (cond ((numberp index) (1+ index))
fd5359c6
MR
3001 ((not number-control) (allout-sibling-index))))
3002 (if (allout-numbered-type-prefix)
3003 (allout-rebullet-heading nil ;;; solicit
c567ac01
RS
3004 new-depth ;;; new-depth
3005 number-control;;; number-control
3006 index ;;; index
3007 nil))))) ;;;(dont!)do-successors
3008 ) ; (if (and (= current-depth new-depth)...))
fd5359c6 3009 ) ; let* ((current-depth (allout-depth))...)
c567ac01 3010 ) ; defun
fd5359c6
MR
3011;;;_ > allout-rebullet-topic (arg)
3012(defun allout-rebullet-topic (arg)
2265e017 3013 "Like `allout-rebullet-topic-grunt', but start from topic visible at point.
19b84ba3 3014
c567ac01 3015Descends into invisible as well as visible topics, however.
1977b8f6 3016
c567ac01 3017With repeat count, shift topic depth by that amount."
1977b8f6
RS
3018 (interactive "P")
3019 (let ((start-col (current-column))
3020 (was-eol (eolp)))
3021 (save-excursion
3022 ;; Normalize arg:
3023 (cond ((null arg) (setq arg 0))
3024 ((listp arg) (setq arg (car arg))))
3025 ;; Fill the user in, in case we're shifting a big topic:
3026 (if (not (zerop arg)) (message "Shifting..."))
fd5359c6
MR
3027 (allout-back-to-current-heading)
3028 (if (<= (+ (allout-recent-depth) arg) 0)
1977b8f6 3029 (error "Attempt to shift topic below level 1"))
fd5359c6 3030 (allout-rebullet-topic-grunt arg)
1977b8f6 3031 (if (not (zerop arg)) (message "Shifting... done.")))
c567ac01 3032 (move-to-column (max 0 (+ start-col arg)))))
fd5359c6
MR
3033;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...)
3034(defun allout-rebullet-topic-grunt (&optional relative-depth
1977b8f6
RS
3035 starting-depth
3036 starting-point
3037 index
3038 do-successors)
3039
c567ac01 3040 "Rebullet the topic at point, visible or invisible, and all
2265e017 3041contained subtopics. See `allout-rebullet-heading' for rebulleting
c567ac01 3042behavior.
1977b8f6 3043
e126900f 3044Arg RELATIVE-DEPTH means to shift the depth of the entire
c567ac01 3045topic that amount.
1977b8f6 3046
e126900f
JB
3047\(fn &optional RELATIVE-DEPTH)"
3048
3049 ;; All args except the first one are for internal recursive use by the
3050 ;; function itself.
1977b8f6
RS
3051
3052 (let* ((relative-depth (or relative-depth 0))
fd5359c6 3053 (new-depth (allout-depth))
1977b8f6
RS
3054 (starting-depth (or starting-depth new-depth))
3055 (on-starting-call (null starting-point))
3056 (index (or index
3057 ;; Leave index null on starting call, so rebullet-heading
3058 ;; calculates it at what might be new depth:
3059 (and (or (zerop relative-depth)
3060 (not on-starting-call))
fd5359c6 3061 (allout-sibling-index))))
1977b8f6
RS
3062 (moving-outwards (< 0 relative-depth))
3063 (starting-point (or starting-point (point))))
3064
3065 ;; Sanity check for excessive promotion done only on starting call:
3066 (and on-starting-call
3067 moving-outwards
3068 (> 0 (+ starting-depth relative-depth))
6a05d05f 3069 (error "Attempt to shift topic out beyond level 1")) ;;; ====>
1977b8f6
RS
3070
3071 (cond ((= starting-depth new-depth)
3072 ;; We're at depth to work on this one:
fd5359c6 3073 (allout-rebullet-heading nil ;;; solicit
1977b8f6
RS
3074 (+ starting-depth ;;; starting-depth
3075 relative-depth)
3076 nil ;;; number
3077 index ;;; index
3078 ;; Every contained topic will get hit,
3079 ;; and we have to get to outside ones
3080 ;; deliberately:
3081 nil) ;;; do-successors
3082 ;; ... and work on subsequent ones which are at greater depth:
3083 (setq index 0)
fd5359c6 3084 (allout-next-heading)
1977b8f6 3085 (while (and (not (eobp))
fd5359c6 3086 (< starting-depth (allout-recent-depth)))
1977b8f6 3087 (setq index (1+ index))
fd5359c6 3088 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
1977b8f6
RS
3089 (1+ starting-depth);;;starting-depth
3090 starting-point ;;; starting-point
3091 index))) ;;; index
3092
3093 ((< starting-depth new-depth)
3094 ;; Rare case - subtopic more than one level deeper than parent.
3095 ;; Treat this one at an even deeper level:
fd5359c6 3096 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
1977b8f6
RS
3097 new-depth ;;; starting-depth
3098 starting-point ;;; starting-point
3099 index))) ;;; index
3100
3101 (if on-starting-call
3102 (progn
3103 ;; Rectify numbering of former siblings of the adjusted topic,
3104 ;; if topic has changed depth
3105 (if (or do-successors
3106 (and (not (zerop relative-depth))
fd5359c6
MR
3107 (or (= (allout-recent-depth) starting-depth)
3108 (= (allout-recent-depth) (+ starting-depth
1977b8f6 3109 relative-depth)))))
fd5359c6 3110 (allout-rebullet-heading nil nil nil nil t))
1977b8f6
RS
3111 ;; Now rectify numbering of new siblings of the adjusted topic,
3112 ;; if depth has been changed:
3113 (progn (goto-char starting-point)
3114 (if (not (zerop relative-depth))
fd5359c6 3115 (allout-rebullet-heading nil nil nil nil t)))))
1977b8f6
RS
3116 )
3117 )
fd5359c6
MR
3118;;;_ > allout-renumber-to-depth (&optional depth)
3119(defun allout-renumber-to-depth (&optional depth)
19b84ba3
RS
3120 "Renumber siblings at current depth.
3121
3122Affects superior topics if optional arg DEPTH is less than current depth.
c567ac01
RS
3123
3124Returns final depth."
3125
3126 ;; Proceed by level, processing subsequent siblings on each,
3127 ;; ascending until we get shallower than the start depth:
3128
fd5359c6 3129 (let ((ascender (allout-depth))
9179616f 3130 was-eobp)
c567ac01 3131 (while (and (not (eobp))
fd5359c6
MR
3132 (allout-depth)
3133 (>= (allout-recent-depth) depth)
c567ac01
RS
3134 (>= ascender depth))
3135 ; Skip over all topics at
3136 ; lesser depths, which can not
3137 ; have been disturbed:
9179616f 3138 (while (and (not (setq was-eobp (eobp)))
fd5359c6
MR
3139 (> (allout-recent-depth) ascender))
3140 (allout-next-heading))
c567ac01 3141 ; Prime ascender for ascension:
fd5359c6
MR
3142 (setq ascender (1- (allout-recent-depth)))
3143 (if (>= (allout-recent-depth) depth)
3144 (allout-rebullet-heading nil ;;; solicit
c567ac01
RS
3145 nil ;;; depth
3146 nil ;;; number-control
3147 nil ;;; index
9179616f
DL
3148 t)) ;;; do-successors
3149 (if was-eobp (goto-char (point-max)))))
fd5359c6
MR
3150 (allout-recent-depth))
3151;;;_ > allout-number-siblings (&optional denumber)
3152(defun allout-number-siblings (&optional denumber)
c567ac01 3153 "Assign numbered topic prefix to this topic and its siblings.
1977b8f6 3154
c567ac01
RS
3155With universal argument, denumber - assign default bullet to this
3156topic and its siblings.
1977b8f6 3157
c567ac01
RS
3158With repeated universal argument (`^U^U'), solicit bullet for each
3159rebulleting each topic at this level."
1977b8f6
RS
3160
3161 (interactive "P")
3162
3163 (save-excursion
fd5359c6
MR
3164 (allout-back-to-current-heading)
3165 (allout-beginning-of-level)
3166 (let ((depth (allout-recent-depth))
c567ac01 3167 (index (if (not denumber) 1))
1977b8f6
RS
3168 (use-bullet (equal '(16) denumber))
3169 (more t))
3170 (while more
fd5359c6 3171 (allout-rebullet-heading use-bullet ;;; solicit
c567ac01 3172 depth ;;; depth
1977b8f6
RS
3173 t ;;; number-control
3174 index ;;; index
3175 nil) ;;; do-successors
3176 (if index (setq index (1+ index)))
fd5359c6
MR
3177 (setq more (allout-next-sibling depth nil))))))
3178;;;_ > allout-shift-in (arg)
3179(defun allout-shift-in (arg)
19b84ba3 3180 "Increase depth of current heading and any topics collapsed within it."
1977b8f6 3181 (interactive "p")
fd5359c6
MR
3182 (allout-rebullet-topic arg))
3183;;;_ > allout-shift-out (arg)
3184(defun allout-shift-out (arg)
19b84ba3 3185 "Decrease depth of current heading and any topics collapsed within it."
1977b8f6 3186 (interactive "p")
fd5359c6 3187 (allout-rebullet-topic (* arg -1)))
c567ac01 3188;;;_ : Surgery (kill-ring) functions with special provisions for outlines:
fd5359c6
MR
3189;;;_ > allout-kill-line (&optional arg)
3190(defun allout-kill-line (&optional arg)
c567ac01 3191 "Kill line, adjusting subsequent lines suitably for outline mode."
1977b8f6
RS
3192
3193 (interactive "*P")
fd5359c6
MR
3194 (if (not (and (allout-mode-p) ; active outline mode,
3195 allout-numbered-bullet ; numbers may need adjustment,
c567ac01 3196 (bolp) ; may be clipping topic head,
fd5359c6 3197 (looking-at allout-regexp))) ; are clipping topic head.
1977b8f6
RS
3198 ;; Above conditions do not obtain - just do a regular kill:
3199 (kill-line arg)
3200 ;; Ah, have to watch out for adjustments:
fd5359c6 3201 (let* ((depth (allout-depth)))
c567ac01 3202 ; Do the kill:
1977b8f6 3203 (kill-line arg)
c567ac01 3204 ; Provide some feedback:
1977b8f6
RS
3205 (sit-for 0)
3206 (save-excursion
c567ac01
RS
3207 ; Start with the topic
3208 ; following killed line:
fd5359c6
MR
3209 (if (not (looking-at allout-regexp))
3210 (allout-next-heading))
3211 (allout-renumber-to-depth depth)))))
3212;;;_ > allout-kill-topic ()
3213(defun allout-kill-topic ()
c567ac01
RS
3214 "Kill topic together with subtopics.
3215
3216Leaves primary topic's trailing vertical whitespace, if any."
1977b8f6
RS
3217
3218 ;; Some finagling is done to make complex topic kills appear faster
3219 ;; than they actually are. A redisplay is performed immediately
3220 ;; after the region is disposed of, though the renumbering process
3221 ;; has yet to be performed. This means that there may appear to be
3222 ;; a lag *after* the kill has been performed.
3223
3224 (interactive)
fd5359c6
MR
3225 (let* ((beg (prog1 (allout-back-to-current-heading)(beginning-of-line)))
3226 (depth (allout-recent-depth)))
3227 (allout-end-of-current-subtree)
1977b8f6 3228 (if (not (eobp))
c567ac01
RS
3229 (if (or (not (looking-at "^$"))
3230 ;; A blank line - cut it with this topic *unless* this
3231 ;; is the last topic at this level, in which case
3232 ;; we'll leave the blank line as part of the
3233 ;; containing topic:
3234 (save-excursion
fd5359c6
MR
3235 (and (allout-next-heading)
3236 (>= (allout-recent-depth) depth))))
c567ac01 3237 (forward-char 1)))
353e2ef2 3238
1977b8f6
RS
3239 (kill-region beg (point))
3240 (sit-for 0)
3241 (save-excursion
fd5359c6
MR
3242 (allout-renumber-to-depth depth))))
3243;;;_ > allout-yank-processing ()
3244(defun allout-yank-processing (&optional arg)
c567ac01 3245
aad94676 3246 "Incidental outline specific business to be done just after text yanks.
19b84ba3 3247
c567ac01 3248Does depth adjustment of yanked topics, when:
1977b8f6 3249
c567ac01
RS
32501 the stuff being yanked starts with a valid outline header prefix, and
32512 it is being yanked at the end of a line which consists of only a valid
1977b8f6
RS
3252 topic prefix.
3253
a0776d6b 3254Also, adjusts numbering of subsequent siblings when appropriate.
1977b8f6 3255
c567ac01
RS
3256Depth adjustment alters the depth of all the topics being yanked
3257the amount it takes to make the first topic have the depth of the
3258header into which it's being yanked.
1977b8f6 3259
c567ac01
RS
3260The point is left in front of yanked, adjusted topics, rather than
3261at the end (and vice-versa with the mark). Non-adjusted yanks,
aad94676 3262however, are left exactly like normal, not outline specific yanks."
c567ac01
RS
3263
3264 (interactive "*P")
3265 ; Get to beginning, leaving
3266 ; region around subject:
9179616f 3267 (if (< (my-mark-marker t) (point))
c567ac01
RS
3268 (exchange-point-and-mark))
3269 (let* ((subj-beg (point))
9179616f
DL
3270 (subj-end (my-mark-marker t))
3271 ;; 'resituate' if yanking an entire topic into topic header:
fd5359c6
MR
3272 (resituate (and (allout-e-o-prefix-p)
3273 (looking-at (concat "\\(" allout-regexp "\\)"))
3274 (allout-prefix-data (match-beginning 1)
c567ac01 3275 (match-end 1))))
353e2ef2 3276 ;; `rectify-numbering' if resituating (where several topics may
c567ac01
RS
3277 ;; be resituating) or yanking a topic into a topic slot (bol):
3278 (rectify-numbering (or resituate
fd5359c6 3279 (and (bolp) (looking-at allout-regexp)))))
c567ac01
RS
3280 (if resituate
3281 ; The yanked stuff is a topic:
3282 (let* ((prefix-len (- (match-end 1) subj-beg))
fd5359c6
MR
3283 (subj-depth (allout-recent-depth))
3284 (prefix-bullet (allout-recent-bullet))
c567ac01
RS
3285 (adjust-to-depth
3286 ;; Nil if adjustment unnecessary, otherwise depth to which
3287 ;; adjustment should be made:
3288 (save-excursion
3289 (and (goto-char subj-end)
3290 (eolp)
3291 (goto-char subj-beg)
fd5359c6 3292 (and (looking-at allout-regexp)
c567ac01
RS
3293 (progn
3294 (beginning-of-line)
3295 (not (= (point) subj-beg)))
fd5359c6
MR
3296 (looking-at allout-regexp)
3297 (allout-prefix-data (match-beginning 0)
c567ac01 3298 (match-end 0)))
fd5359c6 3299 (allout-recent-depth))))
c567ac01
RS
3300 done
3301 (more t))
fd5359c6 3302 (setq rectify-numbering allout-numbered-bullet)
c567ac01
RS
3303 (if adjust-to-depth
3304 ; Do the adjustment:
3305 (progn
3306 (message "... yanking") (sit-for 0)
3307 (save-restriction
3308 (narrow-to-region subj-beg subj-end)
3309 ; Trim off excessive blank
3310 ; line at end, if any:
3311 (goto-char (point-max))
3312 (if (looking-at "^$")
fd5359c6 3313 (allout-unprotected (delete-char -1)))
c567ac01
RS
3314 ; Work backwards, with each
3315 ; shallowest level,
3316 ; successively excluding the
3317 ; last processed topic from
3318 ; the narrow region:
3319 (while more
fd5359c6 3320 (allout-back-to-current-heading)
c567ac01 3321 ; go as high as we can in each bunch:
fd5359c6 3322 (while (allout-ascend-to-depth (1- (allout-depth))))
c567ac01 3323 (save-excursion
fd5359c6 3324 (allout-rebullet-topic-grunt (- adjust-to-depth
c567ac01 3325 subj-depth))
fd5359c6 3326 (allout-depth))
c567ac01
RS
3327 (if (setq more (not (bobp)))
3328 (progn (widen)
3329 (forward-char -1)
3330 (narrow-to-region subj-beg (point))))))
3331 (message "")
3332 ;; Preserve new bullet if it's a distinctive one, otherwise
3333 ;; use old one:
3334 (if (string-match (regexp-quote prefix-bullet)
fd5359c6 3335 allout-distinctive-bullets-string)
c567ac01
RS
3336 ; Delete from bullet of old to
3337 ; before bullet of new:
3338 (progn
3339 (beginning-of-line)
3340 (delete-region (point) subj-beg)
9179616f 3341 (set-marker (my-mark-marker t) subj-end)
c567ac01 3342 (goto-char subj-beg)
fd5359c6 3343 (allout-end-of-prefix))
c567ac01
RS
3344 ; Delete base subj prefix,
3345 ; leaving old one:
3346 (delete-region (point) (+ (point)
3347 prefix-len
3348 (- adjust-to-depth subj-depth)))
3349 ; and delete residual subj
3350 ; prefix digits and space:
3351 (while (looking-at "[0-9]") (delete-char 1))
3352 (if (looking-at " ") (delete-char 1))))
3353 (exchange-point-and-mark))))
3354 (if rectify-numbering
353e2ef2 3355 (progn
c567ac01
RS
3356 (save-excursion
3357 ; Give some preliminary feedback:
3358 (message "... reconciling numbers") (sit-for 0)
3359 ; ... and renumber, in case necessary:
3360 (goto-char subj-beg)
fd5359c6
MR
3361 (if (allout-goto-prefix)
3362 (allout-rebullet-heading nil ;;; solicit
3363 (allout-depth) ;;; depth
c567ac01
RS
3364 nil ;;; number-control
3365 nil ;;; index
3366 t))
3367 (message ""))))
3368 (if (not resituate)
3369 (exchange-point-and-mark))))
fd5359c6
MR
3370;;;_ > allout-yank (&optional arg)
3371(defun allout-yank (&optional arg)
aad94676 3372 "`allout-mode' yank, with depth and numbering adjustment of yanked topics.
19b84ba3 3373
a0776d6b 3374Non-topic yanks work no differently than normal yanks.
c567ac01
RS
3375
3376If a topic is being yanked into a bare topic prefix, the depth of the
3377yanked topic is adjusted to the depth of the topic prefix.
3378
2265e017 3379 1 we're yanking in an `allout-mode' buffer
c567ac01
RS
3380 2 the stuff being yanked starts with a valid outline header prefix, and
3381 3 it is being yanked at the end of a line which consists of only a valid
3382 topic prefix.
3383
3384If these conditions hold then the depth of the yanked topics are all
3385adjusted the amount it takes to make the first one at the depth of the
3386header into which it's being yanked.
3387
3388The point is left in front of yanked, adjusted topics, rather than
3389at the end (and vice-versa with the mark). Non-adjusted yanks,
3390however, (ones that don't qualify for adjustment) are handled
3391exactly like normal yanks.
3392
a0776d6b 3393Numbering of yanked topics, and the successive siblings at the depth
c567ac01
RS
3394into which they're being yanked, is adjusted.
3395
539d7736
JB
3396`allout-yank-pop' works with `allout-yank' just like normal `yank-pop'
3397works with normal `yank' in non-outline buffers."
1977b8f6
RS
3398
3399 (interactive "*P")
3400 (setq this-command 'yank)
c567ac01 3401 (yank arg)
fd5359c6
MR
3402 (if (allout-mode-p)
3403 (allout-yank-processing)))
3404;;;_ > allout-yank-pop (&optional arg)
3405(defun allout-yank-pop (&optional arg)
2265e017 3406 "Yank-pop like `allout-yank' when popping to bare outline prefixes.
19b84ba3
RS
3407
3408Adapts level of popped topics to level of fresh prefix.
c567ac01
RS
3409
3410Note - prefix changes to distinctive bullets will stick, if followed
3411by pops to non-distinctive yanks. Bug..."
1977b8f6
RS
3412
3413 (interactive "*p")
1977b8f6 3414 (setq this-command 'yank)
c567ac01 3415 (yank-pop arg)
fd5359c6
MR
3416 (if (allout-mode-p)
3417 (allout-yank-processing)))
1977b8f6 3418
c567ac01
RS
3419;;;_ - Specialty bullet functions
3420;;;_ : File Cross references
fd5359c6
MR
3421;;;_ > allout-resolve-xref ()
3422(defun allout-resolve-xref ()
19b84ba3
RS
3423 "Pop to file associated with current heading, if it has an xref bullet.
3424
fd5359c6 3425\(Works according to setting of `allout-file-xref-bullet')."
1977b8f6 3426 (interactive)
fd5359c6 3427 (if (not allout-file-xref-bullet)
1977b8f6 3428 (error
635ca796 3429 "Outline cross references disabled - no `allout-file-xref-bullet'")
fd5359c6 3430 (if (not (string= (allout-current-bullet) allout-file-xref-bullet))
635ca796 3431 (error "Current heading lacks cross-reference bullet `%s'"
fd5359c6 3432 allout-file-xref-bullet)
1977b8f6
RS
3433 (let (file-name)
3434 (save-excursion
fd5359c6 3435 (let* ((text-start allout-recent-prefix-end)
fa29cfef 3436 (heading-end (progn (end-of-line) (point))))
1977b8f6
RS
3437 (goto-char text-start)
3438 (setq file-name
3439 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t)
3440 (buffer-substring (match-beginning 1) (match-end 1))))))
3441 (setq file-name
3442 (if (not (= (aref file-name 0) ?:))
3443 (expand-file-name file-name)
353e2ef2 3444 ; A registry-files ref, strip the `:'
1977b8f6
RS
3445 ; and try to follow it:
3446 (let ((reg-ref (reference-registered-file
3447 (substring file-name 1) nil t)))
3448 (if reg-ref (car (cdr reg-ref))))))
3449 (if (or (file-exists-p file-name)
3450 (if (file-writable-p file-name)
3451 (y-or-n-p (format "%s not there, create one? "
3452 file-name))
3453 (error "%s not found and can't be created" file-name)))
3454 (condition-case failure
3455 (find-file-other-window file-name)
9179616f 3456 ('error failure))
1977b8f6
RS
3457 (error "%s not found" file-name))
3458 )
3459 )
3460 )
3461 )
19b84ba3 3462
9179616f 3463;;;_ #6 Exposure Control
c567ac01
RS
3464
3465;;;_ - Fundamental
fd5359c6
MR
3466;;;_ > allout-flag-current-subtree (flag)
3467(defun allout-flag-current-subtree (flag)
19b84ba3
RS
3468 "Hide or show subtree of currently-visible topic.
3469
fd5359c6 3470See `allout-flag-region' for more details."
19b84ba3 3471
c567ac01 3472 (save-excursion
fd5359c6
MR
3473 (allout-back-to-current-heading)
3474 (allout-flag-region (point)
3475 (progn (allout-end-of-current-subtree) (1- (point)))
19b84ba3 3476 flag)))
c567ac01 3477
c567ac01 3478;;;_ - Topic-specific
fd5359c6
MR
3479;;;_ > allout-show-entry ()
3480(defun allout-show-entry ()
3481 "Like `allout-show-current-entry', reveals entries nested in hidden topics.
c567ac01
RS
3482
3483This is a way to give restricted peek at a concealed locality without the
3484expense of exposing its context, but can leave the outline with aberrant
aad94676 3485exposure. `allout-hide-current-entry-completely' or `allout-show-to-offshoot'
c567ac01
RS
3486should be used after the peek to rectify the exposure."
3487
3488 (interactive)
3489 (save-excursion
9179616f
DL
3490 (let ((at (point))
3491 beg end)
fd5359c6 3492 (allout-goto-prefix)
9179616f
DL
3493 (setq beg (if (= (preceding-char) ?\r) (1- (point)) (point)))
3494 (re-search-forward "[\n\r]" nil t)
3495 (setq end (1- (if (< at (point))
3496 ;; We're on topic head line - show only it:
3497 (point)
3498 ;; or we're in body - include it:
fd5359c6
MR
3499 (max beg (or (allout-pre-next-preface) (point))))))
3500 (allout-flag-region beg end ?\n)
9179616f 3501 (list beg end))))
fd5359c6
MR
3502;;;_ > allout-show-children (&optional level strict)
3503(defun allout-show-children (&optional level strict)
c567ac01
RS
3504
3505 "If point is visible, show all direct subheadings of this heading.
19b84ba3 3506
2265e017 3507Otherwise, do `allout-show-to-offshoot', and then show subheadings.
c567ac01
RS
3508
3509Optional LEVEL specifies how many levels below the current level
3510should be shown, or all levels if t. Default is 1.
3511
3512Optional STRICT means don't resort to -show-to-offshoot, no matter
3513what. This is basically so -show-to-offshoot, which is called by
3514this function, can employ the pure offspring-revealing capabilities of
19b84ba3
RS
3515it.
3516
3517Returns point at end of subtree that was opened, if any. (May get a
3518point of non-opened subtree?)"
c567ac01
RS
3519
3520 (interactive "p")
19b84ba3
RS
3521 (let (max-pos)
3522 (if (and (not strict)
fd5359c6 3523 (allout-hidden-p))
c567ac01 3524
fd5359c6 3525 (progn (allout-show-to-offshoot) ; Point's concealed, open to
19b84ba3
RS
3526 ; expose it.
3527 ;; Then recurse, but with "strict" set so we don't
3528 ;; infinite regress:
fd5359c6 3529 (setq max-pos (allout-show-children level t)))
c567ac01 3530
19b84ba3
RS
3531 (save-excursion
3532 (save-restriction
3533 (let* ((start-pt (point))
fd5359c6
MR
3534 (chart (allout-chart-subtree (or level 1)))
3535 (to-reveal (allout-chart-to-reveal chart (or level 1))))
19b84ba3
RS
3536 (goto-char start-pt)
3537 (if (and strict (= (preceding-char) ?\r))
3538 ;; Concealed root would already have been taken care of,
3539 ;; unless strict was set.
9179616f 3540 (progn
fd5359c6
MR
3541 (allout-flag-region (point) (allout-snug-back) ?\n)
3542 (if allout-show-bodies
9179616f 3543 (progn (goto-char (car to-reveal))
fd5359c6 3544 (allout-show-current-entry)))))
19b84ba3
RS
3545 (while to-reveal
3546 (goto-char (car to-reveal))
fd5359c6
MR
3547 (allout-flag-region (point) (allout-snug-back) ?\n)
3548 (if allout-show-bodies
9179616f 3549 (progn (goto-char (car to-reveal))
fd5359c6 3550 (allout-show-current-entry)))
19b84ba3 3551 (setq to-reveal (cdr to-reveal)))))))))
fd5359c6
MR
3552;;;_ > allout-hide-point-reconcile ()
3553(defun allout-hide-reconcile ()
3554 "Like `allout-hide-current-entry'; hides completely if within hidden region.
c567ac01
RS
3555
3556Specifically intended for aberrant exposure states, like entries that were
2265e017 3557exposed by `allout-show-entry' but are within otherwise concealed regions."
c567ac01
RS
3558 (interactive)
3559 (save-excursion
fd5359c6
MR
3560 (allout-goto-prefix)
3561 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3562 (progn (allout-pre-next-preface)
c567ac01
RS
3563 (if (= ?\r (following-char))
3564 (point)
3565 (1- (point))))
3566 ?\r)))
fd5359c6
MR
3567;;;_ > allout-show-to-offshoot ()
3568(defun allout-show-to-offshoot ()
2265e017 3569 "Like `allout-show-entry', but reveals all concealed ancestors, as well.
c567ac01 3570
2265e017
MR
3571As with `allout-hide-current-entry-completely', useful for rectifying
3572aberrant exposure states produced by `allout-show-entry'."
c567ac01
RS
3573
3574 (interactive)
3575 (save-excursion
3576 (let ((orig-pt (point))
fd5359c6 3577 (orig-pref (allout-goto-prefix))
c567ac01
RS
3578 (last-at (point))
3579 bag-it)
3580 (while (or bag-it (= (preceding-char) ?\r))
3581 (beginning-of-line)
3582 (if (= last-at (setq last-at (point)))
3583 ;; Oops, we're not making any progress! Show the current
3584 ;; topic completely, and bag this try.
3585 (progn (beginning-of-line)
fd5359c6 3586 (allout-show-current-subtree)
c567ac01
RS
3587 (goto-char orig-pt)
3588 (setq bag-it t)
3589 (beep)
3590 (message "%s: %s"
fd5359c6 3591 "allout-show-to-offshoot: "
c567ac01 3592 "Aberrant nesting encountered.")))
fd5359c6 3593 (allout-show-children)
c567ac01 3594 (goto-char orig-pref))
19b84ba3 3595 (goto-char orig-pt)))
fd5359c6
MR
3596 (if (allout-hidden-p)
3597 (allout-show-entry)))
3598;;;_ > allout-hide-current-entry ()
3599(defun allout-hide-current-entry ()
c567ac01
RS
3600 "Hide the body directly following this heading."
3601 (interactive)
fd5359c6 3602 (allout-back-to-current-heading)
c567ac01 3603 (save-excursion
fd5359c6
MR
3604 (allout-flag-region (point)
3605 (progn (allout-end-of-current-entry) (point))
9179616f 3606 ?\r)))
fd5359c6
MR
3607;;;_ > allout-show-current-entry (&optional arg)
3608(defun allout-show-current-entry (&optional arg)
c567ac01 3609
19b84ba3 3610 "Show body following current heading, or hide the entry if repeat count."
c567ac01
RS
3611
3612 (interactive "P")
3613 (if arg
fd5359c6 3614 (allout-hide-current-entry)
c567ac01 3615 (save-excursion
fd5359c6
MR
3616 (allout-flag-region (point)
3617 (progn (allout-end-of-current-entry) (point))
19b84ba3 3618 ?\n))))
fd5359c6
MR
3619;;;_ > allout-hide-current-entry-completely ()
3620; ... allout-hide-current-entry-completely also for isearch dynamic exposure:
3621(defun allout-hide-current-entry-completely ()
2265e017 3622 "Like `allout-hide-current-entry', but conceal topic completely.
c567ac01
RS
3623
3624Specifically intended for aberrant exposure states, like entries that were
2265e017 3625exposed by `allout-show-entry' but are within otherwise concealed regions."
c567ac01
RS
3626 (interactive)
3627 (save-excursion
fd5359c6
MR
3628 (allout-goto-prefix)
3629 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3630 (progn (allout-pre-next-preface)
c567ac01
RS
3631 (if (= ?\r (following-char))
3632 (point)
3633 (1- (point))))
3634 ?\r)))
fd5359c6
MR
3635;;;_ > allout-show-current-subtree (&optional arg)
3636(defun allout-show-current-subtree (&optional arg)
19b84ba3 3637 "Show everything within the current topic. With a repeat-count,
353e2ef2 3638expose this topic and its siblings."
19b84ba3
RS
3639 (interactive "P")
3640 (save-excursion
fd5359c6 3641 (if (<= (allout-current-depth) 0)
19b84ba3 3642 ;; Outside any topics - try to get to the first:
fd5359c6 3643 (if (not (allout-next-heading))
6a05d05f 3644 (error "No topics")
19b84ba3
RS
3645 ;; got to first, outermost topic - set to expose it and siblings:
3646 (message "Above outermost topic - exposing all.")
fd5359c6 3647 (allout-flag-region (point-min)(point-max) ?\n))
19b84ba3 3648 (if (not arg)
fd5359c6
MR
3649 (allout-flag-current-subtree ?\n)
3650 (allout-beginning-of-level)
3651 (allout-expose-topic '(* :))))))
3652;;;_ > allout-hide-current-subtree (&optional just-close)
3653(defun allout-hide-current-subtree (&optional just-close)
19b84ba3 3654 "Close the current topic, or containing topic if this one is already closed.
c567ac01 3655
19b84ba3 3656If this topic is closed and it's a top level topic, close this topic
353e2ef2 3657and its siblings.
19b84ba3
RS
3658
3659If optional arg JUST-CLOSE is non-nil, do not treat the parent or
3660siblings, even if the target topic is already closed."
c567ac01
RS
3661
3662 (interactive)
19b84ba3
RS
3663 (let ((from (point))
3664 (orig-eol (progn (end-of-line)
fd5359c6 3665 (if (not (allout-goto-prefix))
6a05d05f 3666 (error "No topics found")
19b84ba3 3667 (end-of-line)(point)))))
fd5359c6 3668 (allout-flag-current-subtree ?\r)
19b84ba3
RS
3669 (goto-char from)
3670 (if (and (= orig-eol (progn (goto-char orig-eol)
3671 (end-of-line)
3672 (point)))
3673 (not just-close)
c567ac01 3674 ;; Structure didn't change - try hiding current level:
19b84ba3 3675 (goto-char from)
fd5359c6 3676 (if (allout-up-current-level 1 t)
19b84ba3
RS
3677 t
3678 (goto-char 0)
3679 (let ((msg
3680 "Top-level topic already closed - closing siblings..."))
3681 (message msg)
fd5359c6 3682 (allout-expose-topic '(0 :))
19b84ba3
RS
3683 (message (concat msg " Done.")))
3684 nil)
fd5359c6
MR
3685 (/= (allout-recent-depth) 0))
3686 (allout-hide-current-subtree))
19b84ba3 3687 (goto-char from)))
fd5359c6
MR
3688;;;_ > allout-show-current-branches ()
3689(defun allout-show-current-branches ()
c567ac01
RS
3690 "Show all subheadings of this heading, but not their bodies."
3691 (interactive)
3692 (beginning-of-line)
fd5359c6
MR
3693 (allout-show-children t))
3694;;;_ > allout-hide-current-leaves ()
3695(defun allout-hide-current-leaves ()
353e2ef2 3696 "Hide the bodies of the current topic and all its offspring."
c567ac01 3697 (interactive)
fd5359c6
MR
3698 (allout-back-to-current-heading)
3699 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
c567ac01
RS
3700 (point))))
3701
3702;;;_ - Region and beyond
fd5359c6
MR
3703;;;_ > allout-show-all ()
3704(defun allout-show-all ()
c567ac01
RS
3705 "Show all of the text in the buffer."
3706 (interactive)
19b84ba3 3707 (message "Exposing entire buffer...")
fd5359c6 3708 (allout-flag-region (point-min) (point-max) ?\n)
19b84ba3 3709 (message "Exposing entire buffer... Done."))
fd5359c6
MR
3710;;;_ > allout-hide-bodies ()
3711(defun allout-hide-bodies ()
c567ac01
RS
3712 "Hide all of buffer except headings."
3713 (interactive)
fd5359c6
MR
3714 (allout-hide-region-body (point-min) (point-max)))
3715;;;_ > allout-hide-region-body (start end)
3716(defun allout-hide-region-body (start end)
c567ac01
RS
3717 "Hide all body lines in the region, but not headings."
3718 (save-excursion
3719 (save-restriction
3720 (narrow-to-region start end)
3721 (goto-char (point-min))
3722 (while (not (eobp))
fd5359c6
MR
3723 (allout-flag-region (point)
3724 (progn (allout-pre-next-preface) (point)) ?\r)
c567ac01
RS
3725 (if (not (eobp))
3726 (forward-char
3727 (if (looking-at "[\n\r][\n\r]")
3728 2 1)))))))
c567ac01 3729
fd5359c6
MR
3730;;;_ > allout-expose-topic (spec)
3731(defun allout-expose-topic (spec)
19b84ba3 3732 "Apply exposure specs to successive outline topic items.
c567ac01 3733
fd5359c6
MR
3734Use the more convenient frontend, `allout-new-exposure', if you don't
3735need evaluation of the arguments, or even better, the `allout-layout'
19b84ba3
RS
3736variable-keyed mode-activation/auto-exposure feature of allout outline
3737mode. See the respective documentation strings for more details.
c567ac01
RS
3738
3739Cursor is left at start position.
3740
19b84ba3
RS
3741SPEC is either a number or a list.
3742
3743Successive specs on a list are applied to successive sibling topics.
c567ac01
RS
3744
3745A simple spec \(either a number, one of a few symbols, or the null
19b84ba3
RS
3746list) dictates the exposure for the corresponding topic.
3747
3748Non-null lists recursively designate exposure specs for respective
3749subtopics of the current topic.
c567ac01 3750
353e2ef2 3751The `:' repeat spec is used to specify exposure for any number of
19b84ba3 3752successive siblings, up to the trailing ones for which there are
353e2ef2 3753explicit specs following the `:'.
c567ac01
RS
3754
3755Simple (numeric and null-list) specs are interpreted as follows:
3756
19b84ba3
RS
3757 Numbers indicate the relative depth to open the corresponding topic.
3758 - negative numbers force the topic to be closed before opening to the
3759 absolute value of the number, so all siblings are open only to
3760 that level.
3761 - positive numbers open to the relative depth indicated by the
3762 number, but do not force already opened subtopics to be closed.
3763 - 0 means to close topic - hide all offspring.
353e2ef2 3764 : - `repeat'
c567ac01 3765 apply prior element to all siblings at current level, *up to*
353e2ef2 3766 those siblings that would be covered by specs following the `:'
c567ac01
RS
3767 on the list. Ie, apply to all topics at level but the last
3768 ones. \(Only first of multiple colons at same level is
3769 respected - subsequent ones are discarded.)
19b84ba3
RS
3770 * - completely opens the topic, including bodies.
3771 + - shows all the sub headers, but not the bodies
3772 - - exposes the body of the corresponding topic.
c567ac01
RS
3773
3774Examples:
fd5359c6 3775\(allout-expose-topic '(-1 : 0))
c567ac01
RS
3776 Close this and all following topics at current level, exposing
3777 only their immediate children, but close down the last topic
3778 at this current level completely.
fd5359c6 3779\(allout-expose-topic '(-1 () : 1 0))
c567ac01
RS
3780 Close current topic so only the immediate subtopics are shown;
3781 show the children in the second to last topic, and completely
3782 close the last one.
fd5359c6 3783\(allout-expose-topic '(-2 : -1 *))
c567ac01
RS
3784 Expose children and grandchildren of all topics at current
3785 level except the last two; expose children of the second to
3786 last and completely open the last one."
3787
3788 (interactive "xExposure spec: ")
19b84ba3
RS
3789 (if (not (listp spec))
3790 nil
fd5359c6 3791 (let ((depth (allout-depth))
19b84ba3
RS
3792 (max-pos 0)
3793 prev-elem curr-elem
3794 stay done
3795 snug-back
3796 )
3797 (while spec
3798 (setq prev-elem curr-elem
3799 curr-elem (car spec)
3800 spec (cdr spec))
3801 (cond ; Do current element:
3802 ((null curr-elem) nil)
3803 ((symbolp curr-elem)
fd5359c6
MR
3804 (cond ((eq curr-elem '*) (allout-show-current-subtree)
3805 (if (> allout-recent-end-of-subtree max-pos)
3806 (setq max-pos allout-recent-end-of-subtree)))
3807 ((eq curr-elem '+) (allout-show-current-branches)
3808 (if (> allout-recent-end-of-subtree max-pos)
3809 (setq max-pos allout-recent-end-of-subtree)))
3810 ((eq curr-elem '-) (allout-show-current-entry))
19b84ba3
RS
3811 ((eq curr-elem ':)
3812 (setq stay t)
353e2ef2 3813 ;; Expand the `repeat' spec to an explicit version,
19b84ba3
RS
3814 ;; w.r.t. remaining siblings:
3815 (let ((residue ; = # of sibs not covered by remaining spec
3816 ;; Dang - could be nice to make use of the chart, sigh:
fd5359c6 3817 (- (length (allout-chart-siblings))
19b84ba3
RS
3818 (length spec))))
3819 (if (< 0 residue)
3820 ;; Some residue - cover it with prev-elem:
3821 (setq spec (append (make-list residue prev-elem)
3822 spec)))))))
3823 ((numberp curr-elem)
fd5359c6
MR
3824 (if (and (>= 0 curr-elem) (allout-visible-p))
3825 (save-excursion (allout-hide-current-subtree t)
19b84ba3
RS
3826 (if (> 0 curr-elem)
3827 nil
fd5359c6 3828 (if (> allout-recent-end-of-subtree max-pos)
19b84ba3 3829 (setq max-pos
fd5359c6 3830 allout-recent-end-of-subtree)))))
19b84ba3 3831 (if (> (abs curr-elem) 0)
fd5359c6
MR
3832 (progn (allout-show-children (abs curr-elem))
3833 (if (> allout-recent-end-of-subtree max-pos)
3834 (setq max-pos allout-recent-end-of-subtree)))))
19b84ba3 3835 ((listp curr-elem)
fd5359c6
MR
3836 (if (allout-descend-to-depth (1+ depth))
3837 (let ((got (allout-expose-topic curr-elem)))
19b84ba3
RS
3838 (if (and got (> got max-pos)) (setq max-pos got))))))
3839 (cond (stay (setq stay nil))
3840 ((listp (car spec)) nil)
3841 ((> max-pos (point))
3842 ;; Capitalize on max-pos state to get us nearer next sibling:
3843 (progn (goto-char (min (point-max) max-pos))
fd5359c6
MR
3844 (allout-next-heading)))
3845 ((allout-next-sibling depth))))
19b84ba3 3846 max-pos)))
fd5359c6
MR
3847;;;_ > allout-old-expose-topic (spec &rest followers)
3848(defun allout-old-expose-topic (spec &rest followers)
e126900f 3849 "Dictate wholesale exposure scheme for current topic, according to SPEC.
c567ac01
RS
3850
3851SPEC is either a number or a list. Optional successive args
3852dictate exposure for subsequent siblings of current topic.
3853
3854A simple spec (either a number, a special symbol, or the null list)
3855dictates the overall exposure for a topic. Non null lists are
3856composite specs whose first element dictates the overall exposure for
3857a topic, with the subsequent elements in the list interpreted as specs
3858that dictate the exposure for the successive offspring of the topic.
3859
3860Simple (numeric and null-list) specs are interpreted as follows:
3861
3862 - Numbers indicate the relative depth to open the corresponding topic:
3863 - negative numbers force the topic to be close before opening to the
3864 absolute value of the number.
3865 - positive numbers just open to the relative depth indicated by the number.
3866 - 0 just closes
353e2ef2
KH
3867 - `*' completely opens the topic, including bodies.
3868 - `+' shows all the sub headers, but not the bodies
3869 - `-' exposes the body and immediate offspring of the corresponding topic.
c567ac01
RS
3870
3871If the spec is a list, the first element must be a number, which
3872dictates the exposure depth of the topic as a whole. Subsequent
3873elements of the list are nested SPECs, dictating the specific exposure
3874for the corresponding offspring of the topic.
3875
e126900f 3876Optional FOLLOWERS arguments dictate exposure for succeeding siblings."
c567ac01
RS
3877
3878 (interactive "xExposure spec: ")
fd5359c6 3879 (let ((depth (allout-current-depth))
c567ac01
RS
3880 done
3881 max-pos)
3882 (cond ((null spec) nil)
3883 ((symbolp spec)
fd5359c6
MR
3884 (if (eq spec '*) (allout-show-current-subtree))
3885 (if (eq spec '+) (allout-show-current-branches))
3886 (if (eq spec '-) (allout-show-current-entry)))
c567ac01
RS
3887 ((numberp spec)
3888 (if (>= 0 spec)
fd5359c6 3889 (save-excursion (allout-hide-current-subtree t)
c567ac01
RS
3890 (end-of-line)
3891 (if (or (not max-pos)
3892 (> (point) max-pos))
3893 (setq max-pos (point)))
3894 (if (> 0 spec)
3895 (setq spec (* -1 spec)))))
3896 (if (> spec 0)
fd5359c6 3897 (allout-show-children spec)))
c567ac01 3898 ((listp spec)
fd5359c6 3899 ;(let ((got (allout-old-expose-topic (car spec))))
c567ac01
RS
3900 ; (if (and got (or (not max-pos) (> got max-pos)))
3901 ; (setq max-pos got)))
fd5359c6 3902 (let ((new-depth (+ (allout-current-depth) 1))
c567ac01 3903 got)
fd5359c6 3904 (setq max-pos (allout-old-expose-topic (car spec)))
c567ac01
RS
3905 (setq spec (cdr spec))
3906 (if (and spec
fd5359c6
MR
3907 (allout-descend-to-depth new-depth)
3908 (not (allout-hidden-p)))
3909 (progn (setq got (apply 'allout-old-expose-topic spec))
c567ac01
RS
3910 (if (and got (or (not max-pos) (> got max-pos)))
3911 (setq max-pos got)))))))
3912 (while (and followers
3913 (progn (if (and max-pos (< (point) max-pos))
3914 (progn (goto-char max-pos)
3915 (setq max-pos nil)))
3916 (end-of-line)
fd5359c6
MR
3917 (allout-next-sibling depth)))
3918 (allout-old-expose-topic (car followers))
c567ac01
RS
3919 (setq followers (cdr followers)))
3920 max-pos))
e126900f
JB
3921(make-obsolete 'allout-old-expose-topic
3922 "use `allout-expose-topic' (with different schema format) instead."
3923 "19.23")
fd5359c6
MR
3924;;;_ > allout-new-exposure '()
3925(defmacro allout-new-exposure (&rest spec)
3926 "Literal frontend for `allout-expose-topic', doesn't evaluate arguments.
2265e017
MR
3927Some arguments that would need to be quoted in `allout-expose-topic'
3928need not be quoted in `allout-new-exposure'.
c567ac01
RS
3929
3930Cursor is left at start position.
3931
c567ac01 3932Examples:
bff05d9e 3933\(allout-new-exposure (-1 () () () 1) 0)
c567ac01
RS
3934 Close current topic at current level so only the immediate
3935 subtopics are shown, except also show the children of the
3936 third subtopic; and close the next topic at the current level.
bff05d9e 3937\(allout-new-exposure : -1 0)
c567ac01
RS
3938 Close all topics at current level to expose only their
3939 immediate children, except for the last topic at the current
353e2ef2 3940 level, in which even its immediate children are hidden.
bff05d9e 3941\(allout-new-exposure -2 : -1 *)
c567ac01
RS
3942 Expose children and grandchildren of first topic at current
3943 level, and expose children of subsequent topics at current
3944 level *except* for the last, which should be opened completely."
3945 (list 'save-excursion
fd5359c6
MR
3946 '(if (not (or (allout-goto-prefix)
3947 (allout-next-heading)))
3948 (error "allout-new-exposure: Can't find any outline topics"))
3949 (list 'allout-expose-topic (list 'quote spec))))
c567ac01 3950
9179616f 3951;;;_ #7 Systematic outline presentation - copying, printing, flattening
19b84ba3 3952
9179616f
DL
3953;;;_ - Mapping and processing of topics
3954;;;_ ( See also Subtree Charting, in Navigation code.)
fd5359c6
MR
3955;;;_ > allout-stringify-flat-index (flat-index)
3956(defun allout-stringify-flat-index (flat-index &optional context)
9179616f
DL
3957 "Convert list representing section/subsection/... to document string.
3958
3959Optional arg CONTEXT indicates interior levels to include."
3960 (let ((delim ".")
71296446 3961 result
9179616f
DL
3962 numstr
3963 (context-depth (or (and context 2) 1)))
3964 ;; Take care of the explicit context:
3965 (while (> context-depth 0)
3966 (setq numstr (int-to-string (car flat-index))
3967 flat-index (cdr flat-index)
3968 result (if flat-index
3969 (cons delim (cons numstr result))
3970 (cons numstr result))
3971 context-depth (if flat-index (1- context-depth) 0)))
3972 (setq delim " ")
3973 ;; Take care of the indentation:
3974 (if flat-index
3975 (progn
3976 (while flat-index
3977 (setq result
3978 (cons delim
3979 (cons (make-string
3980 (1+ (truncate (if (zerop (car flat-index))
3981 1
3982 (log10 (car flat-index)))))
3983 ? )
3984 result)))
3985 (setq flat-index (cdr flat-index)))
3986 ;; Dispose of single extra delim:
3987 (setq result (cdr result))))
3988 (apply 'concat result)))
fd5359c6
MR
3989;;;_ > allout-stringify-flat-index-plain (flat-index)
3990(defun allout-stringify-flat-index-plain (flat-index)
9179616f
DL
3991 "Convert list representing section/subsection/... to document string."
3992 (let ((delim ".")
3993 result)
3994 (while flat-index
3995 (setq result (cons (int-to-string (car flat-index))
3996 (if result
3997 (cons delim result))))
3998 (setq flat-index (cdr flat-index)))
3999 (apply 'concat result)))
fd5359c6
MR
4000;;;_ > allout-stringify-flat-index-indented (flat-index)
4001(defun allout-stringify-flat-index-indented (flat-index)
9179616f
DL
4002 "Convert list representing section/subsection/... to document string."
4003 (let ((delim ".")
71296446 4004 result
9179616f
DL
4005 numstr)
4006 ;; Take care of the explicit context:
4007 (setq numstr (int-to-string (car flat-index))
4008 flat-index (cdr flat-index)
4009 result (if flat-index
4010 (cons delim (cons numstr result))
4011 (cons numstr result)))
4012 (setq delim " ")
4013 ;; Take care of the indentation:
4014 (if flat-index
4015 (progn
4016 (while flat-index
4017 (setq result
4018 (cons delim
4019 (cons (make-string
4020 (1+ (truncate (if (zerop (car flat-index))
4021 1
4022 (log10 (car flat-index)))))
4023 ? )
4024 result)))
4025 (setq flat-index (cdr flat-index)))
4026 ;; Dispose of single extra delim:
4027 (setq result (cdr result))))
4028 (apply 'concat result)))
fd5359c6
MR
4029;;;_ > allout-listify-exposed (&optional start end format)
4030(defun allout-listify-exposed (&optional start end format)
19b84ba3 4031
9179616f 4032 "Produce a list representing exposed topics in current region.
c567ac01 4033
fd5359c6 4034This list can then be used by `allout-process-exposed' to manipulate
9179616f 4035the subject region.
353e2ef2 4036
9179616f 4037Optional START and END indicate bounds of region.
19b84ba3 4038
9179616f
DL
4039optional arg, FORMAT, designates an alternate presentation form for
4040the prefix:
c567ac01 4041
9179616f
DL
4042 list - Present prefix as numeric section.subsection..., starting with
4043 section indicated by the list, innermost nesting first.
4044 `indent' \(symbol) - Convert header prefixes to all white space,
4045 except for distinctive bullets.
c567ac01 4046
9179616f
DL
4047The elements of the list produced are lists that represents a topic
4048header and body. The elements of that list are:
c567ac01 4049
9179616f
DL
4050 - a number representing the depth of the topic,
4051 - a string representing the header-prefix, including trailing whitespace and
4052 bullet.
4053 - a string representing the bullet character,
4054 - and a series of strings, each containing one line of the exposed
4055 portion of the topic entry."
c567ac01 4056
9179616f
DL
4057 (interactive "r")
4058 (save-excursion
4059 (let*
4060 ;; state vars:
4061 (strings prefix pad result depth new-depth out gone-out bullet beg
4062 next done)
c567ac01 4063
9179616f
DL
4064 (goto-char start)
4065 (beginning-of-line)
4066 ;; Goto initial topic, and register preceeding stuff, if any:
fd5359c6 4067 (if (> (allout-goto-prefix) start)
9179616f
DL
4068 ;; First topic follows beginning point - register preliminary stuff:
4069 (setq result (list (list 0 "" nil
4070 (buffer-substring start (1- (point)))))))
4071 (while (and (not done)
4072 (not (eobp)) ; Loop until we've covered the region.
4073 (not (> (point) end)))
fd5359c6
MR
4074 (setq depth (allout-recent-depth) ; Current topics depth,
4075 bullet (allout-recent-bullet) ; ... bullet,
4076 prefix (allout-recent-prefix)
4077 beg (progn (allout-end-of-prefix t) (point))) ; and beginning.
9179616f 4078 (setq done ; The boundary for the current topic:
fd5359c6
MR
4079 (not (allout-next-visible-heading 1)))
4080 (setq new-depth (allout-recent-depth))
9179616f
DL
4081 (setq gone-out out
4082 out (< new-depth depth))
4083 (beginning-of-line)
4084 (setq next (point))
4085 (goto-char beg)
4086 (setq strings nil)
4087 (while (> next (point)) ; Get all the exposed text in
4088 (setq strings
4089 (cons (buffer-substring
4090 beg
4091 ;To hidden text or end of line:
4092 (progn
4093 (search-forward "\r"
4094 (save-excursion (end-of-line)
4095 (point))
4096 1)
4097 (if (= (preceding-char) ?\r)
4098 (1- (point))
4099 (point))))
4100 strings))
4101 (if (< (point) next) ; Resume from after hid text, if any.
4102 (forward-line 1))
4103 (setq beg (point)))
4104 ;; Accumulate list for this topic:
4105 (setq strings (nreverse strings))
4106 (setq result
4107 (cons
4108 (if format
4109 (let ((special (if (string-match
4110 (regexp-quote bullet)
fd5359c6 4111 allout-distinctive-bullets-string)
9179616f
DL
4112 bullet)))
4113 (cond ((listp format)
4114 (list depth
fd5359c6
MR
4115 (if allout-abbreviate-flattened-numbering
4116 (allout-stringify-flat-index format
9179616f 4117 gone-out)
fd5359c6 4118 (allout-stringify-flat-index-plain
9179616f
DL
4119 format))
4120 strings
4121 special))
4122 ((eq format 'indent)
4123 (if special
4124 (list depth
4125 (concat (make-string (1+ depth) ? )
4126 (substring prefix -1))
4127 strings)
4128 (list depth
4129 (make-string depth ? )
4130 strings)))
fd5359c6 4131 (t (error "allout-listify-exposed: %s %s"
9179616f
DL
4132 "invalid format" format))))
4133 (list depth prefix strings))
4134 result))
4135 ;; Reasses format, if any:
4136 (if (and format (listp format))
4137 (cond ((= new-depth depth)
4138 (setq format (cons (1+ (car format))
4139 (cdr format))))
4140 ((> new-depth depth) ; descending - assume by 1:
4141 (setq format (cons 1 format)))
4142 (t
4143 ; Pop the residue:
4144 (while (< new-depth depth)
4145 (setq format (cdr format))
4146 (setq depth (1- depth)))
4147 ; And increment the current one:
4148 (setq format
4149 (cons (1+ (or (car format)
4150 -1))
4151 (cdr format)))))))
4152 ;; Put the list with first at front, to last at back:
4153 (nreverse result))))
fd5359c6 4154;;;_ > allout-process-exposed (&optional func from to frombuf
9179616f 4155;;; tobuf format)
fd5359c6 4156(defun allout-process-exposed (&optional func from to frombuf tobuf
e126900f 4157 format start-num)
9179616f 4158 "Map function on exposed parts of current topic; results to another buffer.
353e2ef2 4159
e126900f 4160Apply FUNC to exposed portions FROM position TO position in buffer
9179616f
DL
4161FROMBUF to buffer TOBUF. Sixth optional arg, FORMAT, designates an
4162alternate presentation form:
c567ac01 4163
9179616f
DL
4164 `flat' - Present prefix as numeric section.subsection..., starting with
4165 section indicated by the start-num, innermost nesting first.
4166 X`flat-indented' - Prefix is like `flat' for first topic at each
4167 X level, but subsequent topics have only leaf topic
4168 X number, padded with blanks to line up with first.
4169 `indent' \(symbol) - Convert header prefixes to all white space,
4170 except for distinctive bullets.
c567ac01 4171
9179616f 4172Defaults:
e126900f 4173 FUNC: `allout-insert-listified'
9179616f
DL
4174 FROM: region start, if region active, else start of buffer
4175 TO: region end, if region active, else end of buffer
4176 FROMBUF: current buffer
4177 TOBUF: buffer name derived: \"*current-buffer-name exposed*\"
4178 FORMAT: nil"
4179
4180 ; Resolve arguments,
4181 ; defaulting if necessary:
fd5359c6 4182 (if (not func) (setq func 'allout-insert-listified))
9179616f
DL
4183 (if (not (and from to))
4184 (if (my-region-active-p)
4185 (setq from (region-beginning) to (region-end))
4186 (setq from (point-min) to (point-max))))
4187 (if frombuf
4188 (if (not (bufferp frombuf))
4189 ;; Specified but not a buffer - get it:
4190 (let ((got (get-buffer frombuf)))
4191 (if (not got)
fd5359c6 4192 (error (concat "allout-process-exposed: source buffer "
9179616f
DL
4193 frombuf
4194 " not found."))
4195 (setq frombuf got))))
4196 ;; not specified - default it:
4197 (setq frombuf (current-buffer)))
4198 (if tobuf
4199 (if (not (bufferp tobuf))
4200 (setq tobuf (get-buffer-create tobuf)))
4201 ;; not specified - default it:
4202 (setq tobuf (concat "*" (buffer-name frombuf) " exposed*")))
4203 (if (listp format)
4204 (nreverse format))
4205
4206 (let* ((listified
4207 (progn (set-buffer frombuf)
fd5359c6 4208 (allout-listify-exposed from to format))))
9179616f
DL
4209 (set-buffer tobuf)
4210 (mapcar func listified)
4211 (pop-to-buffer tobuf)))
4212
4213;;;_ - Copy exposed
fd5359c6
MR
4214;;;_ > allout-insert-listified (listified)
4215(defun allout-insert-listified (listified)
9179616f
DL
4216 "Insert contents of listified outline portion in current buffer.
4217
e126900f 4218LISTIFIED is a list representing each topic header and body:
9179616f
DL
4219
4220 \`(depth prefix text)'
4221
e126900f
JB
4222or
4223
4224 \`(depth prefix text bullet-plus)'
9179616f
DL
4225
4226If `bullet-plus' is specified, it is inserted just after the entire prefix."
4227 (setq listified (cdr listified))
4228 (let ((prefix (prog1
4229 (car listified)
4230 (setq listified (cdr listified))))
4231 (text (prog1
4232 (car listified)
4233 (setq listified (cdr listified))))
4234 (bullet-plus (car listified)))
eac9cf5f
PJ
4235 (insert prefix)
4236 (if bullet-plus (insert (concat " " bullet-plus)))
9179616f 4237 (while text
eac9cf5f 4238 (insert (car text))
9179616f 4239 (if (setq text (cdr text))
eac9cf5f
PJ
4240 (insert "\n")))
4241 (insert "\n")))
fd5359c6
MR
4242;;;_ > allout-copy-exposed-to-buffer (&optional arg tobuf format)
4243(defun allout-copy-exposed-to-buffer (&optional arg tobuf format)
9179616f
DL
4244 "Duplicate exposed portions of current outline to another buffer.
4245
4246Other buffer has current buffers name with \" exposed\" appended to it.
4247
4248With repeat count, copy the exposed parts of only the current topic.
4249
4250Optional second arg TOBUF is target buffer name.
4251
4252Optional third arg FORMAT, if non-nil, symbolically designates an
4253alternate presentation format for the outline:
4254
4255 `flat' - Convert topic header prefixes to numeric
4256 section.subsection... identifiers.
4257 `indent' - Convert header prefixes to all white space, except for
4258 distinctive bullets.
4259 `indent-flat' - The best of both - only the first of each level has
4260 the full path, the rest have only the section number
4261 of the leaf, preceded by the right amount of indentation."
c567ac01
RS
4262
4263 (interactive "P")
4264 (if (not tobuf)
4265 (setq tobuf (get-buffer-create (concat "*" (buffer-name) " exposed*"))))
4266 (let* ((start-pt (point))
fd5359c6
MR
4267 (beg (if arg (allout-back-to-current-heading) (point-min)))
4268 (end (if arg (allout-end-of-current-subtree) (point-max)))
9179616f
DL
4269 (buf (current-buffer))
4270 (start-list ()))
4271 (if (eq format 'flat)
4272 (setq format (if arg (save-excursion
4273 (goto-char beg)
fd5359c6 4274 (allout-topic-flat-index))
9179616f 4275 '(1))))
c567ac01 4276 (save-excursion (set-buffer tobuf)(erase-buffer))
fd5359c6 4277 (allout-process-exposed 'allout-insert-listified
c567ac01
RS
4278 beg
4279 end
4280 (current-buffer)
9179616f
DL
4281 tobuf
4282 format start-list)
c567ac01
RS
4283 (goto-char (point-min))
4284 (pop-to-buffer buf)
4285 (goto-char start-pt)))
fd5359c6
MR
4286;;;_ > allout-flatten-exposed-to-buffer (&optional arg tobuf)
4287(defun allout-flatten-exposed-to-buffer (&optional arg tobuf)
9179616f
DL
4288 "Present numeric outline of outline's exposed portions in another buffer.
4289
e126900f 4290The resulting outline is not compatible with outline mode - use
fd5359c6 4291`allout-copy-exposed-to-buffer' if you want that.
9179616f 4292
fd5359c6 4293Use `allout-indented-exposed-to-buffer' for indented presentation.
9179616f
DL
4294
4295With repeat count, copy the exposed portions of only current topic.
4296
e126900f 4297Other buffer has current buffer's name with \" exposed\" appended to
9179616f
DL
4298it, unless optional second arg TOBUF is specified, in which case it is
4299used verbatim."
4300 (interactive "P")
fd5359c6
MR
4301 (allout-copy-exposed-to-buffer arg tobuf 'flat))
4302;;;_ > allout-indented-exposed-to-buffer (&optional arg tobuf)
4303(defun allout-indented-exposed-to-buffer (&optional arg tobuf)
9179616f
DL
4304 "Present indented outline of outline's exposed portions in another buffer.
4305
e126900f 4306The resulting outline is not compatible with outline mode - use
fd5359c6 4307`allout-copy-exposed-to-buffer' if you want that.
9179616f 4308
fd5359c6 4309Use `allout-flatten-exposed-to-buffer' for numeric sectional presentation.
9179616f
DL
4310
4311With repeat count, copy the exposed portions of only current topic.
4312
e126900f 4313Other buffer has current buffer's name with \" exposed\" appended to
9179616f
DL
4314it, unless optional second arg TOBUF is specified, in which case it is
4315used verbatim."
4316 (interactive "P")
fd5359c6 4317 (allout-copy-exposed-to-buffer arg tobuf 'indent))
c567ac01
RS
4318
4319;;;_ - LaTeX formatting
e126900f
JB
4320;;;_ > allout-latex-verb-quote (string &optional flow)
4321(defun allout-latex-verb-quote (string &optional flow)
539d7736 4322 "Return copy of STRING for literal reproduction across LaTeX processing.
19b84ba3 4323Expresses the original characters \(including carriage returns) of the
539d7736 4324string across LaTeX processing."
9179616f
DL
4325 (mapconcat (function
4326 (lambda (char)
c567ac01
RS
4327 (cond ((memq char '(?\\ ?$ ?% ?# ?& ?{ ?} ?_ ?^ ?- ?*))
4328 (concat "\\char" (number-to-string char) "{}"))
4329 ((= char ?\n) "\\\\")
9179616f 4330 (t (char-to-string char)))))
e126900f 4331 string
c567ac01 4332 ""))
fd5359c6
MR
4333;;;_ > allout-latex-verbatim-quote-curr-line ()
4334(defun allout-latex-verbatim-quote-curr-line ()
539d7736 4335 "Express line for exact \(literal) representation across LaTeX processing.
19b84ba3
RS
4336
4337Adjust line contents so it is unaltered \(from the original line)
539d7736 4338across LaTeX processing, within the context of a `verbatim'
c567ac01
RS
4339environment. Leaves point at the end of the line."
4340 (beginning-of-line)
4341 (let ((beg (point))
4342 (end (progn (end-of-line)(point))))
4343 (goto-char beg)
4344 (while (re-search-forward "\\\\"
4345 ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#"
4346 end ; bounded by end-of-line
4347 1) ; no matches, move to end & return nil
4348 (goto-char (match-beginning 0))
eac9cf5f 4349 (insert "\\")
c567ac01
RS
4350 (setq end (1+ end))
4351 (goto-char (1+ (match-end 0))))))
e126900f
JB
4352;;;_ > allout-insert-latex-header (buffer)
4353(defun allout-insert-latex-header (buffer)
539d7736 4354 "Insert initial LaTeX commands at point in BUFFER."
c567ac01
RS
4355 ;; Much of this is being derived from the stuff in appendix of E in
4356 ;; the TeXBook, pg 421.
e126900f 4357 (set-buffer buffer)
c567ac01
RS
4358 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4359 "report"))
fd5359c6 4360 (page-numbering (if allout-number-pages
c567ac01
RS
4361 "\\pagestyle{empty}\n"
4362 ""))
4363 (linesdef (concat "\\def\\beginlines{"
4364 "\\par\\begingroup\\nobreak\\medskip"
4365 "\\parindent=0pt\n"
4366 " \\kern1pt\\nobreak \\obeylines \\obeyspaces "
4367 "\\everypar{\\strut}}\n"
4368 "\\def\\endlines{"
4369 "\\kern1pt\\endgroup\\medbreak\\noindent}\n"))
4370 (titlecmd (format "\\newcommand{\\titlecmd}[1]{{%s #1}}\n"
fd5359c6 4371 allout-title-style))
c567ac01 4372 (labelcmd (format "\\newcommand{\\labelcmd}[1]{{%s #1}}\n"
fd5359c6 4373 allout-label-style))
c567ac01 4374 (headlinecmd (format "\\newcommand{\\headlinecmd}[1]{{%s #1}}\n"
fd5359c6 4375 allout-head-line-style))
c567ac01 4376 (bodylinecmd (format "\\newcommand{\\bodylinecmd}[1]{{%s #1}}\n"
fd5359c6 4377 allout-body-line-style))
c567ac01
RS
4378 (setlength (format "%s%s%s%s"
4379 "\\newlength{\\stepsize}\n"
4380 "\\setlength{\\stepsize}{"
fd5359c6 4381 allout-indent
c567ac01
RS
4382 "}\n"))
4383 (oneheadline (format "%s%s%s%s%s%s%s"
4384 "\\newcommand{\\OneHeadLine}[3]{%\n"
4385 "\\noindent%\n"
4386 "\\hspace*{#2\\stepsize}%\n"
4387 "\\labelcmd{#1}\\hspace*{.2cm}"
4388 "\\headlinecmd{#3}\\\\["
fd5359c6 4389 allout-line-skip
c567ac01
RS
4390 "]\n}\n"))
4391 (onebodyline (format "%s%s%s%s%s%s"
4392 "\\newcommand{\\OneBodyLine}[2]{%\n"
4393 "\\noindent%\n"
4394 "\\hspace*{#1\\stepsize}%\n"
4395 "\\bodylinecmd{#2}\\\\["
fd5359c6 4396 allout-line-skip
c567ac01
RS
4397 "]\n}\n"))
4398 (begindoc "\\begin{document}\n\\begin{center}\n")
4399 (title (format "%s%s%s%s"
4400 "\\titlecmd{"
fd5359c6 4401 (allout-latex-verb-quote (if allout-title
c567ac01 4402 (condition-case err
fd5359c6 4403 (eval allout-title)
9179616f 4404 ('error "<unnamed buffer>"))
c567ac01
RS
4405 "Unnamed Outline"))
4406 "}\n"
4407 "\\end{center}\n\n"))
4408 (hsize "\\hsize = 7.5 true in\n")
4409 (hoffset "\\hoffset = -1.5 true in\n")
4410 (vspace "\\vspace{.1cm}\n\n"))
4411 (insert (concat doc-style
4412 page-numbering
4413 titlecmd
4414 labelcmd
4415 headlinecmd
4416 bodylinecmd
4417 setlength
4418 oneheadline
4419 onebodyline
4420 begindoc
4421 title
4422 hsize
4423 hoffset
4424 vspace)
4425 )))
e126900f
JB
4426;;;_ > allout-insert-latex-trailer (buffer)
4427(defun allout-insert-latex-trailer (buffer)
539d7736 4428 "Insert concluding LaTeX commands at point in BUFFER."
e126900f 4429 (set-buffer buffer)
c567ac01 4430 (insert "\n\\end{document}\n"))
fd5359c6
MR
4431;;;_ > allout-latexify-one-item (depth prefix bullet text)
4432(defun allout-latexify-one-item (depth prefix bullet text)
19b84ba3
RS
4433 "Insert LaTeX commands for formatting one outline item.
4434
9179616f 4435Args are the topics numeric DEPTH, the header PREFIX lead string, the
19b84ba3 4436BULLET string, and a list of TEXT strings for the body."
c567ac01
RS
4437 (let* ((head-line (if text (car text)))
4438 (body-lines (cdr text))
4439 (curr-line)
4440 body-content bop)
4441 ; Do the head line:
71296446 4442 (insert (concat "\\OneHeadLine{\\verb\1 "
fd5359c6 4443 (allout-latex-verb-quote bullet)
eac9cf5f
PJ
4444 "\1}{"
4445 depth
4446 "}{\\verb\1 "
4447 (if head-line
fd5359c6 4448 (allout-latex-verb-quote head-line)
eac9cf5f
PJ
4449 "")
4450 "\1}\n"))
c567ac01
RS
4451 (if (not body-lines)
4452 nil
eac9cf5f
PJ
4453 ;;(insert "\\beginlines\n")
4454 (insert "\\begin{verbatim}\n")
c567ac01
RS
4455 (while body-lines
4456 (setq curr-line (car body-lines))
4457 (if (and (not body-content)
4458 (not (string-match "^\\s-*$" curr-line)))
4459 (setq body-content t))
4460 ; Mangle any occurrences of
4461 ; "\end{verbatim}" in text,
4462 ; it's special:
4463 (if (and body-content
4464 (setq bop (string-match "\\end{verbatim}" curr-line)))
4465 (setq curr-line (concat (substring curr-line 0 bop)
4466 ">"
4467 (substring curr-line bop))))
eac9cf5f
PJ
4468 ;;(insert "|" (car body-lines) "|")
4469 (insert curr-line)
fd5359c6 4470 (allout-latex-verbatim-quote-curr-line)
eac9cf5f 4471 (insert "\n")
c567ac01
RS
4472 (setq body-lines (cdr body-lines)))
4473 (if body-content
4474 (setq body-content nil)
4475 (forward-char -1)
eac9cf5f 4476 (insert "\\ ")
c567ac01 4477 (forward-char 1))
eac9cf5f
PJ
4478 ;;(insert "\\endlines\n")
4479 (insert "\\end{verbatim}\n")
c567ac01 4480 )))
fd5359c6
MR
4481;;;_ > allout-latexify-exposed (arg &optional tobuf)
4482(defun allout-latexify-exposed (arg &optional tobuf)
539d7736 4483 "Format current topics exposed portions to TOBUF for LaTeX processing.
19b84ba3
RS
4484TOBUF defaults to a buffer named the same as the current buffer, but
4485with \"*\" prepended and \" latex-formed*\" appended.
c567ac01
RS
4486
4487With repeat count, copy the exposed portions of entire buffer."
4488
4489 (interactive "P")
4490 (if (not tobuf)
4491 (setq tobuf
4492 (get-buffer-create (concat "*" (buffer-name) " latexified*"))))
4493 (let* ((start-pt (point))
fd5359c6
MR
4494 (beg (if arg (point-min) (allout-back-to-current-heading)))
4495 (end (if arg (point-max) (allout-end-of-current-subtree)))
c567ac01
RS
4496 (buf (current-buffer)))
4497 (set-buffer tobuf)
1977b8f6 4498 (erase-buffer)
fd5359c6 4499 (allout-insert-latex-header tobuf)
c567ac01 4500 (goto-char (point-max))
fd5359c6 4501 (allout-process-exposed 'allout-latexify-one-item
c567ac01
RS
4502 beg
4503 end
4504 buf
4505 tobuf)
4506 (goto-char (point-max))
fd5359c6 4507 (allout-insert-latex-trailer tobuf)
1977b8f6 4508 (goto-char (point-min))
c567ac01
RS
4509 (pop-to-buffer buf)
4510 (goto-char start-pt)))
4511
9179616f 4512;;;_ #8 miscellaneous
fd5359c6
MR
4513;;;_ > allout-mark-topic ()
4514(defun allout-mark-topic ()
c567ac01
RS
4515 "Put the region around topic currently containing point."
4516 (interactive)
4517 (beginning-of-line)
fd5359c6 4518 (allout-goto-prefix)
c567ac01 4519 (push-mark (point))
fd5359c6 4520 (allout-end-of-current-subtree)
c567ac01
RS
4521 (exchange-point-and-mark))
4522;;;_ > outlineify-sticky ()
19b84ba3
RS
4523;; outlinify-sticky is correct spelling; provide this alias for sticklers:
4524(defalias 'outlinify-sticky 'outlineify-sticky)
c567ac01 4525(defun outlineify-sticky (&optional arg)
a0776d6b 4526 "Activate outline mode and establish file var so it is started subsequently.
1977b8f6 4527
fd5359c6 4528See doc-string for `allout-layout' and `allout-init' for details on
19b84ba3
RS
4529setup for auto-startup."
4530
4531 (interactive "P")
4532
fd5359c6 4533 (allout-mode t)
19b84ba3
RS
4534
4535 (save-excursion
4536 (goto-char (point-min))
fd5359c6 4537 (if (looking-at allout-regexp)
19b84ba3 4538 t
fd5359c6 4539 (allout-open-topic 2)
eac9cf5f 4540 (insert (concat "Dummy outline topic header - see"
fd5359c6 4541 "`allout-mode' docstring: `^Hm'."))
9179616f 4542 (forward-line 1)
1977b8f6 4543 (goto-char (point-max))
9179616f 4544 (open-line 1)
fd5359c6 4545 (allout-open-topic 0)
eac9cf5f 4546 (insert "Local emacs vars.\n")
fd5359c6
MR
4547 (allout-open-topic 1)
4548 (insert "(`allout-layout' is for allout.el allout-mode)\n")
4549 (allout-open-topic 0)
eac9cf5f 4550 (insert "Local variables:\n")
fd5359c6
MR
4551 (allout-open-topic 0)
4552 (insert (format "allout-layout: %s\n"
4553 (or allout-layout
9179616f 4554 '(-1 : 0))))
fd5359c6 4555 (allout-open-topic 0)
eac9cf5f 4556 (insert "End:\n"))))
c567ac01 4557;;;_ > solicit-char-in-string (prompt string &optional do-defaulting)
1977b8f6 4558(defun solicit-char-in-string (prompt string &optional do-defaulting)
c567ac01 4559 "Solicit (with first arg PROMPT) choice of a character from string STRING.
1977b8f6 4560
c567ac01 4561Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
1977b8f6
RS
4562
4563 (let ((new-prompt prompt)
4564 got)
4565
4566 (while (not got)
4567 (message "%s" new-prompt)
4568
4569 ;; We do our own reading here, so we can circumvent, eg, special
9179616f 4570 ;; treatment for `?' character. (Oughta use minibuffer keymap instead.)
1977b8f6 4571 (setq got
c567ac01 4572 (char-to-string (let ((cursor-in-echo-area nil)) (read-char))))
1977b8f6 4573
9179616f
DL
4574 (setq got
4575 (cond ((string-match (regexp-quote got) string) got)
4576 ((and do-defaulting (string= got "\r"))
4577 ;; Return empty string to default:
4578 "")
4579 ((string= got "\C-g") (signal 'quit nil))
4580 (t
4581 (setq new-prompt (concat prompt
4582 got
4583 " ...pick from: "
4584 string
4585 ""))
4586 nil))))
4587 ;; got something out of loop - return it:
4588 got)
1977b8f6 4589 )
c567ac01
RS
4590;;;_ > regexp-sans-escapes (string)
4591(defun regexp-sans-escapes (regexp &optional successive-backslashes)
4592 "Return a copy of REGEXP with all character escapes stripped out.
19b84ba3 4593
c567ac01
RS
4594Representations of actual backslashes - '\\\\\\\\' - are left as a
4595single backslash.
4596
539d7736
JB
4597\(fn REGEXP)"
4598;; Optional arg SUCCESSIVE-BACKSLASHES is used internally for recursion.
c567ac01
RS
4599
4600 (if (string= regexp "")
4601 ""
4602 ;; Set successive-backslashes to number if current char is
4603 ;; backslash, or else to nil:
4604 (setq successive-backslashes
4605 (if (= (aref regexp 0) ?\\)
4606 (if successive-backslashes (1+ successive-backslashes) 1)
4607 nil))
4608 (if (or (not successive-backslashes) (= 2 successive-backslashes))
4609 ;; Include first char:
4610 (concat (substring regexp 0 1)
4611 (regexp-sans-escapes (substring regexp 1)))
4612 ;; Exclude first char, but maintain count:
4613 (regexp-sans-escapes (substring regexp 1) successive-backslashes))))
9179616f
DL
4614;;;_ > my-region-active-p ()
4615(defmacro my-region-active-p ()
4616 (if (fboundp 'region-active-p)
4617 '(region-active-p)
4618 'mark-active))
19b84ba3 4619;;;_ - add-hook definition for divergent emacsen
c567ac01
RS
4620;;;_ > add-hook (hook function &optional append)
4621(if (not (fboundp 'add-hook))
4622 (defun add-hook (hook function &optional append)
19b84ba3 4623 "Add to the value of HOOK the function FUNCTION unless already present.
353e2ef2 4624\(It becomes the first hook on the list unless optional APPEND is non-nil, in
c567ac01
RS
4625which case it becomes the last). HOOK should be a symbol, and FUNCTION may be
4626any valid function. HOOK's value should be a list of functions, not a single
4627function. If HOOK is void, it is first set to nil."
4628 (or (boundp hook) (set hook nil))
4629 (or (if (consp function)
4630 ;; Clever way to tell whether a given lambda-expression
4631 ;; is equal to anything in the hook.
4632 (let ((tail (assoc (cdr function) (symbol-value hook))))
4633 (equal function tail))
4634 (memq function (symbol-value hook)))
353e2ef2 4635 (set hook
c567ac01
RS
4636 (if append
4637 (nconc (symbol-value hook) (list function))
4638 (cons function (symbol-value hook)))))))
76407938 4639;;;_ : my-mark-marker to accommodate divergent emacsen:
9179616f 4640(defun my-mark-marker (&optional force buffer)
539d7736 4641 "Accommodate the different signature for `mark-marker' across Emacsen.
9179616f 4642
e126900f 4643XEmacs takes two optional args, while GNU Emacs does not,
9179616f 4644so pass them along when appropriate."
9471aeec 4645 (if (featurep 'xemacs)
9179616f
DL
4646 (mark-marker force buffer)
4647 (mark-marker)))
c567ac01 4648
9179616f 4649;;;_ #9 Under development
fd5359c6
MR
4650;;;_ > allout-bullet-isearch (&optional bullet)
4651(defun allout-bullet-isearch (&optional bullet)
9179616f 4652 "Isearch \(regexp) for topic with bullet BULLET."
c567ac01
RS
4653 (interactive)
4654 (if (not bullet)
4655 (setq bullet (solicit-char-in-string
4656 "ISearch for topic with bullet: "
fd5359c6 4657 (regexp-sans-escapes allout-bullets-string))))
353e2ef2 4658
c567ac01
RS
4659 (let ((isearch-regexp t)
4660 (isearch-string (concat "^"
fd5359c6 4661 allout-header-prefix
c567ac01
RS
4662 "[ \t]*"
4663 bullet)))
4664 (isearch-repeat 'forward)
4665 (isearch-mode t)))
19b84ba3 4666;;;_ ? Re hooking up with isearch - use isearch-op-fun rather than
353e2ef2 4667;;; wrapping the isearch functions.
1977b8f6
RS
4668
4669;;;_* Local emacs vars.
fd5359c6 4670;;; The following `allout-layout' local variable setting:
19b84ba3
RS
4671;;; - closes all topics from the first topic to just before the third-to-last,
4672;;; - shows the children of the third to last (config vars)
4673;;; - and the second to last (code section),
4674;;; - and closes the last topic (this local-variables section).
4675;;;Local variables:
fd5359c6 4676;;;allout-layout: (0 : -1 -1 0)
19b84ba3
RS
4677;;;End:
4678
ab5796a9 4679;;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
6a05d05f 4680;;; allout.el ends here