2006-05-12 Ken Manheimer <ken.manheimer@gmail.com>
[bpt/emacs.git] / lisp / allout.el
CommitLineData
6a05d05f 1;;; allout.el --- extensive outline mode for use alone and with other modes
19b84ba3 2
0d30b337 3;; Copyright (C) 1992, 1993, 1994, 2001, 2002, 2003, 2004,
31468dcb 4;; 2005, 2006 Free Software Foundation, Inc.
1977b8f6 5
d82979ea
EZ
6;; Author: Ken Manheimer <ken dot manheimer at gmail dot com>
7;; Maintainer: Ken Manheimer <ken dot manheimer at gmail dot com>
c567ac01 8;; Created: Dec 1991 - first release to usenet
4034b0e2 9;; Version: 2.2.1
d82979ea 10;; Keywords: outlines wp languages
1977b8f6
RS
11
12;; This file is part of GNU Emacs.
13
59243403
RS
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
17;; any later version.
18
1977b8f6 19;; GNU Emacs is distributed in the hope that it will be useful,
59243403
RS
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
b578f267 25;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
26;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27;; Boston, MA 02110-1301, USA.
1977b8f6 28
6a05d05f 29;;; Commentary:
19b84ba3 30
96b83743
EZ
31;; Allout outline minor mode provides extensive outline formatting and
32;; and manipulation beyond standard emacs outline mode. Some features:
71296446 33;;
96b83743
EZ
34;; - Classic outline-mode topic-oriented navigation and exposure adjustment
35;; - Topic-oriented editing including coherent topic and subtopic
36;; creation, promotion, demotion, cut/paste across depths, etc.
37;; - Incremental search with dynamic exposure and reconcealment of text
38;; - Customizable bullet format - enables programming-language specific
39;; outlining, for code-folding editing. (Allout code itself is to try it;
40;; formatted as an outline - do ESC-x eval-current-buffer in allout.el; but
41;; emacs local file variables need to be enabled when the
42;; file was visited - see `enable-local-variables'.)
43;; - Configurable per-file initial exposure settings
44;; - Symmetric-key and key-pair topic encryption, plus symmetric passphrase
0949617b
EZ
45;; mnemonic support, with verification against an established passphrase
46;; (using a stashed encrypted dummy string) and user-supplied hint
96b83743
EZ
47;; maintenance. (See allout-toggle-current-subtree-encryption docstring.)
48;; - Automatic topic-number maintenance
49;; - "Hot-spot" operation, for single-keystroke maneuvering and
d82979ea 50;; exposure control (see the allout-mode docstring)
96b83743 51;; - Easy rendering of exposed portions into numbered, latex, indented, etc
d82979ea 52;; outline styles
96b83743
EZ
53;; - Careful attention to whitespace - enabling blank lines between items
54;; and maintenance of hanging indentation (in paragraph auto-fill and
55;; across topic promotion and demotion) of topic bodies consistent with
56;; indentation of their topic header.
71296446 57;;
d82979ea 58;; and more.
71296446 59;;
96b83743
EZ
60;; See the `allout-mode' function's docstring for an introduction to the
61;; mode. The development version and helpful notes are available at
62;; http://myriadicity.net/Sundry/EmacsAllout .
63;;
9179616f 64;; The outline menubar additions provide quick reference to many of
d82979ea
EZ
65;; the features, and see the docstring of the variable `allout-init'
66;; for instructions on priming your emacs session for automatic
67;; activation of allout-mode.
71296446 68;;
fd5359c6
MR
69;; See the docstring of the variables `allout-layout' and
70;; `allout-auto-activation' for details on automatic activation of
d82979ea 71;; `allout-mode' as a minor mode. (It has changed since allout
19b84ba3 72;; 3.x, for those of you that depend on the old method.)
c567ac01 73;;
353e2ef2
KH
74;; Note - the lines beginning with `;;;_' are outline topic headers.
75;; Just `ESC-x eval-current-buffer' to give it a whirl.
19b84ba3 76
d82979ea 77;; ken manheimer (ken dot manheimer at gmail dot com)
c567ac01 78
6a05d05f
PJ
79;;; Code:
80
d82979ea 81;;;_* Dependency autoloads
96b83743 82(require 'overlay)
0949617b 83(eval-when-compile (progn (require 'pgg)
69027dea 84 (require 'pgg-gpg)
96b83743 85 (require 'overlay)
69027dea 86 ))
d82979ea 87
19b84ba3 88;;;_* USER CUSTOMIZATION VARIABLES:
96b83743
EZ
89
90;;;_ > defgroup allout
4bef9110
SE
91(defgroup allout nil
92 "Extensive outline mode for use alone and with other modes."
fd5359c6 93 :prefix "allout-"
d82979ea 94 :group 'outlines)
19b84ba3
RS
95
96;;;_ + Layout, Mode, and Topic Header Configuration
97
fd5359c6
MR
98;;;_ = allout-auto-activation
99(defcustom allout-auto-activation nil
100 "*Regulates auto-activation modality of allout outlines - see `allout-init'.
19b84ba3 101
fd5359c6 102Setq-default by `allout-init' to regulate whether or not allout
19b84ba3 103outline mode is automatically activated when the buffer-specific
fd5359c6
MR
104variable `allout-layout' is non-nil, and whether or not the layout
105dictated by `allout-layout' should be imposed on mode activation.
19b84ba3 106
24190da5 107With value t, auto-mode-activation and auto-layout are enabled.
aad94676 108\(This also depends on `allout-find-file-hook' being installed in
95c12694 109`find-file-hook', which is also done by `allout-init'.)
19b84ba3
RS
110
111With value `ask', auto-mode-activation is enabled, and endorsement for
112performing auto-layout is asked of the user each time.
113
71296446 114With value `activate', only auto-mode-activation is enabled,
353e2ef2 115auto-layout is not.
19b84ba3 116
24190da5 117With value nil, neither auto-mode-activation nor auto-layout are
19b84ba3
RS
118enabled.
119
fd5359c6 120See the docstring for `allout-init' for the proper interface to
9179616f
DL
121this variable."
122 :type '(choice (const :tag "On" t)
123 (const :tag "Ask about layout" "ask")
124 (const :tag "Mode only" "activate")
125 (const :tag "Off" nil))
126 :group 'allout)
4034b0e2
LT
127;;;_ = allout-default-layout
128(defcustom allout-default-layout '(-2 : 0)
129 "*Default allout outline layout specification.
130
131This setting specifies the outline exposure to use when
132`allout-layout' has the local value `t'. This docstring describes the
133layout specifications.
134
135A list value specifies a default layout for the current buffer,
136to be applied upon activation of `allout-mode'. Any non-nil
137value will automatically trigger `allout-mode', provided
138`allout-init' has been called to enable this behavior.
139
140The types of elements in the layout specification are:
141
142 integer - dictate the relative depth to open the corresponding topic(s),
143 where:
144 - negative numbers force the topic to be closed before opening
145 to the absolute value of the number, so all siblings are open
146 only to that level.
147 - positive numbers open to the relative depth indicated by the
148 number, but do not force already opened subtopics to be closed.
149 - 0 means to close topic - hide all subitems.
150 : - repeat spec - apply the preceeding element to all siblings at
151 current level, *up to* those siblings that would be covered by specs
152 following the `:' on the list. Ie, apply to all topics at level but
153 trailing ones accounted for by trailing specs. \(Only the first of
154 multiple colons at the same level is honored - later ones are ignored.)
155 * - completely exposes the topic, including bodies
156 + - exposes all subtopics, but not the bodies
157 - - exposes the body of the corresponding topic, but not subtopics
158 list - a nested layout spec, to be applied intricately to its
159 corresponding item(s)
1977b8f6 160
4034b0e2
LT
161Examples:
162 '(-2 : 0)
163 Collapse the top-level topics to show their children and
164 grandchildren, but completely collapse the final top-level topic.
165 '(-1 () : 1 0)
166 Close the first topic so only the immediate subtopics are shown,
167 leave the subsequent topics exposed as they are until the second
168 second to last topic, which is exposed at least one level, and
169 completely close the last topic.
170 '(-2 : -1 *)
171 Expose children and grandchildren of all topics at current
172 level except the last two; expose children of the second to
173 last and completely expose the last one, including its subtopics.
19b84ba3 174
4034b0e2 175See `allout-expose-topic' for more about the exposure process.
19b84ba3 176
353e2ef2
KH
177Also, allout's mode-specific provisions will make topic prefixes default
178to the comment-start string, if any, of the language of the file. This
4034b0e2
LT
179is modulo the setting of `allout-use-mode-specific-leader', which see."
180 :type 'allout-layout-type
181 :group 'allout)
182;;;_ : allout-layout-type
183(define-widget 'allout-layout-type 'lazy
184 "Allout layout format customization basic building blocks."
185 :type '(repeat
186 (choice (integer :tag "integer (<= zero is strict)")
187 (const :tag ": (repeat prior)" :)
188 (const :tag "* (completely expose)" *)
189 (const :tag "+ (expose all offspring, headlines only)" +)
190 (const :tag "- (expose topic body but not offspring)" -)
191 (allout-layout-type :tag "<Nested layout>"))))
192
fd5359c6
MR
193;;;_ = allout-show-bodies
194(defcustom allout-show-bodies nil
9179616f
DL
195 "*If non-nil, show entire body when exposing a topic, rather than
196just the header."
197 :type 'boolean
198 :group 'allout)
fd5359c6 199(make-variable-buffer-local 'allout-show-bodies)
8570ce80
SM
200;;;###autoload
201(put 'allout-show-bodies 'safe-local-variable
202 (lambda (x) (member x '(t nil))))
1977b8f6 203
fd5359c6
MR
204;;;_ = allout-header-prefix
205(defcustom allout-header-prefix "."
19b84ba3
RS
206 "*Leading string which helps distinguish topic headers.
207
208Outline topic header lines are identified by a leading topic
c567ac01
RS
209header prefix, which mostly have the value of this var at their front.
210\(Level 1 topics are exceptions. They consist of only a single
2265e017 211character, which is typically set to the `allout-primary-bullet'. Many
4bef9110
SE
212outlines start at level 2 to avoid this discrepancy."
213 :type 'string
214 :group 'allout)
fd5359c6 215(make-variable-buffer-local 'allout-header-prefix)
8570ce80
SM
216;;;###autoload
217(put 'allout-header-prefix 'safe-local-variable 'stringp)
fd5359c6
MR
218;;;_ = allout-primary-bullet
219(defcustom allout-primary-bullet "*"
19b84ba3
RS
220 "Bullet used for top-level outline topics.
221
222Outline topic header lines are identified by a leading topic header
c567ac01 223prefix, which is concluded by bullets that includes the value of this
fd5359c6 224var and the respective allout-*-bullets-string vars.
c567ac01 225
353e2ef2 226The value of an asterisk (`*') provides for backwards compatibility
e126900f 227with the original Emacs outline mode. See `allout-plain-bullets-string'
2265e017 228and `allout-distinctive-bullets-string' for the range of available
4bef9110
SE
229bullets."
230 :type 'string
231 :group 'allout)
fd5359c6 232(make-variable-buffer-local 'allout-primary-bullet)
8570ce80
SM
233;;;###autoload
234(put 'allout-primary-bullet 'safe-local-variable 'stringp)
fd5359c6 235;;;_ = allout-plain-bullets-string
d82979ea 236(defcustom allout-plain-bullets-string ".,"
19b84ba3
RS
237 "*The bullets normally used in outline topic prefixes.
238
fd5359c6 239See `allout-distinctive-bullets-string' for the other kind of
c567ac01 240bullets.
1977b8f6 241
353e2ef2 242DO NOT include the close-square-bracket, `]', as a bullet.
1977b8f6 243
c567ac01 244Outline mode has to be reactivated in order for changes to the value
4bef9110
SE
245of this var to take effect."
246 :type 'string
247 :group 'allout)
fd5359c6 248(make-variable-buffer-local 'allout-plain-bullets-string)
8570ce80
SM
249;;;###autoload
250(put 'allout-plain-bullets-string 'safe-local-variable 'stringp)
fd5359c6 251;;;_ = allout-distinctive-bullets-string
d82979ea 252(defcustom allout-distinctive-bullets-string "*+-=>()[{}&!?#%\"X@$~_\\:;^"
19b84ba3 253 "*Persistent outline header bullets used to distinguish special topics.
1977b8f6 254
9179616f
DL
255These bullets are used to distinguish topics from the run-of-the-mill
256ones. They are not used in the standard topic headers created by
71296446 257the topic-opening, shifting, and rebulleting \(eg, on topic shift,
9179616f
DL
258topic paste, blanket rebulleting) routines, but are offered among the
259choices for rebulleting. They are not altered by the above automatic
260rebulleting, so they can be used to characterize topics, eg:
261
262 `?' question topics
263 `\(' parenthetic comment \(with a matching close paren inside)
264 `[' meta-note \(with a matching close ] inside)
d82979ea 265 `\"' a quotation
9179616f
DL
266 `=' value settings
267 `~' \"more or less\"
d82979ea 268 `^' see above
9179616f 269
d82979ea
EZ
270 ... for example. (`#' typically has a special meaning to the software,
271according to the value of `allout-numbered-bullet'.)
9179616f 272
fd5359c6 273See `allout-plain-bullets-string' for the selection of
9179616f 274alternating bullets.
1977b8f6 275
fd5359c6 276You must run `set-allout-regexp' in order for outline mode to
9179616f 277reconcile to changes of this value.
19b84ba3 278
353e2ef2 279DO NOT include the close-square-bracket, `]', on either of the bullet
4bef9110
SE
280strings."
281 :type 'string
282 :group 'allout)
fd5359c6 283(make-variable-buffer-local 'allout-distinctive-bullets-string)
8570ce80
SM
284;;;###autoload
285(put 'allout-distinctive-bullets-string 'safe-local-variable 'stringp)
1977b8f6 286
fd5359c6
MR
287;;;_ = allout-use-mode-specific-leader
288(defcustom allout-use-mode-specific-leader t
19b84ba3
RS
289 "*When non-nil, use mode-specific topic-header prefixes.
290
fd5359c6 291Allout outline mode will use the mode-specific `allout-mode-leaders'
19b84ba3 292and/or comment-start string, if any, to lead the topic prefix string,
353e2ef2 293so topic headers look like comments in the programming language.
19b84ba3
RS
294
295String values are used as they stand.
296
24190da5 297Value t means to first check for assoc value in `allout-mode-leaders'
19b84ba3 298alist, then use comment-start string, if any, then use default \(`.').
9179616f 299\(See note about use of comment-start strings, below.)
19b84ba3 300
fd5359c6 301Set to the symbol for either of `allout-mode-leaders' or
19b84ba3
RS
302`comment-start' to use only one of them, respectively.
303
6ed3e595 304Value nil means to always use the default \(`.').
19b84ba3
RS
305
306comment-start strings that do not end in spaces are tripled, and an
353e2ef2 307`_' underscore is tacked on the end, to distinguish them from regular
19b84ba3 308comment strings. comment-start strings that do end in spaces are not
9179616f 309tripled, but an underscore is substituted for the space. [This
19b84ba3 310presumes that the space is for appearance, not comment syntax. You
fd5359c6 311can use `allout-mode-leaders' to override this behavior, when
4bef9110 312incorrect.]"
71296446 313 :type '(choice (const t) (const nil) string
fd5359c6 314 (const allout-mode-leaders)
4bef9110
SE
315 (const comment-start))
316 :group 'allout)
8570ce80
SM
317;;;###autoload
318(put 'allout-use-mode-specific-leader 'safe-local-variable
319 (lambda (x) (or (member x '(t nil)) (stringp x))))
fd5359c6
MR
320;;;_ = allout-mode-leaders
321(defvar allout-mode-leaders '()
322 "Specific allout-prefix leading strings per major modes.
19b84ba3 323
9179616f 324Entries will be used instead or in lieu of mode-specific
fd5359c6 325comment-start strings. See also `allout-use-mode-specific-leader'.
19b84ba3
RS
326
327If you're constructing a string that will comment-out outline
328structuring so it can be included in program code, append an extra
329character, like an \"_\" underscore, to distinguish the lead string
330from regular comments that start at bol.")
331
fd5359c6
MR
332;;;_ = allout-old-style-prefixes
333(defcustom allout-old-style-prefixes nil
aad94676 334 "*When non-nil, use only old-and-crusty `outline-mode' `*' topic prefixes.
19b84ba3
RS
335
336Non-nil restricts the topic creation and modification
c567ac01 337functions to asterix-padded prefixes, so they look exactly
e126900f 338like the original Emacs-outline style prefixes.
1977b8f6 339
c567ac01 340Whatever the setting of this variable, both old and new style prefixes
4bef9110
SE
341are always respected by the topic maneuvering functions."
342 :type 'boolean
343 :group 'allout)
fd5359c6 344(make-variable-buffer-local 'allout-old-style-prefixes)
8570ce80
SM
345;;;###autoload
346(put 'allout-old-style-prefixes 'safe-local-variable
347 (lambda (x) (member x '(t nil))))
fd5359c6
MR
348;;;_ = allout-stylish-prefixes - alternating bullets
349(defcustom allout-stylish-prefixes t
19b84ba3 350 "*Do fancy stuff with topic prefix bullets according to level, etc.
c567ac01 351
19b84ba3
RS
352Non-nil enables topic creation, modification, and repositioning
353functions to vary the topic bullet char (the char that marks the topic
354depth) just preceding the start of the topic text) according to level.
353e2ef2 355Otherwise, only asterisks (`*') and distinctive bullets are used.
19b84ba3
RS
356
357This is how an outline can look (but sans indentation) with stylish
358prefixes:
c567ac01
RS
359
360 * Top level
361 .* A topic
362 . + One level 3 subtopic
363 . . One level 4 subtopic
19b84ba3 364 . . A second 4 subtopic
c567ac01 365 . + Another level 3 subtopic
19b84ba3
RS
366 . #1 A numbered level 4 subtopic
367 . #2 Another
368 . ! Another level 4 subtopic with a different distinctive bullet
369 . #4 And another numbered level 4 subtopic
c567ac01 370
19b84ba3
RS
371This would be an outline with stylish prefixes inhibited (but the
372numbered and other distinctive bullets retained):
c567ac01
RS
373
374 * Top level
375 .* A topic
19b84ba3
RS
376 . * One level 3 subtopic
377 . * One level 4 subtopic
378 . * A second 4 subtopic
379 . * Another level 3 subtopic
380 . #1 A numbered level 4 subtopic
381 . #2 Another
382 . ! Another level 4 subtopic with a different distinctive bullet
383 . #4 And another numbered level 4 subtopic
c567ac01
RS
384
385Stylish and constant prefixes (as well as old-style prefixes) are
386always respected by the topic maneuvering functions, regardless of
387this variable setting.
388
2265e017 389The setting of this var is not relevant when `allout-old-style-prefixes'
4bef9110
SE
390is non-nil."
391 :type 'boolean
392 :group 'allout)
fd5359c6 393(make-variable-buffer-local 'allout-stylish-prefixes)
8570ce80
SM
394;;;###autoload
395(put 'allout-stylish-prefixes 'safe-local-variable
396 (lambda (x) (member x '(t nil))))
1977b8f6 397
fd5359c6
MR
398;;;_ = allout-numbered-bullet
399(defcustom allout-numbered-bullet "#"
19b84ba3
RS
400 "*String designating bullet of topics that have auto-numbering; nil for none.
401
a0776d6b 402Topics having this bullet have automatic maintenance of a sibling
19b84ba3 403sequence-number tacked on, just after the bullet. Conventionally set
c567ac01 404to \"#\", you can set it to a bullet of your choice. A nil value
4bef9110
SE
405disables numbering maintenance."
406 :type '(choice (const nil) string)
407 :group 'allout)
fd5359c6 408(make-variable-buffer-local 'allout-numbered-bullet)
8570ce80
SM
409;;;###autoload
410(put 'allout-numbered-bullet 'safe-local-variable
411 (lambda (x) (or (not x) (stringp x))))
fd5359c6
MR
412;;;_ = allout-file-xref-bullet
413(defcustom allout-file-xref-bullet "@"
414 "*Bullet signifying file cross-references, for `allout-resolve-xref'.
19b84ba3 415
9179616f 416Set this var to the bullet you want to use for file cross-references."
4bef9110
SE
417 :type '(choice (const nil) string)
418 :group 'allout)
8570ce80
SM
419;;;###autoload
420(put 'allout-file-xref-bullet 'safe-local-variable
421 (lambda (x) (or (not x) (stringp x))))
fd5359c6
MR
422;;;_ = allout-presentation-padding
423(defcustom allout-presentation-padding 2
9179616f
DL
424 "*Presentation-format white-space padding factor, for greater indent."
425 :type 'integer
426 :group 'allout)
427
fd5359c6 428(make-variable-buffer-local 'allout-presentation-padding)
8570ce80
SM
429;;;###autoload
430(put 'allout-presentation-padding 'safe-local-variable 'integerp)
9179616f 431
fd5359c6
MR
432;;;_ = allout-abbreviate-flattened-numbering
433(defcustom allout-abbreviate-flattened-numbering nil
434 "*If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
9179616f
DL
435numbers to minimal amount with some context. Otherwise, entire
436numbers are always used."
437 :type 'boolean
438 :group 'allout)
439
c567ac01 440;;;_ + LaTeX formatting
fd5359c6
MR
441;;;_ - allout-number-pages
442(defcustom allout-number-pages nil
4bef9110
SE
443 "*Non-nil turns on page numbering for LaTeX formatting of an outline."
444 :type 'boolean
445 :group 'allout)
fd5359c6
MR
446;;;_ - allout-label-style
447(defcustom allout-label-style "\\large\\bf"
4bef9110
SE
448 "*Font and size of labels for LaTeX formatting of an outline."
449 :type 'string
450 :group 'allout)
fd5359c6
MR
451;;;_ - allout-head-line-style
452(defcustom allout-head-line-style "\\large\\sl "
4bef9110
SE
453 "*Font and size of entries for LaTeX formatting of an outline."
454 :type 'string
455 :group 'allout)
fd5359c6
MR
456;;;_ - allout-body-line-style
457(defcustom allout-body-line-style " "
4bef9110
SE
458 "*Font and size of entries for LaTeX formatting of an outline."
459 :type 'string
460 :group 'allout)
fd5359c6
MR
461;;;_ - allout-title-style
462(defcustom allout-title-style "\\Large\\bf"
4bef9110
SE
463 "*Font and size of titles for LaTeX formatting of an outline."
464 :type 'string
465 :group 'allout)
fd5359c6 466;;;_ - allout-title
d82979ea 467(defcustom allout-title '(or buffer-file-name (buffer-name))
c567ac01 468 "*Expression to be evaluated to determine the title for LaTeX
4bef9110
SE
469formatted copy."
470 :type 'sexp
471 :group 'allout)
fd5359c6
MR
472;;;_ - allout-line-skip
473(defcustom allout-line-skip ".05cm"
4bef9110
SE
474 "*Space between lines for LaTeX formatting of an outline."
475 :type 'string
476 :group 'allout)
fd5359c6
MR
477;;;_ - allout-indent
478(defcustom allout-indent ".3cm"
4bef9110
SE
479 "*LaTeX formatted depth-indent spacing."
480 :type 'string
481 :group 'allout)
c567ac01 482
d82979ea 483;;;_ + Topic encryption
8570ce80
SM
484;;;_ = allout-encryption group
485(defgroup allout-encryption nil
486 "Settings for topic encryption features of allout outliner."
487 :group 'allout)
d82979ea
EZ
488;;;_ = allout-topic-encryption-bullet
489(defcustom allout-topic-encryption-bullet "~"
490 "*Bullet signifying encryption of the entry's body."
491 :type '(choice (const nil) string)
8570ce80
SM
492 :version "22.0"
493 :group 'allout-encryption)
0949617b
EZ
494;;;_ = allout-passphrase-verifier-handling
495(defcustom allout-passphrase-verifier-handling t
496 "*Enable use of symmetric encryption passphrase verifier if non-nil.
d82979ea
EZ
497
498See the docstring for the `allout-enable-file-variable-adjustment'
499variable for details about allout ajustment of file variables."
0949617b 500 :type 'boolean
8570ce80
SM
501 :version "22.0"
502 :group 'allout-encryption)
0949617b
EZ
503(make-variable-buffer-local 'allout-passphrase-verifier-handling)
504;;;_ = allout-passphrase-hint-handling
505(defcustom allout-passphrase-hint-handling 'always
506 "*Dictate outline encryption passphrase reminder handling:
d82979ea
EZ
507
508 always - always show reminder when prompting
0949617b
EZ
509 needed - show reminder on passphrase entry failure
510 disabled - never present or adjust reminder
d82979ea
EZ
511
512See the docstring for the `allout-enable-file-variable-adjustment'
513variable for details about allout ajustment of file variables."
514 :type '(choice (const always)
515 (const needed)
d82979ea 516 (const disabled))
8570ce80
SM
517 :version "22.0"
518 :group 'allout-encryption)
0949617b 519(make-variable-buffer-local 'allout-passphrase-hint-handling)
d82979ea 520;;;_ = allout-encrypt-unencrypted-on-saves
96b83743 521(defcustom allout-encrypt-unencrypted-on-saves t
d82979ea
EZ
522 "*When saving, should topics pending encryption be encrypted?
523
524The idea is to prevent file-system exposure of any un-encrypted stuff, and
525mostly covers both deliberate file writes and auto-saves.
526
527 - Yes: encrypt all topics pending encryption, even if it's the one
528 currently being edited. \(In that case, the currently edited topic
529 will be automatically decrypted before any user interaction, so they
530 can continue editing but the copy on the file system will be
531 encrypted.)
532 Auto-saves will use the \"All except current topic\" mode if this
533 one is selected, to avoid practical difficulties - see below.
534 - All except current topic: skip the topic currently being edited, even if
535 it's pending encryption. This may expose the current topic on the
536 file sytem, but avoids the nuisance of prompts for the encryption
0949617b 537 passphrase in the middle of editing for, eg, autosaves.
d82979ea
EZ
538 This mode is used for auto-saves for both this option and \"Yes\".
539 - No: leave it to the user to encrypt any unencrypted topics.
540
541For practical reasons, auto-saves always use the 'except-current policy
0949617b
EZ
542when auto-encryption is enabled. \(Otherwise, spurious passphrase prompts
543and unavoidable timing collisions are too disruptive.) If security for a
544file requires that even the current topic is never auto-saved in the clear,
d82979ea
EZ
545disable auto-saves for that file."
546
547 :type '(choice (const :tag "Yes" t)
548 (const :tag "All except current topic" except-current)
549 (const :tag "No" nil))
8570ce80
SM
550 :version "22.0"
551 :group 'allout-encryption)
d82979ea
EZ
552(make-variable-buffer-local 'allout-encrypt-unencrypted-on-saves)
553
c567ac01
RS
554;;;_ + Miscellaneous customization
555
fd5359c6 556;;;_ = allout-command-prefix
96b83743
EZ
557(defcustom allout-command-prefix "\C-c "
558 "*Key sequence to be used as prefix for outline mode command key bindings.
559
560Default is '\C-c<space>'; just '\C-c' is more short-and-sweet, if you're
561willing to let allout use a bunch of \C-c keybindings."
9179616f
DL
562 :type 'string
563 :group 'allout)
564
fd5359c6
MR
565;;;_ = allout-keybindings-list
566;;; You have to reactivate allout-mode - `(allout-mode t)' - to
c567ac01 567;;; institute changes to this var.
fd5359c6 568(defvar allout-keybindings-list ()
2265e017 569 "*List of `allout-mode' key / function bindings, for `allout-mode-map'.
19b84ba3 570
2265e017 571String or vector key will be prefaced with `allout-command-prefix',
9179616f 572unless optional third, non-nil element is present.")
fd5359c6 573(setq allout-keybindings-list
1977b8f6
RS
574 '(
575 ; Motion commands:
fd5359c6
MR
576 ("\C-n" allout-next-visible-heading)
577 ("\C-p" allout-previous-visible-heading)
578 ("\C-u" allout-up-current-level)
579 ("\C-f" allout-forward-current-level)
580 ("\C-b" allout-backward-current-level)
581 ("\C-a" allout-beginning-of-current-entry)
d82979ea 582 ("\C-e" allout-end-of-entry)
1977b8f6 583 ; Exposure commands:
fd5359c6
MR
584 ("\C-i" allout-show-children)
585 ("\C-s" allout-show-current-subtree)
586 ("\C-h" allout-hide-current-subtree)
d82979ea 587 ("h" allout-hide-current-subtree)
fd5359c6
MR
588 ("\C-o" allout-show-current-entry)
589 ("!" allout-show-all)
d82979ea 590 ("x" allout-toggle-current-subtree-encryption)
1977b8f6 591 ; Alteration commands:
fd5359c6
MR
592 (" " allout-open-sibtopic)
593 ("." allout-open-subtopic)
594 ("," allout-open-supertopic)
595 ("'" allout-shift-in)
596 (">" allout-shift-in)
597 ("<" allout-shift-out)
598 ("\C-m" allout-rebullet-topic)
599 ("*" allout-rebullet-current-heading)
600 ("#" allout-number-siblings)
601 ("\C-k" allout-kill-line t)
602 ("\C-y" allout-yank t)
603 ("\M-y" allout-yank-pop t)
604 ("\C-k" allout-kill-topic)
1977b8f6 605 ; Miscellaneous commands:
fd5359c6
MR
606 ;([?\C-\ ] allout-mark-topic)
607 ("@" allout-resolve-xref)
608 ("=c" allout-copy-exposed-to-buffer)
609 ("=i" allout-indented-exposed-to-buffer)
610 ("=t" allout-latexify-exposed)
611 ("=p" allout-flatten-exposed-to-buffer)))
612
fd5359c6
MR
613;;;_ = allout-use-hanging-indents
614(defcustom allout-use-hanging-indents t
19b84ba3
RS
615 "*If non-nil, topic body text auto-indent defaults to indent of the header.
616Ie, it is indented to be just past the header prefix. This is
617relevant mostly for use with indented-text-mode, or other situations
96b83743 618where auto-fill occurs."
4bef9110
SE
619 :type 'boolean
620 :group 'allout)
fd5359c6 621(make-variable-buffer-local 'allout-use-hanging-indents)
8570ce80
SM
622;;;###autoload
623(put 'allout-use-hanging-indents 'safe-local-variable
624 (lambda (x) (member x '(t nil))))
c567ac01 625
fd5359c6
MR
626;;;_ = allout-reindent-bodies
627(defcustom allout-reindent-bodies (if allout-use-hanging-indents
8d118843 628 'text)
19b84ba3 629 "*Non-nil enables auto-adjust of topic body hanging indent with depth shifts.
1977b8f6 630
8d118843
RS
631When active, topic body lines that are indented even with or beyond
632their topic header are reindented to correspond with depth shifts of
633the header.
634
24190da5 635A value of t enables reindent in non-programming-code buffers, ie
8d118843 636those that do not have the variable `comment-start' set. A value of
4bef9110
SE
637`force' enables reindent whether or not `comment-start' is set."
638 :type '(choice (const nil) (const t) (const text) (const force))
639 :group 'allout)
8d118843 640
fd5359c6 641(make-variable-buffer-local 'allout-reindent-bodies)
8570ce80
SM
642;;;###autoload
643(put 'allout-reindent-bodies 'safe-local-variable
644 (lambda (x) (member x '(nil t text force))))
c567ac01 645
d82979ea
EZ
646;;;_ = allout-enable-file-variable-adjustment
647(defcustom allout-enable-file-variable-adjustment t
0949617b 648 "*If non-nil, some allout outline actions edit Emacs local file var text.
d82979ea
EZ
649
650This can range from changes to existing entries, addition of new ones,
651and creation of a new local variables section when necessary.
19b84ba3 652
d82979ea
EZ
653Emacs file variables adjustments are also inhibited if `enable-local-variables'
654is nil.
c567ac01 655
d82979ea 656Operations potentially causing edits include allout encryption routines.
69027dea 657For details, see `allout-toggle-current-subtree-encryption's docstring."
4bef9110
SE
658 :type 'boolean
659 :group 'allout)
d82979ea 660(make-variable-buffer-local 'allout-enable-file-variable-adjustment)
c567ac01 661
19b84ba3 662;;;_* CODE - no user customizations below.
c567ac01 663
9179616f
DL
664;;;_ #1 Internal Outline Formatting and Configuration
665;;;_ : Version
fd5359c6 666;;;_ = allout-version
4034b0e2 667(defvar allout-version "2.2.1"
0949617b 668 "Version of currently loaded outline package. \(allout.el)")
fd5359c6
MR
669;;;_ > allout-version
670(defun allout-version (&optional here)
19b84ba3
RS
671 "Return string describing the loaded outline version."
672 (interactive "P")
fd5359c6 673 (let ((msg (concat "Allout Outline Mode v " allout-version)))
eac9cf5f 674 (if here (insert msg))
19b84ba3
RS
675 (message "%s" msg)
676 msg))
69027dea
EZ
677;;;_ : Mode activation (defined here because it's referenced early)
678;;;_ = allout-mode
679(defvar allout-mode nil "Allout outline mode minor-mode flag.")
680(make-variable-buffer-local 'allout-mode)
4034b0e2
LT
681;;;_ = allout-layout nil
682(defvar allout-layout nil ; LEAVE GLOBAL VALUE NIL - see docstring.
683 "Buffer-specific setting for allout layout.
684
685In buffers where this is non-nil \(and if `allout-init' has been run, to
686enable this behavior), `allout-mode' will be automatically activated. The
687layout dictated by the value will be used to set the initial exposure when
688`allout-mode' is activated.
689
690\*You should not setq-default this variable non-nil unless you want every
691visited file to be treated as an allout file.*
692
693The value would typically be set by a file local variable. For
694example, the following lines at the bottom of an Emacs Lisp file:
695
696;;;Local variables:
697;;;allout-layout: \(0 : -1 -1 0)
698;;;End:
699
700dictate activation of `allout-mode' mode when the file is visited
701\(presuming allout-init was already run), followed by the
702equivalent of `\(allout-expose-topic 0 : -1 -1 0)'. \(This is
703the layout used for the allout.el source file.)
704
705`allout-default-layout' describes the specification format.
706`allout-layout' can additionally have the value `t', in which
707case the value of `allout-default-layout' is used.")
708(make-variable-buffer-local 'allout-layout)
b1a569b5 709;;;###autoload
8570ce80
SM
710(put 'allout-layout 'safe-local-variable
711 (lambda (x) (or (numberp x) (listp x) (integerp x)
712 (member x '(: * + -)))))
4034b0e2 713
9179616f 714;;;_ : Topic header format
fd5359c6
MR
715;;;_ = allout-regexp
716(defvar allout-regexp ""
c567ac01 717 "*Regular expression to match the beginning of a heading line.
19b84ba3 718
c567ac01
RS
719Any line whose beginning matches this regexp is considered a
720heading. This var is set according to the user configuration vars
2265e017 721by `set-allout-regexp'.")
fd5359c6
MR
722(make-variable-buffer-local 'allout-regexp)
723;;;_ = allout-bullets-string
724(defvar allout-bullets-string ""
19b84ba3
RS
725 "A string dictating the valid set of outline topic bullets.
726
fd5359c6
MR
727This var should *not* be set by the user - it is set by `set-allout-regexp',
728and is produced from the elements of `allout-plain-bullets-string'
729and `allout-distinctive-bullets-string'.")
730(make-variable-buffer-local 'allout-bullets-string)
731;;;_ = allout-bullets-string-len
732(defvar allout-bullets-string-len 0
2265e017 733 "Length of current buffers' `allout-plain-bullets-string'.")
fd5359c6
MR
734(make-variable-buffer-local 'allout-bullets-string-len)
735;;;_ = allout-line-boundary-regexp
736(defvar allout-line-boundary-regexp ()
aad94676 737 "`allout-regexp' with outline style beginning-of-line anchor.
19b84ba3 738
96b83743
EZ
739This is properly set when `allout-regexp' is produced by
740`set-allout-regexp', so that (match-beginning 2) and (match-end
7412) delimit the prefix.")
fd5359c6
MR
742(make-variable-buffer-local 'allout-line-boundary-regexp)
743;;;_ = allout-bob-regexp
744(defvar allout-bob-regexp ()
2265e017 745 "Like `allout-line-boundary-regexp', for headers at beginning of buffer.
9179616f 746\(match-beginning 2) and \(match-end 2) delimit the prefix.")
fd5359c6
MR
747(make-variable-buffer-local 'allout-bob-regexp)
748;;;_ = allout-header-subtraction
749(defvar allout-header-subtraction (1- (length allout-header-prefix))
750 "Allout-header prefix length to subtract when computing topic depth.")
751(make-variable-buffer-local 'allout-header-subtraction)
752;;;_ = allout-plain-bullets-string-len
753(defvar allout-plain-bullets-string-len (length allout-plain-bullets-string)
2265e017 754 "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.")
fd5359c6
MR
755(make-variable-buffer-local 'allout-plain-bullets-string-len)
756
757
758;;;_ X allout-reset-header-lead (header-lead)
759(defun allout-reset-header-lead (header-lead)
c567ac01 760 "*Reset the leading string used to identify topic headers."
1977b8f6 761 (interactive "sNew lead string: ")
fd5359c6
MR
762 (setq allout-header-prefix header-lead)
763 (setq allout-header-subtraction (1- (length allout-header-prefix)))
764 (set-allout-regexp))
765;;;_ X allout-lead-with-comment-string (header-lead)
766(defun allout-lead-with-comment-string (&optional header-lead)
19b84ba3
RS
767 "*Set the topic-header leading string to specified string.
768
769Useful when for encapsulating outline structure in programming
770language comments. Returns the leading string."
1977b8f6
RS
771
772 (interactive "P")
773 (if (not (stringp header-lead))
774 (setq header-lead (read-string
775 "String prefix for topic headers: ")))
fd5359c6
MR
776 (setq allout-reindent-bodies nil)
777 (allout-reset-header-lead header-lead)
1977b8f6 778 header-lead)
fd5359c6
MR
779;;;_ > allout-infer-header-lead ()
780(defun allout-infer-header-lead ()
781 "Determine appropriate `allout-header-prefix'.
19b84ba3
RS
782
783Works according to settings of:
784
8d118843 785 `comment-start'
fd5359c6
MR
786 `allout-header-prefix' (default)
787 `allout-use-mode-specific-leader'
788and `allout-mode-leaders'.
19b84ba3 789
fd5359c6 790Apply this via \(re)activation of `allout-mode', rather than
8d118843 791invoking it directly."
fd5359c6
MR
792 (let* ((use-leader (and (boundp 'allout-use-mode-specific-leader)
793 (if (or (stringp allout-use-mode-specific-leader)
794 (memq allout-use-mode-specific-leader
795 '(allout-mode-leaders
19b84ba3
RS
796 comment-start
797 t)))
fd5359c6 798 allout-use-mode-specific-leader
19b84ba3
RS
799 ;; Oops - garbled value, equate with effect of 't:
800 t)))
801 (leader
802 (cond
803 ((not use-leader) nil)
804 ;; Use the explicitly designated leader:
805 ((stringp use-leader) use-leader)
fd5359c6 806 (t (or (and (memq use-leader '(t allout-mode-leaders))
19b84ba3 807 ;; Get it from outline mode leaders?
fd5359c6
MR
808 (cdr (assq major-mode allout-mode-leaders)))
809 ;; ... didn't get from allout-mode-leaders...
19b84ba3
RS
810 (and (memq use-leader '(t comment-start))
811 comment-start
812 ;; Use comment-start, maybe tripled, and with
353e2ef2 813 ;; underscore:
19b84ba3
RS
814 (concat
815 (if (string= " "
816 (substring comment-start
817 (1- (length comment-start))))
818 ;; Use comment-start, sans trailing space:
819 (substring comment-start 0 -1)
820 (concat comment-start comment-start comment-start))
821 ;; ... and append underscore, whichever:
822 "_")))))))
823 (if (not leader)
824 nil
fd5359c6 825 (if (string= leader allout-header-prefix)
19b84ba3 826 nil ; no change, nothing to do.
fd5359c6
MR
827 (setq allout-header-prefix leader)
828 allout-header-prefix))))
829;;;_ > allout-infer-body-reindent ()
830(defun allout-infer-body-reindent ()
831 "Determine proper setting for `allout-reindent-bodies'.
8d118843 832
fd5359c6 833Depends on default setting of `allout-reindent-bodies' \(which see)
8d118843
RS
834and presence of setting for `comment-start', to tell whether the
835file is programming code."
fd5359c6 836 (if (and allout-reindent-bodies
8d118843 837 comment-start
fd5359c6
MR
838 (not (eq 'force allout-reindent-bodies)))
839 (setq allout-reindent-bodies nil)))
840;;;_ > set-allout-regexp ()
841(defun set-allout-regexp ()
19b84ba3
RS
842 "Generate proper topic-header regexp form for outline functions.
843
fd5359c6
MR
844Works with respect to `allout-plain-bullets-string' and
845`allout-distinctive-bullets-string'."
1977b8f6
RS
846
847 (interactive)
fd5359c6
MR
848 ;; Derive allout-bullets-string from user configured components:
849 (setq allout-bullets-string "")
850 (let ((strings (list 'allout-plain-bullets-string
851 'allout-distinctive-bullets-string
852 'allout-primary-bullet))
1977b8f6
RS
853 cur-string
854 cur-len
c567ac01 855 cur-char
96b83743 856 index)
1977b8f6 857 (while strings
96b83743 858 (setq index 0)
1977b8f6
RS
859 (setq cur-len (length (setq cur-string (symbol-value (car strings)))))
860 (while (< index cur-len)
861 (setq cur-char (aref cur-string index))
fd5359c6
MR
862 (setq allout-bullets-string
863 (concat allout-bullets-string
1977b8f6
RS
864 (cond
865 ; Single dash would denote a
866 ; sequence, repeated denotes
867 ; a dash:
868 ((eq cur-char ?-) "--")
869 ; literal close-square-bracket
870 ; doesn't work right in the
871 ; expr, exclude it:
872 ((eq cur-char ?\]) "")
873 (t (regexp-quote (char-to-string cur-char))))))
874 (setq index (1+ index)))
875 (setq strings (cdr strings)))
876 )
fd5359c6
MR
877 ;; Derive next for repeated use in allout-pending-bullet:
878 (setq allout-plain-bullets-string-len (length allout-plain-bullets-string))
879 (setq allout-header-subtraction (1- (length allout-header-prefix)))
880 ;; Produce the new allout-regexp:
881 (setq allout-regexp (concat "\\(\\"
882 allout-header-prefix
1977b8f6 883 "[ \t]*["
fd5359c6 884 allout-bullets-string
1977b8f6 885 "]\\)\\|\\"
fd5359c6 886 allout-primary-bullet
1977b8f6 887 "+\\|\^l"))
fd5359c6 888 (setq allout-line-boundary-regexp
96b83743 889 (concat "\\(\n\\)\\(" allout-regexp "\\)"))
fd5359c6
MR
890 (setq allout-bob-regexp
891 (concat "\\(\\`\\)\\(" allout-regexp "\\)"))
1977b8f6 892 )
9179616f 893;;;_ : Key bindings
fd5359c6
MR
894;;;_ = allout-mode-map
895(defvar allout-mode-map nil "Keybindings for (allout) outline minor mode.")
896;;;_ > produce-allout-mode-map (keymap-alist &optional base-map)
897(defun produce-allout-mode-map (keymap-list &optional base-map)
e126900f 898 "Produce keymap for use as allout-mode-map, from KEYMAP-LIST.
19b84ba3
RS
899
900Built on top of optional BASE-MAP, or empty sparse map if none specified.
fd5359c6 901See doc string for allout-keybindings-list for format of binding list."
9179616f 902 (let ((map (or base-map (make-sparse-keymap)))
fd5359c6 903 (pref (list allout-command-prefix)))
9179616f
DL
904 (mapcar (function
905 (lambda (cell)
906 (let ((add-pref (null (cdr (cdr cell))))
907 (key-suff (list (car cell))))
908 (apply 'define-key
909 (list map
910 (apply 'concat (if add-pref
911 (append pref key-suff)
912 key-suff))
913 (car (cdr cell)))))))
19b84ba3
RS
914 keymap-list)
915 map))
d82979ea
EZ
916;;;_ = allout-prior-bindings - being deprecated.
917(defvar allout-prior-bindings nil
918 "Variable for use in V18, with allout-added-bindings, for
919resurrecting, on mode deactivation, bindings that existed before
920activation. Being deprecated.")
921;;;_ = allout-added-bindings - being deprecated
922(defvar allout-added-bindings nil
923 "Variable for use in V18, with allout-prior-bindings, for
924resurrecting, on mode deactivation, bindings that existed before
925activation. Being deprecated.")
9179616f 926;;;_ : Menu bar
95c12694
RS
927(defvar allout-mode-exposure-menu)
928(defvar allout-mode-editing-menu)
929(defvar allout-mode-navigation-menu)
930(defvar allout-mode-misc-menu)
fd5359c6 931(defun produce-allout-mode-menubar-entries ()
9179616f 932 (require 'easymenu)
fd5359c6
MR
933 (easy-menu-define allout-mode-exposure-menu
934 allout-mode-map
9179616f
DL
935 "Allout outline exposure menu."
936 '("Exposure"
fd5359c6
MR
937 ["Show Entry" allout-show-current-entry t]
938 ["Show Children" allout-show-children t]
939 ["Show Subtree" allout-show-current-subtree t]
940 ["Hide Subtree" allout-hide-current-subtree t]
941 ["Hide Leaves" allout-hide-current-leaves t]
9179616f 942 "----"
fd5359c6
MR
943 ["Show All" allout-show-all t]))
944 (easy-menu-define allout-mode-editing-menu
945 allout-mode-map
9179616f
DL
946 "Allout outline editing menu."
947 '("Headings"
fd5359c6
MR
948 ["Open Sibling" allout-open-sibtopic t]
949 ["Open Subtopic" allout-open-subtopic t]
950 ["Open Supertopic" allout-open-supertopic t]
9179616f 951 "----"
fd5359c6
MR
952 ["Shift Topic In" allout-shift-in t]
953 ["Shift Topic Out" allout-shift-out t]
954 ["Rebullet Topic" allout-rebullet-topic t]
955 ["Rebullet Heading" allout-rebullet-current-heading t]
d82979ea
EZ
956 ["Number Siblings" allout-number-siblings t]
957 "----"
958 ["Toggle Topic Encryption"
959 allout-toggle-current-subtree-encryption
960 (> (allout-current-depth) 1)]))
fd5359c6
MR
961 (easy-menu-define allout-mode-navigation-menu
962 allout-mode-map
9179616f
DL
963 "Allout outline navigation menu."
964 '("Navigation"
fd5359c6 965 ["Next Visible Heading" allout-next-visible-heading t]
9179616f 966 ["Previous Visible Heading"
fd5359c6 967 allout-previous-visible-heading t]
9179616f 968 "----"
fd5359c6
MR
969 ["Up Level" allout-up-current-level t]
970 ["Forward Current Level" allout-forward-current-level t]
9179616f 971 ["Backward Current Level"
fd5359c6 972 allout-backward-current-level t]
9179616f
DL
973 "----"
974 ["Beginning of Entry"
fd5359c6 975 allout-beginning-of-current-entry t]
d82979ea 976 ["End of Entry" allout-end-of-entry t]
fd5359c6
MR
977 ["End of Subtree" allout-end-of-current-subtree t]))
978 (easy-menu-define allout-mode-misc-menu
979 allout-mode-map
9179616f
DL
980 "Allout outlines miscellaneous bindings."
981 '("Misc"
fd5359c6 982 ["Version" allout-version t]
9179616f 983 "----"
fd5359c6 984 ["Duplicate Exposed" allout-copy-exposed-to-buffer t]
9179616f 985 ["Duplicate Exposed, numbered"
71296446 986 allout-flatten-exposed-to-buffer t]
9179616f 987 ["Duplicate Exposed, indented"
71296446 988 allout-indented-exposed-to-buffer t]
9179616f 989 "----"
fd5359c6
MR
990 ["Set Header Lead" allout-reset-header-lead t]
991 ["Set New Exposure" allout-expose-topic t])))
9179616f 992;;;_ : Mode-Specific Variable Maintenance Utilities
fd5359c6
MR
993;;;_ = allout-mode-prior-settings
994(defvar allout-mode-prior-settings nil
aad94676 995 "Internal `allout-mode' use; settings to be resumed on mode deactivation.")
fd5359c6
MR
996(make-variable-buffer-local 'allout-mode-prior-settings)
997;;;_ > allout-resumptions (name &optional value)
998(defun allout-resumptions (name &optional value)
1977b8f6 999
2265e017 1000 "Registers or resumes settings over `allout-mode' activation/deactivation.
19b84ba3
RS
1001
1002First arg is NAME of variable affected. Optional second arg is list
fd5359c6 1003containing allout-mode-specific VALUE to be imposed on named
69027dea 1004variable, and to be registered. \(It's a list so you can specify
19b84ba3
RS
1005registrations of null values.) If no value is specified, the
1006registered value is returned (encapsulated in the list, so the caller
1007can distinguish nil vs no value), and the registration is popped
c567ac01 1008from the list."
1977b8f6 1009
fd5359c6 1010 (let ((on-list (assq name allout-mode-prior-settings))
353e2ef2 1011 prior-capsule ; By `capsule' i mean a list
1977b8f6
RS
1012 ; containing a value, so we can
1013 ; distinguish nil from no value.
1014 )
1015
1016 (if value
1017
1018 ;; Registering:
1019 (progn
1020 (if on-list
1021 nil ; Already preserved prior value - don't mess with it.
1022 ;; Register the old value, or nil if previously unbound:
fd5359c6 1023 (setq allout-mode-prior-settings
1977b8f6
RS
1024 (cons (list name
1025 (if (boundp name) (list (symbol-value name))))
fd5359c6 1026 allout-mode-prior-settings)))
c567ac01
RS
1027 ; And impose the new value, locally:
1028 (progn (make-local-variable name)
1029 (set name (car value))))
1977b8f6
RS
1030
1031 ;; Relinquishing:
1032 (if (not on-list)
1033
1034 ;; Oops, not registered - leave it be:
1035 nil
1036
1037 ;; Some registration:
1038 ; reestablish it:
1039 (setq prior-capsule (car (cdr on-list)))
1040 (if prior-capsule
1041 (set name (car prior-capsule)) ; Some prior value - reestablish it.
1042 (makunbound name)) ; Previously unbound - demolish var.
1043 ; Remove registration:
1044 (let (rebuild)
fd5359c6
MR
1045 (while allout-mode-prior-settings
1046 (if (not (eq (car allout-mode-prior-settings)
1977b8f6
RS
1047 on-list))
1048 (setq rebuild
fd5359c6 1049 (cons (car allout-mode-prior-settings)
1977b8f6 1050 rebuild)))
fd5359c6
MR
1051 (setq allout-mode-prior-settings
1052 (cdr allout-mode-prior-settings)))
1053 (setq allout-mode-prior-settings rebuild)))))
1977b8f6 1054 )
9179616f 1055;;;_ : Mode-specific incidentals
fd5359c6 1056;;;_ > allout-unprotected (expr)
d82979ea 1057(defmacro allout-unprotected (expr)
96b83743
EZ
1058 "Enable internal outline operations to alter invisible text."
1059 `(let ((inhibit-read-only t))
1060 ,expr))
1061;;;_ = allout-mode-hook
1062(defvar allout-mode-hook nil
1063 "*Hook that's run when allout mode starts.")
1064;;;_ = allout-overlay-category
1065(defvar allout-overlay-category nil
1066 "Symbol for use in allout invisible-text overlays as the category.")
1067;;;_ = allout-view-change-hook
1068(defvar allout-view-change-hook nil
1069 "*Hook that's run after allout outline visibility changes.")
1070
1071;;;_ = allout-outside-normal-auto-fill-function
1072(defvar allout-outside-normal-auto-fill-function nil
1073 "Value of normal-auto-fill-function outside of allout mode.
1074
1075Used by allout-auto-fill to do the mandated normal-auto-fill-function
1076wrapped within allout's automatic fill-prefix setting.")
1077(make-variable-buffer-local 'allout-outside-normal-auto-fill-function)
19b84ba3 1078;;;_ = file-var-bug hack
fd5359c6 1079(defvar allout-v18/19-file-var-hack nil
c567ac01 1080 "Horrible hack used to prevent invalid multiple triggering of outline
2265e017 1081mode from prop-line file-var activation. Used by `allout-mode' function
c567ac01 1082to track repeats.")
0949617b
EZ
1083;;;_ = allout-passphrase-verifier-string
1084(defvar allout-passphrase-verifier-string nil
1085 "Setting used to test solicited encryption passphrases against the one
1086already associated with a file.
1087
1088It consists of an encrypted random string useful only to verify that a
1089passphrase entered by the user is effective for decryption. The passphrase
1090itself is \*not* recorded in the file anywhere, and the encrypted contents
1091are random binary characters to avoid exposing greater susceptibility to
1092search attacks.
d82979ea
EZ
1093
1094The verifier string is retained as an Emacs file variable, as well as in
1095the emacs buffer state, if file variable adjustments are enabled. See
1096`allout-enable-file-variable-adjustment' for details about that.")
0949617b 1097(make-variable-buffer-local 'allout-passphrase-verifier-string)
8570ce80 1098;;;###autoload
7e5d77dc 1099(put 'allout-passphrase-verifier-string 'safe-local-variable 'stringp)
0949617b
EZ
1100;;;_ = allout-passphrase-hint-string
1101(defvar allout-passphrase-hint-string ""
1102 "Variable used to retain reminder string for file's encryption passphrase.
d82979ea 1103
0949617b 1104See the description of `allout-passphrase-hint-handling' for details about how
d82979ea
EZ
1105the reminder is deployed.
1106
1107The hint is retained as an Emacs file variable, as well as in the emacs buffer
1108state, if file variable adjustments are enabled. See
1109`allout-enable-file-variable-adjustment' for details about that.")
0949617b
EZ
1110(make-variable-buffer-local 'allout-passphrase-hint-string)
1111(setq-default allout-passphrase-hint-string "")
8570ce80
SM
1112;;;###autoload
1113(put 'allout-passphrase-hint-string 'safe-local-variable 'stringp)
d82979ea
EZ
1114;;;_ = allout-after-save-decrypt
1115(defvar allout-after-save-decrypt nil
1116 "Internal variable, is nil or has the value of two points:
1117
1118 - the location of a topic to be decrypted after saving is done
1119 - where to situate the cursor after the decryption is performed
1120
1121This is used to decrypt the topic that was currently being edited, if it
1122was encrypted automatically as part of a file write or autosave.")
1123(make-variable-buffer-local 'allout-after-save-decrypt)
69027dea
EZ
1124;;;_ > allout-mode-p ()
1125;; Must define this macro above any uses, or byte compilation will lack
1126;; proper def, if file isn't loaded - eg, during emacs build!
1127(defmacro allout-mode-p ()
1128 "Return t if `allout-mode' is active in current buffer."
1129 'allout-mode)
d82979ea
EZ
1130;;;_ > allout-write-file-hook-handler ()
1131(defun allout-write-file-hook-handler ()
1132 "Implement `allout-encrypt-unencrypted-on-saves' policy for file writes."
1133
0949617b
EZ
1134 (if (or (not (allout-mode-p))
1135 (not (boundp 'allout-encrypt-unencrypted-on-saves))
d82979ea
EZ
1136 (not allout-encrypt-unencrypted-on-saves))
1137 nil
1138 (let ((except-mark (and (equal allout-encrypt-unencrypted-on-saves
1139 'except-current)
1140 (point-marker))))
1141 (if (save-excursion (goto-char (point-min))
1142 (allout-next-topic-pending-encryption except-mark))
1143 (progn
1144 (message "auto-encrypting pending topics")
96b83743 1145 (sit-for 0)
d82979ea
EZ
1146 (condition-case failure
1147 (setq allout-after-save-decrypt
1148 (allout-encrypt-decrypted except-mark))
1149 (error (progn
1150 (message
1151 "allout-write-file-hook-handler suppressing error %s"
1152 failure)
1153 (sit-for 2))))))
1154 ))
1155 nil)
1156;;;_ > allout-auto-save-hook-handler ()
1157(defun allout-auto-save-hook-handler ()
69027dea 1158 "Implement `allout-encrypt-unencrypted-on-saves' policy for auto save."
d82979ea 1159
0949617b 1160 (if (and (allout-mode-p) allout-encrypt-unencrypted-on-saves)
d82979ea
EZ
1161 ;; Always implement 'except-current policy when enabled.
1162 (let ((allout-encrypt-unencrypted-on-saves 'except-current))
1163 (allout-write-file-hook-handler))))
1164;;;_ > allout-after-saves-handler ()
1165(defun allout-after-saves-handler ()
1166 "Decrypt topic encrypted for save, if it's currently being edited.
1167
1168Ie, if it was pending encryption and contained the point in its body before
1169the save.
1170
1171We use values stored in `allout-after-save-decrypt' to locate the topic
1172and the place for the cursor after the decryption is done."
1173 (if (not (and (allout-mode-p)
1174 (boundp 'allout-after-save-decrypt)
1175 allout-after-save-decrypt))
1176 t
1177 (goto-char (car allout-after-save-decrypt))
1178 (let ((was-modified (buffer-modified-p)))
69027dea 1179 (allout-toggle-subtree-encryption)
d82979ea
EZ
1180 (if (not was-modified)
1181 (set-buffer-modified-p nil)))
1182 (goto-char (cadr allout-after-save-decrypt))
1183 (setq allout-after-save-decrypt nil))
1184 )
19b84ba3
RS
1185
1186;;;_ #2 Mode activation
fd5359c6
MR
1187;;;_ = allout-explicitly-deactivated
1188(defvar allout-explicitly-deactivated nil
d82979ea 1189 "If t, `allout-mode's last deactivation was deliberate.
2265e017 1190So `allout-post-command-business' should not reactivate it...")
fd5359c6
MR
1191(make-variable-buffer-local 'allout-explicitly-deactivated)
1192;;;_ > allout-init (&optional mode)
1193(defun allout-init (&optional mode)
2265e017 1194 "Prime `allout-mode' to enable/disable auto-activation, wrt `allout-layout'.
19b84ba3 1195
8d118843 1196MODE is one of the following symbols:
19b84ba3 1197
353e2ef2
KH
1198 - nil \(or no argument) deactivate auto-activation/layout;
1199 - `activate', enable auto-activation only;
1200 - `ask', enable auto-activation, and enable auto-layout but with
a0776d6b 1201 confirmation for layout operation solicited from user each time;
353e2ef2 1202 - `report', just report and return the current auto-activation state;
8d118843
RS
1203 - anything else \(eg, t) for auto-activation and auto-layout, without
1204 any confirmation check.
19b84ba3 1205
e126900f 1206Use this function to setup your Emacs session for automatic activation
19b84ba3 1207of allout outline mode, contingent to the buffer-specific setting of
fd5359c6
MR
1208the `allout-layout' variable. (See `allout-layout' and
1209`allout-expose-topic' docstrings for more details on auto layout).
19b84ba3 1210
d82979ea
EZ
1211`allout-init' works by setting up (or removing) the `allout-mode'
1212find-file-hook, and giving `allout-auto-activation' a suitable
1213setting.
19b84ba3 1214
e126900f
JB
1215To prime your Emacs session for full auto-outline operation, include
1216the following two lines in your Emacs init file:
19b84ba3
RS
1217
1218\(require 'allout)
fd5359c6 1219\(allout-init t)"
19b84ba3 1220
d82979ea
EZ
1221 (interactive)
1222 (if (interactive-p)
1223 (progn
1224 (setq mode
1225 (completing-read
1226 (concat "Select outline auto setup mode "
1227 "(empty for report, ? for options) ")
1228 '(("nil")("full")("activate")("deactivate")
1229 ("ask") ("report") (""))
1230 nil
1231 t))
1232 (if (string= mode "")
1233 (setq mode 'report)
1234 (setq mode (intern-soft mode)))))
8d118843
RS
1235 (let
1236 ;; convenience aliases, for consistent ref to respective vars:
fd5359c6 1237 ((hook 'allout-find-file-hook)
0949617b
EZ
1238 (find-file-hook-var-name (if (boundp 'find-file-hook)
1239 'find-file-hook
1240 'find-file-hooks))
fd5359c6 1241 (curr-mode 'allout-auto-activation))
353e2ef2 1242
8d118843 1243 (cond ((not mode)
0949617b
EZ
1244 (set find-file-hook-var-name
1245 (delq hook (symbol-value find-file-hook-var-name)))
8d118843
RS
1246 (if (interactive-p)
1247 (message "Allout outline mode auto-activation inhibited.")))
1248 ((eq mode 'report)
0949617b 1249 (if (not (memq hook (symbol-value find-file-hook-var-name)))
d82979ea
EZ
1250 (allout-init nil)
1251 ;; Just punt and use the reports from each of the modes:
1252 (allout-init (symbol-value curr-mode))))
0949617b 1253 (t (add-hook find-file-hook-var-name hook)
353e2ef2 1254 (set curr-mode ; `set', not `setq'!
8d118843
RS
1255 (cond ((eq mode 'activate)
1256 (message
1257 "Outline mode auto-activation enabled.")
1258 'activate)
1259 ((eq mode 'report)
1260 ;; Return the current mode setting:
fd5359c6 1261 (allout-init mode))
8d118843
RS
1262 ((eq mode 'ask)
1263 (message
1264 (concat "Outline mode auto-activation and "
1265 "-layout \(upon confirmation) enabled."))
1266 'ask)
1267 ((message
1268 "Outline mode auto-activation and -layout enabled.")
1269 'full)))))))
fd5359c6
MR
1270;;;_ > allout-setup-menubar ()
1271(defun allout-setup-menubar ()
aad94676 1272 "Populate the current buffer's menubar with `allout-mode' stuff."
fd5359c6
MR
1273 (let ((menus (list allout-mode-exposure-menu
1274 allout-mode-editing-menu
1275 allout-mode-navigation-menu
1276 allout-mode-misc-menu))
9179616f
DL
1277 cur)
1278 (while menus
1279 (setq cur (car menus)
1280 menus (cdr menus))
1281 (easy-menu-add cur))))
96b83743
EZ
1282;;;_ > allout-set-overlay-category
1283(defun allout-set-overlay-category ()
1284 "Set the properties of the allout invisible-text overlay."
1285 (setplist 'allout-overlay-category nil)
1286 (put 'allout-overlay-category 'invisible 'allout)
1287 (put 'allout-overlay-category 'evaporate t)
1288 ;; XXX We use isearch-open-invisible *and* isearch-mode-end-hook. The
1289 ;; latter would be sufficient, but it seems that a separate behavior -
1290 ;; the _transient_ opening of invisible text during isearch - is keyed to
1291 ;; presence of the isearch-open-invisible property - even though this
1292 ;; property controls the isearch _arrival_ behavior. This is the case at
1293 ;; least in emacs 21, 22.0, and xemacs 21.4.
1294 (put 'allout-overlay-category 'isearch-open-invisible
1295 'allout-isearch-end-handler)
1296 (if (featurep 'xemacs)
1297 (put 'allout-overlay-category 'start-open t)
1298 (put 'allout-overlay-category 'insert-in-front-hooks
1299 '(allout-overlay-insert-in-front-handler)))
1300 (if (featurep 'xemacs)
1301 (progn (make-variable-buffer-local 'before-change-functions)
1302 (add-hook 'before-change-functions
1303 'allout-before-change-handler))
1304 (put 'allout-overlay-category 'modification-hooks
1305 '(allout-overlay-interior-modification-handler))))
fd5359c6 1306;;;_ > allout-mode (&optional toggle)
19b84ba3 1307;;;_ : Defun:
0949617b 1308;;;###autoload
fd5359c6 1309(defun allout-mode (&optional toggle)
c567ac01 1310;;;_ . Doc string:
19b84ba3 1311 "Toggle minor mode for controlling exposure and editing of text outlines.
96b83743 1312\\<allout-mode-map>
19b84ba3 1313
9179616f
DL
1314Optional arg forces mode to re-initialize iff arg is positive num or
1315symbol. Allout outline mode always runs as a minor mode.
19b84ba3 1316
aad94676 1317Allout outline mode provides extensive outline oriented formatting and
9179616f
DL
1318manipulation. It enables structural editing of outlines, as well as
1319navigation and exposure. It also is specifically aimed at
1320accommodating syntax-sensitive text like programming languages. \(For
1321an example, see the allout code itself, which is organized as an allout
1322outline.)
19b84ba3 1323
9179616f 1324In addition to outline navigation and exposure, allout includes:
19b84ba3 1325
d82979ea 1326 - topic-oriented repositioning, promotion/demotion, cut, and paste
9179616f
DL
1327 - integral outline exposure-layout
1328 - incremental search with dynamic exposure and reconcealment of hidden text
1329 - automatic topic-number maintenance
d82979ea 1330 - easy topic encryption and decryption
9179616f 1331 - \"Hot-spot\" operation, for single-keystroke maneuvering and
fd5359c6 1332 exposure control. \(See the allout-mode docstring.)
9179616f
DL
1333
1334and many other features.
19b84ba3
RS
1335
1336Below is a description of the bindings, and then explanation of
2265e017 1337special `allout-mode' features and terminology. See also the outline
9179616f 1338menubar additions for quick reference to many of the features, and see
f134d28b 1339the docstring of the function `allout-init' for instructions on
d82979ea 1340priming your emacs session for automatic activation of `allout-mode'.
9179616f 1341
19b84ba3 1342
fd5359c6
MR
1343The bindings are dictated by the `allout-keybindings-list' and
1344`allout-command-prefix' variables.
19b84ba3
RS
1345
1346 Navigation: Exposure Control:
1347 ---------- ----------------
0949617b
EZ
1348\\[allout-next-visible-heading] allout-next-visible-heading | \\[allout-hide-current-subtree] allout-hide-current-subtree
1349\\[allout-previous-visible-heading] allout-previous-visible-heading | \\[allout-show-children] allout-show-children
1350\\[allout-up-current-level] allout-up-current-level | \\[allout-show-current-subtree] allout-show-current-subtree
1351\\[allout-forward-current-level] allout-forward-current-level | \\[allout-show-current-entry] allout-show-current-entry
1352\\[allout-backward-current-level] allout-backward-current-level | \\[allout-show-all] allout-show-all
1353\\[allout-end-of-entry] allout-end-of-entry
96b83743 1354\\[allout-beginning-of-current-entry] allout-beginning-of-current-entry, alternately, goes to hot-spot
19b84ba3
RS
1355
1356 Topic Header Production:
1357 -----------------------
96b83743
EZ
1358\\[allout-open-sibtopic] allout-open-sibtopic Create a new sibling after current topic.
1359\\[allout-open-subtopic] allout-open-subtopic ... an offspring of current topic.
1360\\[allout-open-supertopic] allout-open-supertopic ... a sibling of the current topic's parent.
19b84ba3
RS
1361
1362 Topic Level and Prefix Adjustment:
1363 ---------------------------------
96b83743
EZ
1364\\[allout-shift-in] allout-shift-in Shift current topic and all offspring deeper.
1365\\[allout-shift-out] allout-shift-out ... less deep.
1366\\[allout-rebullet-current-heading] allout-rebullet-current-heading Prompt for alternate bullet for
0949617b
EZ
1367 current topic.
1368\\[allout-rebullet-topic] allout-rebullet-topic Reconcile bullets of topic and its offspring
19b84ba3
RS
1369 - distinctive bullets are not changed, others
1370 alternated according to nesting depth.
96b83743 1371\\[allout-number-siblings] allout-number-siblings Number bullets of topic and siblings - the
1977b8f6
RS
1372 offspring are not affected. With repeat
1373 count, revoke numbering.
1374
19b84ba3
RS
1375 Topic-oriented Killing and Yanking:
1376 ----------------------------------
96b83743
EZ
1377\\[allout-kill-topic] allout-kill-topic Kill current topic, including offspring.
1378\\[allout-kill-line] allout-kill-line Like kill-line, but reconciles numbering, etc.
1379\\[allout-yank] allout-yank Yank, adjusting depth of yanked topic to
1977b8f6 1380 depth of heading if yanking into bare topic
19b84ba3 1381 heading (ie, prefix sans text).
96b83743
EZ
1382\\[allout-yank-pop] allout-yank-pop Is to allout-yank as yank-pop is to yank
1383
1384 Topic-oriented Encryption:
1385 -------------------------
1386\\[allout-toggle-current-subtree-encryption] allout-toggle-current-subtree-encryption Encrypt/Decrypt topic content
1977b8f6 1387
19b84ba3
RS
1388 Misc commands:
1389 -------------
19b84ba3
RS
1390M-x outlineify-sticky Activate outline mode for current buffer,
1391 and establish a default file-var setting
fd5359c6 1392 for `allout-layout'.
96b83743 1393\\[allout-mark-topic] allout-mark-topic
0949617b 1394\\[allout-copy-exposed-to-buffer] allout-copy-exposed-to-buffer
9179616f 1395 Duplicate outline, sans concealed text, to
d82979ea
EZ
1396 buffer with name derived from derived from that
1397 of current buffer - \"*BUFFERNAME exposed*\".
96b83743 1398\\[allout-flatten-exposed-to-buffer] allout-flatten-exposed-to-buffer
9179616f
DL
1399 Like above 'copy-exposed', but convert topic
1400 prefixes to section.subsection... numeric
1401 format.
96b83743 1402\\[eval-expression] (allout-init t) Setup Emacs session for outline mode
19b84ba3 1403 auto-activation.
1977b8f6 1404
96b83743 1405 Topic Encryption
d82979ea 1406
96b83743
EZ
1407Outline mode supports gpg encryption of topics, with support for
1408symmetric and key-pair modes, passphrase timeout, passphrase
1409consistency checking, user-provided hinting for symmetric key
1410mode, and auto-encryption of topics pending encryption on save.
1411\(Topics pending encryption are, by default, automatically
1412encrypted during file saves; if you're editing the contents of
1413such a topic, it is automatically decrypted for continued
1414editing.) The aim is reliable topic privacy while preventing
1415accidents like neglected encryption before saves, forgetting
1416which passphrase was used, and other practical pitfalls.
d82979ea 1417
69027dea 1418See `allout-toggle-current-subtree-encryption' function docstring and
d82979ea
EZ
1419`allout-encrypt-unencrypted-on-saves' customization variable for details.
1420
19b84ba3 1421 HOT-SPOT Operation
c567ac01 1422
19b84ba3
RS
1423Hot-spot operation provides a means for easy, single-keystroke outline
1424navigation and exposure control.
c567ac01 1425
19b84ba3
RS
1426When the text cursor is positioned directly on the bullet character of
1427a topic, regular characters (a to z) invoke the commands of the
fd5359c6 1428corresponding allout-mode keymap control chars. For example, \"f\"
96b83743 1429would invoke the command typically bound to \"C-c<space>C-f\"
fd5359c6 1430\(\\[allout-forward-current-level] `allout-forward-current-level').
19b84ba3 1431
96b83743
EZ
1432Thus, by positioning the cursor on a topic bullet, you can
1433execute the outline navigation and manipulation commands with a
1434single keystroke. Regular navigation keys (eg, \\[forward-char], \\[next-line]) never get
1435this special translation, so you can use them to get out of the
1436hot-spot and back to normal operation.
c567ac01 1437
fd5359c6 1438Note that the command `allout-beginning-of-current-entry' \(\\[allout-beginning-of-current-entry]\)
c567ac01 1439will move to the hot-spot when the cursor is already located at the
96b83743 1440beginning of the current entry, so you usually can hit \\[allout-beginning-of-current-entry]
c567ac01 1441twice in a row to get to the hot-spot.
1977b8f6 1442
19b84ba3 1443 Terminology
1977b8f6 1444
c567ac01
RS
1445Topic hierarchy constituents - TOPICS and SUBTOPICS:
1446
e126900f 1447TOPIC: A basic, coherent component of an Emacs outline. It can
96b83743 1448 contain and be contained by other topics.
c567ac01
RS
1449CURRENT topic:
1450 The visible topic most immediately containing the cursor.
19b84ba3
RS
1451DEPTH: The degree of nesting of a topic; it increases with
1452 containment. Also called the:
c567ac01
RS
1453LEVEL: The same as DEPTH.
1454
1455ANCESTORS:
1456 The topics that contain a topic.
1457PARENT: A topic's immediate ancestor. It has a depth one less than
1458 the topic.
1459OFFSPRING:
19b84ba3
RS
1460 The topics contained by a topic;
1461SUBTOPIC:
1462 An immediate offspring of a topic;
c567ac01
RS
1463CHILDREN:
1464 The immediate offspring of a topic.
1465SIBLINGS:
19b84ba3 1466 Topics having the same parent and depth.
353e2ef2 1467
c567ac01
RS
1468Topic text constituents:
1469
1470HEADER: The first line of a topic, include the topic PREFIX and header
353e2ef2 1471 text.
d82979ea
EZ
1472PREFIX: The leading text of a topic which distinguishes it from normal
1473 text. It has a strict form, which consists of a prefix-lead
1474 string, padding, and a bullet. The bullet may be followed by a
1475 number, indicating the ordinal number of the topic among its
1476 siblings, a space, and then the header text.
c567ac01
RS
1477
1478 The relative length of the PREFIX determines the nesting depth
1479 of the topic.
1480PREFIX-LEAD:
353e2ef2 1481 The string at the beginning of a topic prefix, normally a `.'.
c567ac01 1482 It can be customized by changing the setting of
2265e017 1483 `allout-header-prefix' and then reinitializing `allout-mode'.
c567ac01
RS
1484
1485 By setting the prefix-lead to the comment-string of a
aad94676 1486 programming language, you can embed outline structuring in
c567ac01 1487 program code without interfering with the language processing
fd5359c6 1488 of that code. See `allout-use-mode-specific-leader'
19b84ba3 1489 docstring for more detail.
c567ac01
RS
1490PREFIX-PADDING:
1491 Spaces or asterisks which separate the prefix-lead and the
96b83743 1492 bullet, determining the depth of the topic.
c567ac01 1493BULLET: A character at the end of the topic prefix, it must be one of
fd5359c6
MR
1494 the characters listed on `allout-plain-bullets-string' or
1495 `allout-distinctive-bullets-string'. (See the documentation
c567ac01 1496 for these variables for more details.) The default choice of
96b83743
EZ
1497 bullet when generating topics varies in a cycle with the depth of
1498 the topic.
c567ac01
RS
1499ENTRY: The text contained in a topic before any offspring.
1500BODY: Same as ENTRY.
1501
1502
1503EXPOSURE:
1504 The state of a topic which determines the on-screen visibility
353e2ef2 1505 of its offspring and contained text.
c567ac01
RS
1506CONCEALED:
1507 Topics and entry text whose display is inhibited. Contiguous
353e2ef2 1508 units of concealed text is represented by `...' ellipses.
c567ac01
RS
1509
1510 Concealed topics are effectively collapsed within an ancestor.
1511CLOSED: A topic whose immediate offspring and body-text is concealed.
353e2ef2 1512OPEN: A topic that is not closed, though its offspring or body may be."
c567ac01 1513;;;_ . Code
1977b8f6
RS
1514 (interactive "P")
1515
c567ac01 1516 (let* ((active (and (not (equal major-mode 'outline))
fd5359c6 1517 (allout-mode-p)))
353e2ef2 1518 ; Massage universal-arg `toggle' val:
c567ac01 1519 (toggle (and toggle
19b84ba3
RS
1520 (or (and (listp toggle)(car toggle))
1521 toggle)))
a0776d6b 1522 ; Activation specifically demanded?
69027dea 1523 (explicit-activation (and toggle
19b84ba3 1524 (or (symbolp toggle)
69027dea
EZ
1525 (and (wholenump toggle)
1526 (not (zerop toggle))))))
fd5359c6
MR
1527 ;; allout-mode already called once during this complex command?
1528 (same-complex-command (eq allout-v18/19-file-var-hack
19b84ba3 1529 (car command-history)))
96b83743
EZ
1530 (write-file-hook-var-name (cond ((boundp 'write-file-functions)
1531 'write-file-functions)
1532 ((boundp 'write-file-hooks)
1533 'write-file-hooks)
1534 (t 'local-write-file-hooks)))
19b84ba3
RS
1535 do-layout
1536 )
c567ac01 1537
19b84ba3 1538 ; See comments below re v19.18,.19 bug.
fd5359c6 1539 (setq allout-v18/19-file-var-hack (car command-history))
c567ac01 1540
1977b8f6
RS
1541 (cond
1542
19b84ba3 1543 ;; Provision for v19.18, 19.19 bug -
c567ac01
RS
1544 ;; Emacs v 19.18, 19.19 file-var code invokes prop-line-designated
1545 ;; modes twice when file is visited. We have to avoid toggling mode
1546 ;; off on second invocation, so we detect it as best we can, and
1547 ;; skip everything.
1548 ((and same-complex-command ; Still in same complex command
d82979ea 1549 ; as last time `allout-mode' invoked.
19b84ba3
RS
1550 active ; Already activated.
1551 (not explicit-activation) ; Prop-line file-vars don't have args.
1552 (string-match "^19.1[89]" ; Bug only known to be in v19.18 and
1553 emacs-version)); 19.19.
c567ac01 1554 t)
353e2ef2 1555
19b84ba3 1556 ;; Deactivation:
c567ac01 1557 ((and (not explicit-activation)
19b84ba3
RS
1558 (or active toggle))
1559 ; Activation not explicitly
1560 ; requested, and either in
1561 ; active state or *de*activation
1562 ; specifically requested:
fd5359c6 1563 (setq allout-explicitly-deactivated t)
d82979ea
EZ
1564 (if (string-match "^18\." emacs-version)
1565 ; Revoke those keys that remain
1566 ; as we set them:
1567 (let ((curr-loc (current-local-map)))
1568 (mapcar (function
1569 (lambda (cell)
1570 (if (eq (lookup-key curr-loc (car cell))
1571 (car (cdr cell)))
1572 (define-key curr-loc (car cell)
1573 (assq (car cell) allout-prior-bindings)))))
1574 allout-added-bindings)
1575 (allout-resumptions 'allout-added-bindings)
1576 (allout-resumptions 'allout-prior-bindings)))
c567ac01 1577
fd5359c6 1578 (if allout-old-style-prefixes
c567ac01 1579 (progn
fd5359c6
MR
1580 (allout-resumptions 'allout-primary-bullet)
1581 (allout-resumptions 'allout-old-style-prefixes)))
96b83743
EZ
1582 ;;(allout-resumptions 'selective-display)
1583 (remove-from-invisibility-spec '(allout . t))
0949617b 1584 (set write-file-hook-var-name
d82979ea 1585 (delq 'allout-write-file-hook-handler
0949617b 1586 (symbol-value write-file-hook-var-name)))
d82979ea
EZ
1587 (setq auto-save-hook
1588 (delq 'allout-auto-save-hook-handler
1589 auto-save-hook))
fd5359c6
MR
1590 (allout-resumptions 'paragraph-start)
1591 (allout-resumptions 'paragraph-separate)
96b83743
EZ
1592 (allout-resumptions 'auto-fill-function)
1593 (allout-resumptions 'normal-auto-fill-function)
fd5359c6
MR
1594 (allout-resumptions 'allout-former-auto-filler)
1595 (setq allout-mode nil))
1977b8f6 1596
19b84ba3 1597 ;; Activation:
1977b8f6 1598 ((not active)
fd5359c6
MR
1599 (setq allout-explicitly-deactivated nil)
1600 (if allout-old-style-prefixes
c567ac01 1601 (progn ; Inhibit all the fancy formatting:
fd5359c6
MR
1602 (allout-resumptions 'allout-primary-bullet '("*"))
1603 (allout-resumptions 'allout-old-style-prefixes '(()))))
19b84ba3 1604
96b83743
EZ
1605 (allout-set-overlay-category) ; Doesn't hurt to redo this.
1606
fd5359c6
MR
1607 (allout-infer-header-lead)
1608 (allout-infer-body-reindent)
19b84ba3 1609
fd5359c6 1610 (set-allout-regexp)
19b84ba3
RS
1611
1612 ; Produce map from current version
fd5359c6 1613 ; of allout-keybindings-list:
c567ac01
RS
1614 (if (boundp 'minor-mode-map-alist)
1615
1616 (progn ; V19, and maybe lucid and
19b84ba3 1617 ; epoch, minor-mode key bindings:
fd5359c6
MR
1618 (setq allout-mode-map
1619 (produce-allout-mode-map allout-keybindings-list))
8570ce80
SM
1620 (substitute-key-definition 'beginning-of-line
1621 'move-beginning-of-line
1622 allout-mode-map global-map)
1623 (substitute-key-definition 'end-of-line
1624 'move-end-of-line
1625 allout-mode-map global-map)
fd5359c6
MR
1626 (produce-allout-mode-menubar-entries)
1627 (fset 'allout-mode-map allout-mode-map)
19b84ba3
RS
1628 ; Include on minor-mode-map-alist,
1629 ; if not already there:
fd5359c6 1630 (if (not (member '(allout-mode . allout-mode-map)
19b84ba3
RS
1631 minor-mode-map-alist))
1632 (setq minor-mode-map-alist
fd5359c6 1633 (cons '(allout-mode . allout-mode-map)
19b84ba3
RS
1634 minor-mode-map-alist))))
1635
d82979ea
EZ
1636 ; V18 minor-mode key bindings:
1637 ; Stash record of added bindings
1638 ; for later revocation:
1639 (allout-resumptions 'allout-added-bindings
1640 (list allout-keybindings-list))
1641 (allout-resumptions 'allout-prior-bindings
1642 (list (current-local-map)))
19b84ba3 1643 ; and add them:
fd5359c6 1644 (use-local-map (produce-allout-mode-map allout-keybindings-list
19b84ba3 1645 (current-local-map)))
c567ac01 1646 )
353e2ef2 1647
96b83743
EZ
1648 (add-to-invisibility-spec '(allout . t))
1649 (make-local-variable 'line-move-ignore-invisible)
1650 (setq line-move-ignore-invisible t)
fd5359c6
MR
1651 (add-hook 'pre-command-hook 'allout-pre-command-business)
1652 (add-hook 'post-command-hook 'allout-post-command-business)
96b83743 1653 (add-hook 'isearch-mode-end-hook 'allout-isearch-end-handler)
0949617b 1654 (add-hook write-file-hook-var-name 'allout-write-file-hook-handler)
d82979ea 1655 (add-hook 'auto-save-hook 'allout-auto-save-hook-handler)
19b84ba3
RS
1656 ; Custom auto-fill func, to support
1657 ; respect for topic headline,
1658 ; hanging-indents, etc:
96b83743
EZ
1659 ;; Register prevailing fill func for use by allout-auto-fill:
1660 (allout-resumptions 'allout-former-auto-filler (list auto-fill-function))
1661 ;; Register allout-auto-fill to be used if filling is active:
1662 (allout-resumptions 'auto-fill-function '(allout-auto-fill))
1663 (allout-resumptions 'allout-outside-normal-auto-fill-function
1664 (list normal-auto-fill-function))
1665 (allout-resumptions 'normal-auto-fill-function '(allout-auto-fill))
c567ac01 1666 ;; Paragraphs are broken by topic headlines.
1977b8f6 1667 (make-local-variable 'paragraph-start)
fd5359c6 1668 (allout-resumptions 'paragraph-start
9179616f 1669 (list (concat paragraph-start "\\|^\\("
fd5359c6 1670 allout-regexp "\\)")))
1977b8f6 1671 (make-local-variable 'paragraph-separate)
fd5359c6 1672 (allout-resumptions 'paragraph-separate
9179616f 1673 (list (concat paragraph-separate "\\|^\\("
fd5359c6 1674 allout-regexp "\\)")))
c567ac01 1675
fd5359c6 1676 (or (assq 'allout-mode minor-mode-alist)
c567ac01 1677 (setq minor-mode-alist
aad94676 1678 (cons '(allout-mode " Allout") minor-mode-alist)))
19b84ba3 1679
fd5359c6 1680 (allout-setup-menubar)
9179616f 1681
fd5359c6 1682 (if allout-layout
19b84ba3 1683 (setq do-layout t))
1977b8f6 1684
fd5359c6
MR
1685 (run-hooks 'allout-mode-hook)
1686 (setq allout-mode t))
19b84ba3
RS
1687
1688 ;; Reactivation:
8d118843 1689 ((setq do-layout t)
fd5359c6 1690 (allout-infer-body-reindent))
c567ac01 1691 ) ; cond
19b84ba3 1692
4034b0e2
LT
1693 (let ((use-layout (if (listp allout-layout)
1694 allout-layout
1695 allout-default-layout)))
1696 (if (and do-layout
1697 allout-auto-activation
1698 use-layout
1699 (and (not (eq allout-auto-activation 'activate))
1700 (if (eq allout-auto-activation 'ask)
1701 (if (y-or-n-p (format "Expose %s with layout '%s'? "
1702 (buffer-name)
1703 use-layout))
1704 t
1705 (message "Skipped %s layout." (buffer-name))
1706 nil)
1707 t)))
1708 (save-excursion
1709 (message "Adjusting '%s' exposure..." (buffer-name))
1710 (goto-char 0)
1711 (allout-this-or-next-heading)
1712 (condition-case err
1713 (progn
1714 (apply 'allout-expose-topic (list use-layout))
1715 (message "Adjusting '%s' exposure... done." (buffer-name)))
1716 ;; Problem applying exposure - notify user, but don't
1717 ;; interrupt, eg, file visit:
1718 (error (message "%s" (car (cdr err)))
1719 (sit-for 1))))))
fd5359c6 1720 allout-mode
c567ac01 1721 ) ; let*
19b84ba3 1722 ) ; defun
46771bb3
EZ
1723;;;_ > allout-minor-mode
1724(defalias 'allout-minor-mode 'allout-mode)
773e7e48
EZ
1725
1726;;;_ - Position Assessment
1727;;;_ > allout-hidden-p (&optional pos)
1728(defsubst allout-hidden-p (&optional pos)
1729 "Non-nil if the character after point is invisible."
1730 (get-char-property (or pos (point)) 'invisible))
1731
96b83743
EZ
1732;;;_ > allout-overlay-insert-in-front-handler (ol after beg end
1733;;; &optional prelen)
1734(defun allout-overlay-insert-in-front-handler (ol after beg end
1735 &optional prelen)
1736 "Shift the overlay so stuff inserted in front of it are excluded."
1737 (if after
1738 (move-overlay ol (1+ beg) (overlay-end ol))))
1739;;;_ > allout-overlay-interior-modification-handler (ol after beg end
1740;;; &optional prelen)
1741(defun allout-overlay-interior-modification-handler (ol after beg end
1742 &optional prelen)
1743 "Get confirmation before making arbitrary changes to invisible text.
1744
1745We expose the invisible text and ask for confirmation. Refusal or
1746keyboard-quit abandons the changes, with keyboard-quit additionally
1747reclosing the opened text.
1748
1749No confirmation is necessary when inhibit-read-only is set - eg, allout
1750internal functions use this feature cohesively bunch changes."
1751
1752 (when (and (not inhibit-read-only) (not after))
1753 (let ((start (point))
1754 (ol-start (overlay-start ol))
1755 (ol-end (overlay-end ol))
1756 (msg "Change within concealed text disallowed.")
1757 opened
1758 first)
1759 (goto-char beg)
1760 (while (< (point) end)
1761 (when (allout-hidden-p)
1762 (allout-show-to-offshoot)
1763 (if (allout-hidden-p)
1764 (save-excursion (forward-char 1)
1765 (allout-show-to-offshoot)))
1766 (when (not first)
1767 (setq opened t)
1768 (setq first (point))))
1769 (goto-char (if (featurep 'xemacs)
1770 (next-property-change (1+ (point)) nil end)
1771 (next-char-property-change (1+ (point)) end))))
1772 (when first
1773 (goto-char first)
1774 (condition-case nil
1775 (if (not
1776 (yes-or-no-p
1777 (substitute-command-keys
4034b0e2 1778 (concat "Modify concealed text? (\"no\" just aborts,"
96b83743
EZ
1779 " \\[keyboard-quit] also reconceals) "))))
1780 (progn (goto-char start)
1781 (error "Concealed-text change refused.")))
1782 (quit (allout-flag-region ol-start ol-end nil)
1783 (allout-flag-region ol-start ol-end t)
1784 (error "Concealed-text change abandoned, text reconcealed."))))
1785 (goto-char start))))
1786;;;_ > allout-before-change-handler (beg end)
1787(defun allout-before-change-handler (beg end)
1788 "Protect against changes to invisible text.
1789
1790See allout-overlay-interior-modification-handler for details.
1791
1792This before-change handler is used only where modification-hooks
1793overlay property is not supported."
4034b0e2 1794 (if (not (allout-mode-p))
96b83743
EZ
1795 nil
1796 (allout-overlay-interior-modification-handler nil nil beg end nil)))
1797;;;_ > allout-isearch-end-handler (&optional overlay)
1798(defun allout-isearch-end-handler (&optional overlay)
1799 "Reconcile allout outline exposure on arriving in hidden text after isearch.
1800
1801Optional OVERLAY parameter is for when this function is used by
1802`isearch-open-invisible' overlay property. It is otherwise unused, so this
1803function can also be used as an `isearch-mode-end-hook'."
1804
1805 (if (and (allout-mode-p) (allout-hidden-p))
1806 (allout-show-to-offshoot)))
1807
fd5359c6 1808;;;_ #3 Internal Position State-Tracking - "allout-recent-*" funcs
19b84ba3 1809;;; All the basic outline functions that directly do string matches to
1977b8f6 1810;;; evaluate heading prefix location set the variables
fd5359c6
MR
1811;;; `allout-recent-prefix-beginning' and `allout-recent-prefix-end'
1812;;; when successful. Functions starting with `allout-recent-' all
19b84ba3
RS
1813;;; use this state, providing the means to avoid redundant searches
1814;;; for just-established data. This optimization can provide
1815;;; significant speed improvement, but it must be employed carefully.
fd5359c6
MR
1816;;;_ = allout-recent-prefix-beginning
1817(defvar allout-recent-prefix-beginning 0
c567ac01 1818 "Buffer point of the start of the last topic prefix encountered.")
fd5359c6
MR
1819(make-variable-buffer-local 'allout-recent-prefix-beginning)
1820;;;_ = allout-recent-prefix-end
1821(defvar allout-recent-prefix-end 0
c567ac01 1822 "Buffer point of the end of the last topic prefix encountered.")
fd5359c6
MR
1823(make-variable-buffer-local 'allout-recent-prefix-end)
1824;;;_ = allout-recent-end-of-subtree
1825(defvar allout-recent-end-of-subtree 0
2265e017 1826 "Buffer point last returned by `allout-end-of-current-subtree'.")
fd5359c6
MR
1827(make-variable-buffer-local 'allout-recent-end-of-subtree)
1828;;;_ > allout-prefix-data (beg end)
d82979ea 1829(defmacro allout-prefix-data (beg end)
fd5359c6
MR
1830 "Register allout-prefix state data - BEGINNING and END of prefix.
1831
1832For reference by `allout-recent' funcs. Returns BEGINNING."
1833 `(setq allout-recent-prefix-end ,end
d82979ea 1834 allout-recent-prefix-beginning ,beg))
fd5359c6
MR
1835;;;_ > allout-recent-depth ()
1836(defmacro allout-recent-depth ()
19b84ba3 1837 "Return depth of last heading encountered by an outline maneuvering function.
c567ac01
RS
1838
1839All outline functions which directly do string matches to assess
2265e017
MR
1840headings set the variables `allout-recent-prefix-beginning' and
1841`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01
RS
1842to return the current depth."
1843
fd5359c6
MR
1844 '(max 1 (- allout-recent-prefix-end
1845 allout-recent-prefix-beginning
1846 allout-header-subtraction)))
1847;;;_ > allout-recent-prefix ()
1848(defmacro allout-recent-prefix ()
2265e017 1849 "Like `allout-recent-depth', but returns text of last encountered prefix.
c567ac01
RS
1850
1851All outline functions which directly do string matches to assess
2265e017
MR
1852headings set the variables `allout-recent-prefix-beginning' and
1853`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01 1854to return the current depth."
fd5359c6
MR
1855 '(buffer-substring allout-recent-prefix-beginning
1856 allout-recent-prefix-end))
1857;;;_ > allout-recent-bullet ()
1858(defmacro allout-recent-bullet ()
1859 "Like allout-recent-prefix, but returns bullet of last encountered prefix.
c567ac01
RS
1860
1861All outline functions which directly do string matches to assess
2265e017
MR
1862headings set the variables `allout-recent-prefix-beginning' and
1863`allout-recent-prefix-end' if successful. This function uses those settings
c567ac01 1864to return the current depth of the most recently matched topic."
fd5359c6
MR
1865 '(buffer-substring (1- allout-recent-prefix-end)
1866 allout-recent-prefix-end))
c567ac01 1867
19b84ba3 1868;;;_ #4 Navigation
c567ac01 1869
46771bb3 1870;;;_ - Position Assessment
c567ac01 1871;;;_ : Location Predicates
fd5359c6
MR
1872;;;_ > allout-on-current-heading-p ()
1873(defun allout-on-current-heading-p ()
19b84ba3
RS
1874 "Return non-nil if point is on current visible topics' header line.
1875
1876Actually, returns prefix beginning point."
1977b8f6 1877 (save-excursion
96b83743 1878 (allout-beginning-of-current-line)
fd5359c6
MR
1879 (and (looking-at allout-regexp)
1880 (allout-prefix-data (match-beginning 0) (match-end 0)))))
1881;;;_ > allout-on-heading-p ()
1882(defalias 'allout-on-heading-p 'allout-on-current-heading-p)
1883;;;_ > allout-e-o-prefix-p ()
1884(defun allout-e-o-prefix-p ()
19b84ba3 1885 "True if point is located where current topic prefix ends, heading begins."
c567ac01 1886 (and (save-excursion (beginning-of-line)
fd5359c6
MR
1887 (looking-at allout-regexp))
1888 (= (point)(save-excursion (allout-end-of-prefix)(point)))))
c567ac01 1889;;;_ : Location attributes
fd5359c6 1890;;;_ > allout-depth ()
96b83743
EZ
1891(defun allout-depth ()
1892 "Return depth of topic most immediately containing point.
1893
1894Return zero if point is not within any topic.
1895
1896Like `allout-current-depth', but respects hidden as well as visible topics."
9179616f 1897 (save-excursion
96b83743
EZ
1898 (let ((start-point (point)))
1899 (if (and (allout-goto-prefix)
1900 (not (< start-point (point))))
1901 (allout-recent-depth)
1902 (progn
1903 ;; Oops, no prefix, zero prefix data:
1904 (allout-prefix-data (point)(point))
1905 ;; ... and return 0:
1906 0)))))
fd5359c6 1907;;;_ > allout-current-depth ()
96b83743
EZ
1908(defun allout-current-depth ()
1909 "Return depth of visible topic most immediately containing point.
1910
1911Return zero if point is not within any topic."
1912 (save-excursion
1913 (if (allout-back-to-current-heading)
1914 (max 1
1915 (- allout-recent-prefix-end
1916 allout-recent-prefix-beginning
1917 allout-header-subtraction))
1918 0)))
fd5359c6
MR
1919;;;_ > allout-get-current-prefix ()
1920(defun allout-get-current-prefix ()
c567ac01 1921 "Topic prefix of the current topic."
1977b8f6 1922 (save-excursion
fd5359c6
MR
1923 (if (allout-goto-prefix)
1924 (allout-recent-prefix))))
1925;;;_ > allout-get-bullet ()
1926(defun allout-get-bullet ()
c567ac01 1927 "Return bullet of containing topic (visible or not)."
1977b8f6 1928 (save-excursion
fd5359c6
MR
1929 (and (allout-goto-prefix)
1930 (allout-recent-bullet))))
1931;;;_ > allout-current-bullet ()
1932(defun allout-current-bullet ()
c567ac01 1933 "Return bullet of current (visible) topic heading, or none if none found."
96b83743 1934 (condition-case nil
1977b8f6 1935 (save-excursion
fd5359c6
MR
1936 (allout-back-to-current-heading)
1937 (buffer-substring (- allout-recent-prefix-end 1)
1938 allout-recent-prefix-end))
1977b8f6 1939 ;; Quick and dirty provision, ostensibly for missing bullet:
9179616f 1940 ('args-out-of-range nil))
1977b8f6 1941 )
fd5359c6
MR
1942;;;_ > allout-get-prefix-bullet (prefix)
1943(defun allout-get-prefix-bullet (prefix)
c567ac01 1944 "Return the bullet of the header prefix string PREFIX."
1977b8f6
RS
1945 ;; Doesn't make sense if we're old-style prefixes, but this just
1946 ;; oughtn't be called then, so forget about it...
fd5359c6 1947 (if (string-match allout-regexp prefix)
1977b8f6 1948 (substring prefix (1- (match-end 0)) (match-end 0))))
fd5359c6
MR
1949;;;_ > allout-sibling-index (&optional depth)
1950(defun allout-sibling-index (&optional depth)
9179616f
DL
1951 "Item number of this prospective topic among its siblings.
1952
e126900f 1953If optional arg DEPTH is greater than current depth, then we're
9179616f
DL
1954opening a new level, and return 0.
1955
1956If less than this depth, ascend to that depth and count..."
1957
1958 (save-excursion
1959 (cond ((and depth (<= depth 0) 0))
fd5359c6 1960 ((or (not depth) (= depth (allout-depth)))
9179616f 1961 (let ((index 1))
fd5359c6 1962 (while (allout-previous-sibling (allout-recent-depth) nil)
9179616f
DL
1963 (setq index (1+ index)))
1964 index))
fd5359c6
MR
1965 ((< depth (allout-recent-depth))
1966 (allout-ascend-to-depth depth)
1967 (allout-sibling-index))
9179616f 1968 (0))))
fd5359c6
MR
1969;;;_ > allout-topic-flat-index ()
1970(defun allout-topic-flat-index ()
9179616f
DL
1971 "Return a list indicating point's numeric section.subsect.subsubsect...
1972Outermost is first."
fd5359c6
MR
1973 (let* ((depth (allout-depth))
1974 (next-index (allout-sibling-index depth))
9179616f
DL
1975 (rev-sibls nil))
1976 (while (> next-index 0)
1977 (setq rev-sibls (cons next-index rev-sibls))
1978 (setq depth (1- depth))
fd5359c6 1979 (setq next-index (allout-sibling-index depth)))
9179616f
DL
1980 rev-sibls)
1981 )
1977b8f6 1982
96b83743
EZ
1983;;;_ - Navigation routines
1984;;;_ > allout-beginning-of-current-line ()
1985(defun allout-beginning-of-current-line ()
1986 "Like beginning of line, but to visible text."
1987
1988 ;; XXX We would use `(move-beginning-of-line 1)', but it gets
1989 ;; stuck on some hidden newlines, eg at column 80, as of GNU Emacs 22.0.50.
1990 ;; Conversely, `beginning-of-line' can make no progress in other
1991 ;; situations. Both are necessary, in the order used below.
1992 (move-beginning-of-line 1)
1993 (beginning-of-line)
1994 (while (or (not (bolp)) (allout-hidden-p))
1995 (beginning-of-line)
1996 (if (or (allout-hidden-p) (not (bolp)))
1997 (forward-char -1))))
1998;;;_ > allout-end-of-current-line ()
1999(defun allout-end-of-current-line ()
2000 "Move to the end of line, past concealed text if any."
2001 ;; XXX This is for symmetry with `allout-beginning-of-current-line' -
2002 ;; `move-end-of-line' doesn't suffer the same problem as
2003 ;; `move-beginning-of-line'.
2004 (end-of-line)
2005 (while (allout-hidden-p)
2006 (end-of-line)
2007 (if (allout-hidden-p) (forward-char 1))))
fd5359c6
MR
2008;;;_ > allout-next-heading ()
2009(defsubst allout-next-heading ()
c567ac01
RS
2010 "Move to the heading for the topic \(possibly invisible) before this one.
2011
2012Returns the location of the heading, or nil if none found."
2013
9179616f 2014 (if (and (bobp) (not (eobp)))
c567ac01
RS
2015 (forward-char 1))
2016
fd5359c6
MR
2017 (if (re-search-forward allout-line-boundary-regexp nil 0)
2018 (allout-prefix-data ; Got valid location state - set vars:
9179616f 2019 (goto-char (or (match-beginning 2)
fd5359c6
MR
2020 allout-recent-prefix-beginning))
2021 (or (match-end 2) allout-recent-prefix-end))))
96b83743 2022;;;_ > allout-this-or-next-heading
fd5359c6 2023(defun allout-this-or-next-heading ()
8d118843 2024 "Position cursor on current or next heading."
fd5359c6
MR
2025 ;; A throwaway non-macro that is defined after allout-next-heading
2026 ;; and usable by allout-mode.
2027 (if (not (allout-goto-prefix)) (allout-next-heading)))
2028;;;_ > allout-previous-heading ()
2029(defmacro allout-previous-heading ()
19b84ba3 2030 "Move to the prior \(possibly invisible) heading line.
c567ac01
RS
2031
2032Return the location of the beginning of the heading, or nil if not found."
2033
2034 '(if (bobp)
2035 nil
fd5359c6 2036 (allout-goto-prefix)
c567ac01
RS
2037 (if
2038 ;; searches are unbounded and return nil if failed:
fd5359c6
MR
2039 (or (re-search-backward allout-line-boundary-regexp nil 0)
2040 (looking-at allout-bob-regexp))
19b84ba3 2041 (progn ; Got valid location state - set vars:
fd5359c6 2042 (allout-prefix-data
c567ac01 2043 (goto-char (or (match-beginning 2)
fd5359c6
MR
2044 allout-recent-prefix-beginning))
2045 (or (match-end 2) allout-recent-prefix-end))))))
96b83743
EZ
2046;;;_ > allout-get-invisibility-overlay ()
2047(defun allout-get-invisibility-overlay ()
2048 "Return the overlay at point that dictates allout invisibility."
2049 (let ((overlays (overlays-at (point)))
2050 got)
2051 (while (and overlays (not got))
2052 (if (equal (overlay-get (car overlays) 'invisible) 'allout)
2053 (setq got (car overlays))))
2054 got))
2055;;;_ > allout-back-to-visible-text ()
2056(defun allout-back-to-visible-text ()
2057 "Move to most recent prior character that is visible, and return point."
2058 (if (allout-hidden-p)
2059 (goto-char (overlay-start (allout-get-invisibility-overlay))))
2060 (point))
c567ac01
RS
2061
2062;;;_ - Subtree Charting
2063;;;_ " These routines either produce or assess charts, which are
2064;;; nested lists of the locations of topics within a subtree.
2065;;;
2066;;; Use of charts enables efficient navigation of subtrees, by
2067;;; requiring only a single regexp-search based traversal, to scope
2068;;; out the subtopic locations. The chart then serves as the basis
9179616f
DL
2069;;; for assessment or adjustment of the subtree, without redundant
2070;;; traversal of the structure.
c567ac01 2071
fd5359c6
MR
2072;;;_ > allout-chart-subtree (&optional levels orig-depth prev-depth)
2073(defun allout-chart-subtree (&optional levels orig-depth prev-depth)
19b84ba3
RS
2074 "Produce a location \"chart\" of subtopics of the containing topic.
2075
a0776d6b 2076Optional argument LEVELS specifies the depth \(relative to start
d82979ea
EZ
2077depth) for the chart. Subsequent optional args are not for public
2078use.
2079
2080Point is left at the end of the subtree.
19b84ba3 2081
d82979ea 2082Charts are used to capture outline structure, so that outline-altering
19b84ba3
RS
2083routines need assess the structure only once, and then use the chart
2084for their elaborate manipulations.
2085
2086Topics are entered in the chart so the last one is at the car.
2087The entry for each topic consists of an integer indicating the point
2088at the beginning of the topic. Charts for offspring consists of a
2089list containing, recursively, the charts for the respective subtopics.
2090The chart for a topics' offspring precedes the entry for the topic
2091itself.
2092
d82979ea
EZ
2093The other function parameters are for internal recursion, and should
2094not be specified by external callers. ORIG-DEPTH is depth of topic at
2095starting point, and PREV-DEPTH is depth of prior topic."
19b84ba3 2096
353e2ef2 2097 (let ((original (not orig-depth)) ; `orig-depth' set only in recursion.
19b84ba3
RS
2098 chart curr-depth)
2099
2100 (if original ; Just starting?
2101 ; Register initial settings and
2102 ; position to first offspring:
fd5359c6 2103 (progn (setq orig-depth (allout-depth))
19b84ba3 2104 (or prev-depth (setq prev-depth (1+ orig-depth)))
fd5359c6 2105 (allout-next-heading)))
c567ac01 2106
19b84ba3
RS
2107 ;; Loop over the current levels' siblings. Besides being more
2108 ;; efficient than tail-recursing over a level, it avoids exceeding
e126900f 2109 ;; the typically quite constrained Emacs max-lisp-eval-depth.
9179616f 2110 ;;
19b84ba3
RS
2111 ;; Probably would speed things up to implement loop-based stack
2112 ;; operation rather than recursing for lower levels. Bah.
9179616f 2113
c567ac01 2114 (while (and (not (eobp))
19b84ba3 2115 ; Still within original topic?
fd5359c6 2116 (< orig-depth (setq curr-depth (allout-recent-depth)))
19b84ba3
RS
2117 (cond ((= prev-depth curr-depth)
2118 ;; Register this one and move on:
2119 (setq chart (cons (point) chart))
2120 (if (and levels (<= levels 1))
2121 ;; At depth limit - skip sublevels:
fd5359c6 2122 (or (allout-next-sibling curr-depth)
19b84ba3
RS
2123 ;; or no more siblings - proceed to
2124 ;; next heading at lesser depth:
e6a9aec7 2125 (while (and (<= curr-depth
fd5359c6
MR
2126 (allout-recent-depth))
2127 (allout-next-heading))))
2128 (allout-next-heading)))
19b84ba3
RS
2129
2130 ((and (< prev-depth curr-depth)
2131 (or (not levels)
2132 (> levels 0)))
2133 ;; Recurse on deeper level of curr topic:
2134 (setq chart
fd5359c6 2135 (cons (allout-chart-subtree (and levels
19b84ba3
RS
2136 (1- levels))
2137 orig-depth
2138 curr-depth)
2139 chart))
2140 ;; ... then continue with this one.
2141 )
2142
2143 ;; ... else nil if we've ascended back to prev-depth.
2144
2145 )))
2146
2147 (if original ; We're at the last sibling on
2148 ; the original level. Position
2149 ; to the end of it:
c567ac01 2150 (progn (and (not (eobp)) (forward-char -1))
96b83743
EZ
2151 (and (= (preceding-char) ?\n)
2152 (= (aref (buffer-substring (max 1 (- (point) 3))
2153 (point))
2154 1)
2155 ?\n)
19b84ba3 2156 (forward-char -1))
fd5359c6 2157 (setq allout-recent-end-of-subtree (point))))
353e2ef2 2158
c567ac01
RS
2159 chart ; (nreverse chart) not necessary,
2160 ; and maybe not preferable.
2161 ))
fd5359c6
MR
2162;;;_ > allout-chart-siblings (&optional start end)
2163(defun allout-chart-siblings (&optional start end)
c567ac01 2164 "Produce a list of locations of this and succeeding sibling topics.
fd5359c6 2165Effectively a top-level chart of siblings. See `allout-chart-subtree'
c567ac01
RS
2166for an explanation of charts."
2167 (save-excursion
fd5359c6 2168 (if (allout-goto-prefix)
c567ac01 2169 (let ((chart (list (point))))
fd5359c6 2170 (while (allout-next-sibling)
c567ac01 2171 (setq chart (cons (point) chart)))
19b84ba3 2172 (if chart (setq chart (nreverse chart)))))))
fd5359c6
MR
2173;;;_ > allout-chart-to-reveal (chart depth)
2174(defun allout-chart-to-reveal (chart depth)
c567ac01 2175
19b84ba3 2176 "Return a flat list of hidden points in subtree CHART, up to DEPTH.
c567ac01 2177
19b84ba3 2178Note that point can be left at any of the points on chart, or at the
c567ac01
RS
2179start point."
2180
2181 (let (result here)
2182 (while (and (or (eq depth t) (> depth 0))
2183 chart)
2184 (setq here (car chart))
2185 (if (listp here)
fd5359c6 2186 (let ((further (allout-chart-to-reveal here (or (eq depth t)
c567ac01
RS
2187 (1- depth)))))
2188 ;; We're on the start of a subtree - recurse with it, if there's
2189 ;; more depth to go:
2190 (if further (setq result (append further result)))
2191 (setq chart (cdr chart)))
2192 (goto-char here)
96b83743 2193 (if (allout-hidden-p)
c567ac01
RS
2194 (setq result (cons here result)))
2195 (setq chart (cdr chart))))
2196 result))
fd5359c6 2197;;;_ X allout-chart-spec (chart spec &optional exposing)
e126900f
JB
2198;; (defun allout-chart-spec (chart spec &optional exposing)
2199;; "Not yet \(if ever) implemented.
2200
2201;; Produce exposure directives given topic/subtree CHART and an exposure SPEC.
2202
2203;; Exposure spec indicates the locations to be exposed and the prescribed
2204;; exposure status. Optional arg EXPOSING is an integer, with 0
2205;; indicating pending concealment, anything higher indicating depth to
2206;; which subtopic headers should be exposed, and negative numbers
2207;; indicating (negative of) the depth to which subtopic headers and
2208;; bodies should be exposed.
2209
2210;; The produced list can have two types of entries. Bare numbers
2211;; indicate points in the buffer where topic headers that should be
2212;; exposed reside.
2213
2214;; - bare negative numbers indicates that the topic starting at the
2215;; point which is the negative of the number should be opened,
2216;; including their entries.
2217;; - bare positive values indicate that this topic header should be
2218;; opened.
2219;; - Lists signify the beginning and end points of regions that should
2220;; be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
2221;; exposure:"
2222;; (while spec
2223;; (cond ((listp spec)
2224;; )
2225;; )
2226;; (setq spec (cdr spec)))
2227;; )
c567ac01
RS
2228
2229;;;_ - Within Topic
fd5359c6
MR
2230;;;_ > allout-goto-prefix ()
2231(defun allout-goto-prefix ()
9179616f 2232 "Put point at beginning of immediately containing outline topic.
19b84ba3 2233
9179616f 2234Goes to most immediate subsequent topic if none immediately containing.
19b84ba3
RS
2235
2236Not sensitive to topic visibility.
c567ac01 2237
d27081f5 2238Returns the point at the beginning of the prefix, or nil if none."
c567ac01 2239
19b84ba3
RS
2240 (let (done)
2241 (while (and (not done)
96b83743 2242 (search-backward "\n" nil 1))
19b84ba3 2243 (forward-char 1)
fd5359c6
MR
2244 (if (looking-at allout-regexp)
2245 (setq done (allout-prefix-data (match-beginning 0)
19b84ba3
RS
2246 (match-end 0)))
2247 (forward-char -1)))
2248 (if (bobp)
fd5359c6
MR
2249 (cond ((looking-at allout-regexp)
2250 (allout-prefix-data (match-beginning 0)(match-end 0)))
2251 ((allout-next-heading))
19b84ba3
RS
2252 (done))
2253 done)))
fd5359c6
MR
2254;;;_ > allout-end-of-prefix ()
2255(defun allout-end-of-prefix (&optional ignore-decorations)
19b84ba3
RS
2256 "Position cursor at beginning of header text.
2257
2258If optional IGNORE-DECORATIONS is non-nil, put just after bullet,
2259otherwise skip white space between bullet and ensuing text."
c567ac01 2260
fd5359c6 2261 (if (not (allout-goto-prefix))
1977b8f6
RS
2262 nil
2263 (let ((match-data (match-data)))
2264 (goto-char (match-end 0))
c567ac01
RS
2265 (if ignore-decorations
2266 t
2267 (while (looking-at "[0-9]") (forward-char 1))
2268 (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1)))
9179616f 2269 (store-match-data match-data))
1977b8f6 2270 ;; Reestablish where we are:
fd5359c6
MR
2271 (allout-current-depth)))
2272;;;_ > allout-current-bullet-pos ()
2273(defun allout-current-bullet-pos ()
c567ac01
RS
2274 "Return position of current \(visible) topic's bullet."
2275
fd5359c6 2276 (if (not (allout-current-depth))
c567ac01
RS
2277 nil
2278 (1- (match-end 0))))
fd5359c6
MR
2279;;;_ > allout-back-to-current-heading ()
2280(defun allout-back-to-current-heading ()
96b83743
EZ
2281 "Move to heading line of current topic, or beginning if already on the line.
2282
2283Return value of point, unless we started outside of (before any) topics,
2284in which case we return nil."
2285
2286 (allout-beginning-of-current-line)
2287 (if (or (allout-on-current-heading-p)
2288 (and (re-search-backward (concat "^\\(" allout-regexp "\\)")
2289 nil 'move)
2290 (progn (while (allout-hidden-p)
2291 (allout-beginning-of-current-line)
2292 (if (not (looking-at allout-regexp))
2293 (re-search-backward (concat
2294 "^\\(" allout-regexp "\\)")
2295 nil 'move)))
2296 (allout-prefix-data (match-beginning 1)
2297 (match-end 1)))))
2298 (if (interactive-p)
2299 (allout-end-of-prefix)
2300 (point))))
fd5359c6
MR
2301;;;_ > allout-back-to-heading ()
2302(defalias 'allout-back-to-heading 'allout-back-to-current-heading)
96b83743
EZ
2303;;;_ > allout-pre-next-prefix ()
2304(defun allout-pre-next-prefix ()
1977b8f6
RS
2305 "Skip forward to just before the next heading line.
2306
c567ac01 2307Returns that character position."
1977b8f6 2308
fd5359c6 2309 (if (re-search-forward allout-line-boundary-regexp nil 'move)
c567ac01 2310 (prog1 (goto-char (match-beginning 0))
fd5359c6 2311 (allout-prefix-data (match-beginning 2)(match-end 2)))))
96b83743
EZ
2312;;;_ > allout-end-of-subtree (&optional current include-trailing-blank)
2313(defun allout-end-of-subtree (&optional current include-trailing-blank)
d82979ea
EZ
2314 "Put point at the end of the last leaf in the containing topic.
2315
96b83743
EZ
2316Optional CURRENT means put point at the end of the containing
2317visible topic.
2318
2319Optional INCLUDE-TRAILING-BLANK means include a trailing blank line, if
2320any, as part of the subtree. Otherwise, that trailing blank will be
2321excluded as delimiting whitespace between topics.
d82979ea
EZ
2322
2323Returns the value of point."
2324 (interactive "P")
2325 (if current
2326 (allout-back-to-current-heading)
2327 (allout-goto-prefix))
fd5359c6
MR
2328 (let ((level (allout-recent-depth)))
2329 (allout-next-heading)
1977b8f6 2330 (while (and (not (eobp))
fd5359c6
MR
2331 (> (allout-recent-depth) level))
2332 (allout-next-heading))
c567ac01 2333 (and (not (eobp)) (forward-char -1))
96b83743 2334 (if (and (not include-trailing-blank) (= ?\n (preceding-char)))
c567ac01 2335 (forward-char -1))
fd5359c6 2336 (setq allout-recent-end-of-subtree (point))))
96b83743
EZ
2337;;;_ > allout-end-of-current-subtree (&optional include-trailing-blank)
2338(defun allout-end-of-current-subtree (&optional include-trailing-blank)
2339
d82979ea
EZ
2340 "Put point at end of last leaf in currently visible containing topic.
2341
96b83743
EZ
2342Optional INCLUDE-TRAILING-BLANK means include a trailing blank line, if
2343any, as part of the subtree. Otherwise, that trailing blank will be
2344excluded as delimiting whitespace between topics.
2345
d82979ea
EZ
2346Returns the value of point."
2347 (interactive)
96b83743 2348 (allout-end-of-subtree t include-trailing-blank))
fd5359c6
MR
2349;;;_ > allout-beginning-of-current-entry ()
2350(defun allout-beginning-of-current-entry ()
d82979ea 2351 "When not already there, position point at beginning of current topic header.
c567ac01
RS
2352
2353If already there, move cursor to bullet for hot-spot operation.
46771bb3 2354\(See `allout-mode' doc string for details of hot-spot operation.)"
1977b8f6 2355 (interactive)
c567ac01 2356 (let ((start-point (point)))
46771bb3 2357 (move-beginning-of-line 1)
fd5359c6 2358 (allout-end-of-prefix)
c567ac01
RS
2359 (if (and (interactive-p)
2360 (= (point) start-point))
fd5359c6 2361 (goto-char (allout-current-bullet-pos)))))
96b83743
EZ
2362;;;_ > allout-end-of-entry (&optional inclusive)
2363(defun allout-end-of-entry (&optional inclusive)
2364 "Position the point at the end of the current topics' entry.
2365
2366Optional INCLUSIVE means also include trailing empty line, if any. When
2367unset, whitespace between items separates them even when the items are
2368collapsed."
1977b8f6 2369 (interactive)
96b83743
EZ
2370 (allout-pre-next-prefix)
2371 (if (and (not inclusive) (not (bobp)) (= ?\n (preceding-char)))
2372 (forward-char -1))
2373 (point))
fd5359c6
MR
2374;;;_ > allout-end-of-current-heading ()
2375(defun allout-end-of-current-heading ()
9179616f 2376 (interactive)
fd5359c6 2377 (allout-beginning-of-current-entry)
96b83743 2378 (search-forward "\n" nil t)
d82979ea 2379 (forward-char -1))
fd5359c6 2380(defalias 'allout-end-of-heading 'allout-end-of-current-heading)
d82979ea
EZ
2381;;;_ > allout-get-body-text ()
2382(defun allout-get-body-text ()
2383 "Return the unmangled body text of the topic immediately containing point."
2384 (save-excursion
2385 (allout-end-of-prefix)
96b83743 2386 (if (not (search-forward "\n" nil t))
d82979ea
EZ
2387 nil
2388 (backward-char 1)
2389 (let ((pre-body (point)))
2390 (if (not pre-body)
2391 nil
96b83743 2392 (allout-end-of-entry t)
d82979ea
EZ
2393 (if (not (= pre-body (point)))
2394 (buffer-substring-no-properties (1+ pre-body) (point))))
2395 )
2396 )
2397 )
2398 )
1977b8f6 2399
c567ac01 2400;;;_ - Depth-wise
fd5359c6
MR
2401;;;_ > allout-ascend-to-depth (depth)
2402(defun allout-ascend-to-depth (depth)
c567ac01 2403 "Ascend to depth DEPTH, returning depth if successful, nil if not."
fd5359c6 2404 (if (and (> depth 0)(<= depth (allout-depth)))
1977b8f6 2405 (let ((last-good (point)))
fd5359c6 2406 (while (and (< depth (allout-depth))
1977b8f6 2407 (setq last-good (point))
fd5359c6
MR
2408 (allout-beginning-of-level)
2409 (allout-previous-heading)))
2410 (if (= (allout-recent-depth) depth)
2411 (progn (goto-char allout-recent-prefix-beginning)
1977b8f6 2412 depth)
d82979ea
EZ
2413 (goto-char last-good)
2414 nil))
2415 (if (interactive-p) (allout-end-of-prefix))))
fd5359c6
MR
2416;;;_ > allout-ascend ()
2417(defun allout-ascend ()
9179616f 2418 "Ascend one level, returning t if successful, nil if not."
d82979ea
EZ
2419 (prog1
2420 (if (allout-beginning-of-level)
2421 (allout-previous-heading))
2422 (if (interactive-p) (allout-end-of-prefix))))
fd5359c6
MR
2423;;;_ > allout-descend-to-depth (depth)
2424(defun allout-descend-to-depth (depth)
19b84ba3
RS
2425 "Descend to depth DEPTH within current topic.
2426
2427Returning depth if successful, nil if not."
1977b8f6 2428 (let ((start-point (point))
fd5359c6 2429 (start-depth (allout-depth)))
1977b8f6 2430 (while
fd5359c6
MR
2431 (and (> (allout-depth) 0)
2432 (not (= depth (allout-recent-depth))) ; ... not there yet
2433 (allout-next-heading) ; ... go further
2434 (< start-depth (allout-recent-depth)))) ; ... still in topic
2435 (if (and (> (allout-depth) 0)
2436 (= (allout-recent-depth) depth))
1977b8f6
RS
2437 depth
2438 (goto-char start-point)
2439 nil))
2440 )
fd5359c6 2441;;;_ > allout-up-current-level (arg &optional dont-complain)
d82979ea 2442(defun allout-up-current-level (arg &optional dont-complain)
19b84ba3
RS
2443 "Move out ARG levels from current visible topic.
2444
2445Positions on heading line of containing topic. Error if unable to
2446ascend that far, or nil if unable to ascend but optional arg
2447DONT-COMPLAIN is non-nil."
d82979ea 2448 (interactive "p")
fd5359c6
MR
2449 (allout-back-to-current-heading)
2450 (let ((present-level (allout-recent-depth))
19b84ba3 2451 (last-good (point))
96b83743 2452 failed)
1977b8f6 2453 ;; Loop for iterating arg:
fd5359c6 2454 (while (and (> (allout-recent-depth) 1)
1977b8f6 2455 (> arg 0)
19b84ba3
RS
2456 (not (bobp))
2457 (not failed))
2458 (setq last-good (point))
1977b8f6 2459 ;; Loop for going back over current or greater depth:
fd5359c6
MR
2460 (while (and (not (< (allout-recent-depth) present-level))
2461 (or (allout-previous-visible-heading 1)
19b84ba3 2462 (not (setq failed present-level)))))
fd5359c6 2463 (setq present-level (allout-current-depth))
1977b8f6 2464 (setq arg (- arg 1)))
19b84ba3
RS
2465 (if (or failed
2466 (> arg 0))
2467 (progn (goto-char last-good)
d82979ea 2468 (if (interactive-p) (allout-end-of-prefix))
19b84ba3 2469 (if (not dont-complain)
6a05d05f 2470 (error "Can't ascend past outermost level")
d82979ea 2471 (if (interactive-p) (allout-end-of-prefix))
19b84ba3 2472 nil))
d82979ea 2473 (if (interactive-p) (allout-end-of-prefix))
fd5359c6 2474 allout-recent-prefix-beginning)))
1977b8f6 2475
c567ac01 2476;;;_ - Linear
fd5359c6
MR
2477;;;_ > allout-next-sibling (&optional depth backward)
2478(defun allout-next-sibling (&optional depth backward)
2265e017 2479 "Like `allout-forward-current-level', but respects invisible topics.
1977b8f6 2480
c567ac01 2481Traverse at optional DEPTH, or current depth if none specified.
1977b8f6 2482
c567ac01 2483Go backward if optional arg BACKWARD is non-nil.
1977b8f6 2484
c567ac01 2485Return depth if successful, nil otherwise."
1977b8f6
RS
2486
2487 (if (and backward (bobp))
2488 nil
fd5359c6 2489 (let ((start-depth (or depth (allout-depth)))
1977b8f6 2490 (start-point (point))
c567ac01 2491 last-depth)
1977b8f6 2492 (while (and (not (if backward (bobp) (eobp)))
fd5359c6
MR
2493 (if backward (allout-previous-heading)
2494 (allout-next-heading))
2495 (> (setq last-depth (allout-recent-depth)) start-depth)))
1977b8f6 2496 (if (and (not (eobp))
fd5359c6
MR
2497 (and (> (or last-depth (allout-depth)) 0)
2498 (= (allout-recent-depth) start-depth)))
2499 allout-recent-prefix-beginning
1977b8f6 2500 (goto-char start-point)
fd5359c6 2501 (if depth (allout-depth) start-depth)
c567ac01 2502 nil))))
fd5359c6
MR
2503;;;_ > allout-previous-sibling (&optional depth backward)
2504(defun allout-previous-sibling (&optional depth backward)
d82979ea 2505 "Like `allout-forward-current-level' backwards, respecting invisible topics.
1977b8f6 2506
c567ac01 2507Optional DEPTH specifies depth to traverse, default current depth.
1977b8f6 2508
c567ac01 2509Optional BACKWARD reverses direction.
1977b8f6 2510
c567ac01 2511Return depth if successful, nil otherwise."
fd5359c6 2512 (allout-next-sibling depth (not backward))
1977b8f6 2513 )
fd5359c6
MR
2514;;;_ > allout-snug-back ()
2515(defun allout-snug-back ()
539d7736 2516 "Position cursor at end of previous topic.
19b84ba3
RS
2517
2518Presumes point is at the start of a topic prefix."
c567ac01
RS
2519 (if (or (bobp) (eobp))
2520 nil
2521 (forward-char -1))
96b83743 2522 (if (or (bobp) (not (= ?\n (preceding-char))))
c567ac01 2523 nil
96b83743 2524 (forward-char -1))
c567ac01 2525 (point))
fd5359c6
MR
2526;;;_ > allout-beginning-of-level ()
2527(defun allout-beginning-of-level ()
c567ac01 2528 "Go back to the first sibling at this level, visible or not."
fd5359c6
MR
2529 (allout-end-of-level 'backward))
2530;;;_ > allout-end-of-level (&optional backward)
2531(defun allout-end-of-level (&optional backward)
c567ac01 2532 "Go to the last sibling at this level, visible or not."
1977b8f6 2533
fd5359c6
MR
2534 (let ((depth (allout-depth)))
2535 (while (allout-previous-sibling depth nil))
2536 (prog1 (allout-recent-depth)
d82979ea 2537 (if (interactive-p) (allout-end-of-prefix)))))
fd5359c6
MR
2538;;;_ > allout-next-visible-heading (arg)
2539(defun allout-next-visible-heading (arg)
19b84ba3 2540 "Move to the next ARG'th visible heading line, backward if arg is negative.
c567ac01 2541
96b83743 2542Move to buffer limit in indicated direction if headings are exhausted."
1977b8f6 2543
1977b8f6 2544 (interactive "p")
c567ac01
RS
2545 (let* ((backward (if (< arg 0) (setq arg (* -1 arg))))
2546 (step (if backward -1 1))
2547 prev got)
2548
2549 (while (> arg 0) ; limit condition
2550 (while (and (not (if backward (bobp)(eobp))) ; boundary condition
19b84ba3 2551 ;; Move, skipping over all those concealed lines:
96b83743
EZ
2552 (prog1 (condition-case nil (or (line-move step) t)
2553 (error nil))
2554 (allout-beginning-of-current-line))
fd5359c6 2555 (not (setq got (looking-at allout-regexp)))))
c567ac01
RS
2556 ;; Register this got, it may be the last:
2557 (if got (setq prev got))
2558 (setq arg (1- arg)))
2559 (cond (got ; Last move was to a prefix:
fd5359c6
MR
2560 (allout-prefix-data (match-beginning 0) (match-end 0))
2561 (allout-end-of-prefix))
c567ac01 2562 (prev ; Last move wasn't, but prev was:
fd5359c6 2563 (allout-prefix-data (match-beginning 0) (match-end 0)))
c567ac01 2564 ((not backward) (end-of-line) nil))))
fd5359c6
MR
2565;;;_ > allout-previous-visible-heading (arg)
2566(defun allout-previous-visible-heading (arg)
c567ac01 2567 "Move to the previous heading line.
1977b8f6 2568
c567ac01 2569With argument, repeats or can move forward if negative.
2265e017 2570A heading line is one that starts with a `*' (or that `allout-regexp'
c567ac01 2571matches)."
1977b8f6 2572 (interactive "p")
fd5359c6
MR
2573 (allout-next-visible-heading (- arg)))
2574;;;_ > allout-forward-current-level (arg)
d82979ea 2575(defun allout-forward-current-level (arg)
19b84ba3 2576 "Position point at the next heading of the same level.
1977b8f6 2577
19b84ba3 2578Takes optional repeat-count, goes backward if count is negative.
1977b8f6 2579
19b84ba3 2580Returns resulting position, else nil if none found."
d82979ea 2581 (interactive "p")
fd5359c6 2582 (let ((start-depth (allout-current-depth))
19b84ba3
RS
2583 (start-arg arg)
2584 (backward (> 0 arg))
2585 last-depth
2586 (last-good (point))
2587 at-boundary)
2588 (if (= 0 start-depth)
2589 (error "No siblings, not in a topic..."))
2590 (if backward (setq arg (* -1 arg)))
2591 (while (not (or (zerop arg)
2592 at-boundary))
2593 (while (and (not (if backward (bobp) (eobp)))
fd5359c6
MR
2594 (if backward (allout-previous-visible-heading 1)
2595 (allout-next-visible-heading 1))
2596 (> (setq last-depth (allout-recent-depth)) start-depth)))
19b84ba3
RS
2597 (if (and last-depth (= last-depth start-depth)
2598 (not (if backward (bobp) (eobp))))
2599 (setq last-good (point)
2600 arg (1- arg))
2601 (setq at-boundary t)))
2602 (if (and (not (eobp))
2603 (= arg 0)
fd5359c6
MR
2604 (and (> (or last-depth (allout-depth)) 0)
2605 (= (allout-recent-depth) start-depth)))
2606 allout-recent-prefix-beginning
19b84ba3 2607 (goto-char last-good)
d82979ea 2608 (if (not (interactive-p))
19b84ba3 2609 nil
fd5359c6 2610 (allout-end-of-prefix)
6a05d05f 2611 (error "Hit %s level %d topic, traversed %d of %d requested"
19b84ba3 2612 (if backward "first" "last")
fd5359c6 2613 (allout-recent-depth)
19b84ba3
RS
2614 (- (abs start-arg) arg)
2615 (abs start-arg))))))
fd5359c6 2616;;;_ > allout-backward-current-level (arg)
d82979ea 2617(defun allout-backward-current-level (arg)
fd5359c6 2618 "Inverse of `allout-forward-current-level'."
d82979ea
EZ
2619 (interactive "p")
2620 (if (interactive-p)
19b84ba3 2621 (let ((current-prefix-arg (* -1 arg)))
fd5359c6
MR
2622 (call-interactively 'allout-forward-current-level))
2623 (allout-forward-current-level (* -1 arg))))
c567ac01 2624
19b84ba3 2625;;;_ #5 Alteration
c567ac01
RS
2626
2627;;;_ - Fundamental
fd5359c6
MR
2628;;;_ = allout-post-goto-bullet
2629(defvar allout-post-goto-bullet nil
2630 "Outline internal var, for `allout-pre-command-business' hot-spot operation.
19b84ba3
RS
2631
2632When set, tells post-processing to reposition on topic bullet, and
2265e017 2633then unset it. Set by `allout-pre-command-business' when implementing
19b84ba3
RS
2634hot-spot operation, where literal characters typed over a topic bullet
2635are mapped to the command of the corresponding control-key on the
2265e017 2636`allout-mode-map'.")
fd5359c6
MR
2637(make-variable-buffer-local 'allout-post-goto-bullet)
2638;;;_ > allout-post-command-business ()
2639(defun allout-post-command-business ()
2265e017 2640 "Outline `post-command-hook' function.
c567ac01 2641
2265e017 2642- Implement (and clear) `allout-post-goto-bullet', for hot-spot
c567ac01
RS
2643 outline commands.
2644
96b83743 2645- Decrypt topic currently being edited if it was encrypted for a save."
c567ac01
RS
2646
2647 ; Apply any external change func:
fd5359c6 2648 (if (not (allout-mode-p)) ; In allout-mode.
19b84ba3 2649 nil
d82979ea
EZ
2650
2651 (if (and (boundp 'allout-after-save-decrypt)
2652 allout-after-save-decrypt)
2653 (allout-after-saves-handler))
2654
96b83743 2655 ;; Implement -post-goto-bullet, if set:
fd5359c6
MR
2656 (if (and allout-post-goto-bullet
2657 (allout-current-bullet-pos))
2658 (progn (goto-char (allout-current-bullet-pos))
2659 (setq allout-post-goto-bullet nil)))
19b84ba3 2660 ))
fd5359c6
MR
2661;;;_ > allout-pre-command-business ()
2662(defun allout-pre-command-business ()
2265e017 2663 "Outline `pre-command-hook' function for outline buffers.
58edceeb 2664Implements special behavior when cursor is on bullet character.
c567ac01 2665
58edceeb
JB
2666When the cursor is on the bullet character, self-insert characters are
2667reinterpreted as the corresponding control-character in the
2668`allout-mode-map'. The `allout-mode' `post-command-hook' insures that
2669the cursor which has moved as a result of such reinterpretation is
2670positioned on the bullet character of the destination topic.
c567ac01 2671
9179616f
DL
2672The upshot is that you can get easy, single (ie, unmodified) key
2673outline maneuvering operations by positioning the cursor on the bullet
58edceeb
JB
2674char. When in this mode you can use regular cursor-positioning
2675command/keystrokes to relocate the cursor off of a bullet character to
2676return to regular interpretation of self-insert characters."
d82979ea 2677
fd5359c6 2678 (if (not (allout-mode-p))
9179616f 2679 nil
9179616f
DL
2680 ;; Hot-spot navigation provisions:
2681 (if (and (eq this-command 'self-insert-command)
fd5359c6 2682 (eq (point)(allout-current-bullet-pos)))
9179616f
DL
2683 (let* ((this-key-num (cond
2684 ((numberp last-command-char)
2685 last-command-char)
d82979ea
EZ
2686 ;; Only xemacs has characterp.
2687 ((and (fboundp 'characterp)
0949617b
EZ
2688 (apply 'characterp
2689 (list last-command-char)))
2690 (apply 'char-to-int (list last-command-char)))
9179616f
DL
2691 (t 0)))
2692 mapped-binding)
2693 (if (zerop this-key-num)
2694 nil
c567ac01
RS
2695 ; Map upper-register literals
2696 ; to lower register:
9179616f
DL
2697 (if (<= 96 this-key-num)
2698 (setq this-key-num (- this-key-num 32)))
c567ac01 2699 ; Check if we have a literal:
9179616f
DL
2700 (if (and (<= 64 this-key-num)
2701 (>= 96 this-key-num))
2702 (setq mapped-binding
fd5359c6
MR
2703 (lookup-key 'allout-mode-map
2704 (concat allout-command-prefix
9179616f
DL
2705 (char-to-string (- this-key-num
2706 64))))))
2707 (if mapped-binding
fd5359c6 2708 (setq allout-post-goto-bullet t
9179616f 2709 this-command mapped-binding)))))))
fd5359c6
MR
2710;;;_ > allout-find-file-hook ()
2711(defun allout-find-file-hook ()
4034b0e2 2712 "Activate `allout-mode' on non-nil `allout-auto-activation', `allout-layout'.
fd5359c6
MR
2713
2714See `allout-init' for setup instructions."
2715 (if (and allout-auto-activation
2716 (not (allout-mode-p))
2717 allout-layout)
2718 (allout-mode t)))
c567ac01
RS
2719
2720;;;_ - Topic Format Assessment
fd5359c6
MR
2721;;;_ > allout-solicit-alternate-bullet (depth &optional current-bullet)
2722(defun allout-solicit-alternate-bullet (depth &optional current-bullet)
1977b8f6 2723
19b84ba3
RS
2724 "Prompt for and return a bullet char as an alternative to the current one.
2725
2726Offer one suitable for current depth DEPTH as default."
1977b8f6 2727
9179616f 2728 (let* ((default-bullet (or (and (stringp current-bullet) current-bullet)
fd5359c6
MR
2729 (allout-bullet-for-depth depth)))
2730 (sans-escapes (regexp-sans-escapes allout-bullets-string))
9179616f
DL
2731 choice)
2732 (save-excursion
fd5359c6 2733 (goto-char (allout-current-bullet-pos))
9179616f
DL
2734 (setq choice (solicit-char-in-string
2735 (format "Select bullet: %s ('%s' default): "
2736 sans-escapes
2737 default-bullet)
2738 sans-escapes
2739 t)))
2740 (message "")
1977b8f6
RS
2741 (if (string= choice "") default-bullet choice))
2742 )
fd5359c6
MR
2743;;;_ > allout-distinctive-bullet (bullet)
2744(defun allout-distinctive-bullet (bullet)
e126900f 2745 "True if BULLET is one of those on `allout-distinctive-bullets-string'."
fd5359c6
MR
2746 (string-match (regexp-quote bullet) allout-distinctive-bullets-string))
2747;;;_ > allout-numbered-type-prefix (&optional prefix)
2748(defun allout-numbered-type-prefix (&optional prefix)
c567ac01 2749 "True if current header prefix bullet is numbered bullet."
fd5359c6
MR
2750 (and allout-numbered-bullet
2751 (string= allout-numbered-bullet
1977b8f6 2752 (if prefix
fd5359c6
MR
2753 (allout-get-prefix-bullet prefix)
2754 (allout-get-bullet)))))
d82979ea
EZ
2755;;;_ > allout-encrypted-type-prefix (&optional prefix)
2756(defun allout-encrypted-type-prefix (&optional prefix)
2757 "True if current header prefix bullet is for an encrypted entry \(body)."
2758 (and allout-topic-encryption-bullet
2759 (string= allout-topic-encryption-bullet
2760 (if prefix
2761 (allout-get-prefix-bullet prefix)
2762 (allout-get-bullet)))))
fd5359c6
MR
2763;;;_ > allout-bullet-for-depth (&optional depth)
2764(defun allout-bullet-for-depth (&optional depth)
19b84ba3 2765 "Return outline topic bullet suited to optional DEPTH, or current depth."
1977b8f6 2766 ;; Find bullet in plain-bullets-string modulo DEPTH.
fd5359c6
MR
2767 (if allout-stylish-prefixes
2768 (char-to-string (aref allout-plain-bullets-string
1977b8f6 2769 (% (max 0 (- depth 2))
fd5359c6
MR
2770 allout-plain-bullets-string-len)))
2771 allout-primary-bullet)
1977b8f6
RS
2772 )
2773
c567ac01 2774;;;_ - Topic Production
fd5359c6
MR
2775;;;_ > allout-make-topic-prefix (&optional prior-bullet
2776(defun allout-make-topic-prefix (&optional prior-bullet
1977b8f6
RS
2777 new
2778 depth
2779 solicit
2780 number-control
2781 index)
2782 ;; Depth null means use current depth, non-null means we're either
2783 ;; opening a new topic after current topic, lower or higher, or we're
2784 ;; changing level of current topic.
2785 ;; Solicit dominates specified bullet-char.
c567ac01 2786;;;_ . Doc string:
19b84ba3 2787 "Generate a topic prefix suitable for optional arg DEPTH, or current depth.
c567ac01
RS
2788
2789All the arguments are optional.
2790
2791PRIOR-BULLET indicates the bullet of the prefix being changed, or
2792nil if none. This bullet may be preserved (other options
2265e017 2793notwithstanding) if it is on the `allout-distinctive-bullets-string',
c567ac01
RS
2794for instance.
2795
2796Second arg NEW indicates that a new topic is being opened after the
2797topic at point, if non-nil. Default bullet for new topics, eg, may
2798be set (contingent to other args) to numbered bullets if previous
2799sibling is one. The implication otherwise is that the current topic
2800is being adjusted - shifted or rebulleted - and we don't consider
2801bullet or previous sibling.
2802
2803Third arg DEPTH forces the topic prefix to that depth, regardless of
2804the current topics' depth.
2805
9179616f
DL
2806If SOLICIT is non-nil, then the choice of bullet is solicited from
2807user. If it's a character, then that character is offered as the
2808default, otherwise the one suited to the context \(according to
2809distinction or depth) is offered. \(This overrides other options,
2810including, eg, a distinctive PRIOR-BULLET.) If non-nil, then the
2811context-specific bullet is used.
c567ac01 2812
fd5359c6 2813Fifth arg, NUMBER-CONTROL, matters only if `allout-numbered-bullet'
c567ac01
RS
2814is non-nil *and* soliciting was not explicitly invoked. Then
2815NUMBER-CONTROL non-nil forces prefix to either numbered or
2816denumbered format, depending on the value of the sixth arg, INDEX.
2817
2818\(Note that NUMBER-CONTROL does *not* apply to level 1 topics. Sorry...)
2819
2820If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
2821the prefix of the topic is forced to be numbered. Non-nil
2822NUMBER-CONTROL and nil INDEX forces non-numbered format on the
2823bullet. Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
2824that the index for the numbered prefix will be derived, by counting
2825siblings back to start of level. If INDEX is a number, then that
2826number is used as the index for the numbered prefix (allowing, eg,
a0776d6b 2827sequential renumbering to not require this function counting back the
c567ac01
RS
2828index for each successive sibling)."
2829;;;_ . Code:
1977b8f6
RS
2830 ;; The options are ordered in likely frequence of use, most common
2831 ;; highest, least lowest. Ie, more likely to be doing prefix
2832 ;; adjustments than soliciting, and yet more than numbering.
2833 ;; Current prefix is least dominant, but most likely to be commonly
2834 ;; specified...
2835
2836 (let* (body
2837 numbering
2838 denumbering
fd5359c6
MR
2839 (depth (or depth (allout-depth)))
2840 (header-lead allout-header-prefix)
1977b8f6
RS
2841 (bullet-char
2842
2843 ;; Getting value for bullet char is practically the whole job:
2844
2845 (cond
2846 ; Simplest situation - level 1:
fd5359c6 2847 ((<= depth 1) (setq header-lead "") allout-primary-bullet)
1977b8f6 2848 ; Simple, too: all asterisks:
fd5359c6 2849 (allout-old-style-prefixes
1977b8f6
RS
2850 ;; Cheat - make body the whole thing, null out header-lead and
2851 ;; bullet-char:
2852 (setq body (make-string depth
fd5359c6 2853 (string-to-char allout-primary-bullet)))
1977b8f6
RS
2854 (setq header-lead "")
2855 "")
2856
2857 ;; (Neither level 1 nor old-style, so we're space padding.
2858 ;; Sneak it in the condition of the next case, whatever it is.)
2859
2860 ;; Solicitation overrides numbering and other cases:
2861 ((progn (setq body (make-string (- depth 2) ?\ ))
2862 ;; The actual condition:
2863 solicit)
fd5359c6 2864 (let* ((got (allout-solicit-alternate-bullet depth solicit)))
1977b8f6 2865 ;; Gotta check whether we're numbering and got a numbered bullet:
fd5359c6 2866 (setq numbering (and allout-numbered-bullet
1977b8f6 2867 (not (and number-control (not index)))
fd5359c6 2868 (string= got allout-numbered-bullet)))
1977b8f6
RS
2869 ;; Now return what we got, regardless:
2870 got))
2871
2872 ;; Numbering invoked through args:
fd5359c6 2873 ((and allout-numbered-bullet number-control)
1977b8f6 2874 (if (setq numbering (not (setq denumbering (not index))))
fd5359c6 2875 allout-numbered-bullet
19b84ba3 2876 (if (and prior-bullet
fd5359c6 2877 (not (string= allout-numbered-bullet
19b84ba3
RS
2878 prior-bullet)))
2879 prior-bullet
fd5359c6 2880 (allout-bullet-for-depth depth))))
1977b8f6
RS
2881
2882 ;;; Neither soliciting nor controlled numbering ;;;
2883 ;;; (may be controlled denumbering, tho) ;;;
2884
2885 ;; Check wrt previous sibling:
2886 ((and new ; only check for new prefixes
fd5359c6
MR
2887 (<= depth (allout-depth))
2888 allout-numbered-bullet ; ... & numbering enabled
1977b8f6
RS
2889 (not denumbering)
2890 (let ((sibling-bullet
2891 (save-excursion
2892 ;; Locate correct sibling:
fd5359c6
MR
2893 (or (>= depth (allout-depth))
2894 (allout-ascend-to-depth depth))
2895 (allout-get-bullet))))
1977b8f6 2896 (if (and sibling-bullet
fd5359c6 2897 (string= allout-numbered-bullet sibling-bullet))
1977b8f6
RS
2898 (setq numbering sibling-bullet)))))
2899
2900 ;; Distinctive prior bullet?
2901 ((and prior-bullet
fd5359c6 2902 (allout-distinctive-bullet prior-bullet)
1977b8f6 2903 ;; Either non-numbered:
fd5359c6
MR
2904 (or (not (and allout-numbered-bullet
2905 (string= prior-bullet allout-numbered-bullet)))
1977b8f6
RS
2906 ;; or numbered, and not denumbering:
2907 (setq numbering (not denumbering)))
2908 ;; Here 'tis:
2909 prior-bullet))
2910
2911 ;; Else, standard bullet per depth:
fd5359c6 2912 ((allout-bullet-for-depth depth)))))
1977b8f6
RS
2913
2914 (concat header-lead
2915 body
2916 bullet-char
2917 (if numbering
2918 (format "%d" (cond ((and index (numberp index)) index)
fd5359c6
MR
2919 (new (1+ (allout-sibling-index depth)))
2920 ((allout-sibling-index))))))
1977b8f6
RS
2921 )
2922 )
96b83743
EZ
2923;;;_ > allout-open-topic (relative-depth &optional before offer-recent-bullet)
2924(defun allout-open-topic (relative-depth &optional before offer-recent-bullet)
d82979ea 2925 "Open a new topic at depth DEPTH.
19b84ba3
RS
2926
2927New topic is situated after current one, unless optional flag BEFORE
96b83743
EZ
2928is non-nil, or unless current line is completely empty - lacking even
2929whitespace - in which case open is done on the current line.
2930
2931When adding an offspring, it will be added immediately after the parent if
2932the other offspring are exposed, or after the last child if the offspring
2933are hidden. \(The intervening offspring will be exposed in the latter
2934case.)
c567ac01 2935
96b83743 2936If OFFER-RECENT-BULLET is true, offer to use the bullet of the prior sibling.
9179616f 2937
c567ac01
RS
2938Nuances:
2939
2940- Creation of new topics is with respect to the visible topic
2941 containing the cursor, regardless of intervening concealed ones.
2942
2943- New headers are generally created after/before the body of a
2944 topic. However, they are created right at cursor location if the
2945 cursor is on a blank line, even if that breaks the current topic
2946 body. This is intentional, to provide a simple means for
2947 deliberately dividing topic bodies.
2948
2949- Double spacing of topic lists is preserved. Also, the first
2950 level two topic is created double-spaced (and so would be
2951 subsequent siblings, if that's left intact). Otherwise,
2952 single-spacing is used.
2953
2954- Creation of sibling or nested topics is with respect to the topic
2955 you're starting from, even when creating backwards. This way you
2956 can easily create a sibling in front of the current topic without
a0776d6b 2957 having to go to its preceding sibling, and then open forward
c567ac01 2958 from there."
1977b8f6 2959
96b83743 2960 (allout-beginning-of-current-line)
fd5359c6 2961 (let* ((depth (+ (allout-current-depth) relative-depth))
1977b8f6
RS
2962 (opening-on-blank (if (looking-at "^\$")
2963 (not (setq before nil))))
d82979ea
EZ
2964 ;; bunch o vars set while computing ref-topic
2965 opening-numbered
d82979ea
EZ
2966 ref-depth
2967 ref-bullet
1977b8f6
RS
2968 (ref-topic (save-excursion
2969 (cond ((< relative-depth 0)
fd5359c6 2970 (allout-ascend-to-depth depth))
1977b8f6 2971 ((>= relative-depth 1) nil)
fd5359c6
MR
2972 (t (allout-back-to-current-heading)))
2973 (setq ref-depth (allout-recent-depth))
9179616f 2974 (setq ref-bullet
fd5359c6
MR
2975 (if (> allout-recent-prefix-end 1)
2976 (allout-recent-bullet)
9179616f 2977 ""))
1977b8f6
RS
2978 (setq opening-numbered
2979 (save-excursion
fd5359c6 2980 (and allout-numbered-bullet
1977b8f6 2981 (or (<= relative-depth 0)
fd5359c6
MR
2982 (allout-descend-to-depth depth))
2983 (if (allout-numbered-type-prefix)
2984 allout-numbered-bullet))))
1977b8f6
RS
2985 (point)))
2986 dbl-space
c567ac01 2987 doing-beginning)
1977b8f6
RS
2988
2989 (if (not opening-on-blank)
2990 ; Positioning and vertical
2991 ; padding - only if not
2992 ; opening-on-blank:
353e2ef2 2993 (progn
1977b8f6
RS
2994 (goto-char ref-topic)
2995 (setq dbl-space ; Determine double space action:
c567ac01
RS
2996 (or (and (<= relative-depth 0) ; not descending;
2997 (save-excursion
a0776d6b 2998 ;; at b-o-b or preceded by a blank line?
c567ac01
RS
2999 (or (> 0 (forward-line -1))
3000 (looking-at "^\\s-*$")
3001 (bobp)))
1977b8f6 3002 (save-excursion
c567ac01 3003 ;; succeeded by a blank line?
fd5359c6 3004 (allout-end-of-current-subtree)
96b83743 3005 (looking-at "\n\n")))
1977b8f6
RS
3006 (and (= ref-depth 1)
3007 (or before
3008 (= depth 1)
3009 (save-excursion
3010 ;; Don't already have following
3011 ;; vertical padding:
96b83743 3012 (not (allout-pre-next-prefix)))))))
1977b8f6 3013
96b83743
EZ
3014 ;; Position to prior heading, if inserting backwards, and not
3015 ;; going outwards:
c567ac01 3016 (if (and before (>= relative-depth 0))
fd5359c6 3017 (progn (allout-back-to-current-heading)
1977b8f6 3018 (setq doing-beginning (bobp))
c567ac01 3019 (if (not (bobp))
fd5359c6 3020 (allout-previous-heading)))
c567ac01 3021 (if (and before (bobp))
96b83743 3022 (open-line 1)))
1977b8f6 3023
c567ac01 3024 (if (<= relative-depth 0)
1977b8f6
RS
3025 ;; Not going inwards, don't snug up:
3026 (if doing-beginning
96b83743
EZ
3027 (if (not dbl-space)
3028 (open-line 1)
3029 (open-line 2))
c567ac01
RS
3030 (if before
3031 (progn (end-of-line)
96b83743
EZ
3032 (allout-pre-next-prefix)
3033 (while (and (= ?\n (following-char))
3034 (save-excursion
3035 (forward-char 1)
3036 (allout-hidden-p)))
c567ac01
RS
3037 (forward-char 1))
3038 (if (not (looking-at "^$"))
96b83743
EZ
3039 (open-line 1)))
3040 (allout-end-of-current-subtree)
3041 (if (looking-at "\n\n") (forward-char 1))))
3042 ;; Going inwards - double-space if first offspring is
3043 ;; double-spaced, otherwise snug up.
3044 (allout-end-of-entry)
46771bb3
EZ
3045 (if (eobp)
3046 (newline 1)
3047 (line-move 1))
96b83743
EZ
3048 (allout-beginning-of-current-line)
3049 (backward-char 1)
1977b8f6
RS
3050 (if (bolp)
3051 ;; Blank lines between current header body and next
3052 ;; header - get to last substantive (non-white-space)
3053 ;; line in body:
96b83743
EZ
3054 (progn (setq dbl-space t)
3055 (re-search-backward "[^ \t\n]" nil t)))
3056 (if (looking-at "\n\n")
3057 (setq dbl-space t))
1977b8f6 3058 (if (save-excursion
fd5359c6 3059 (allout-next-heading)
96b83743
EZ
3060 (when (> (allout-recent-depth) ref-depth)
3061 ;; This is an offspring.
3062 (forward-line -1)
3063 (looking-at "^\\s-*$")))
1977b8f6 3064 (progn (forward-line 1)
96b83743 3065 (open-line 1)
d82979ea 3066 (forward-line 1)))
96b83743
EZ
3067 (allout-end-of-current-line))
3068
1977b8f6 3069 ;;(if doing-beginning (goto-char doing-beginning))
c567ac01 3070 (if (not (bobp))
d82979ea
EZ
3071 ;; We insert a newline char rather than using open-line to
3072 ;; avoid rear-stickiness inheritence of read-only property.
c567ac01
RS
3073 (progn (if (and (not (> depth ref-depth))
3074 (not before))
96b83743
EZ
3075 (open-line 1)
3076 (if (and (not dbl-space) (> depth ref-depth))
3077 (newline 1)
c567ac01 3078 (if dbl-space
96b83743 3079 (open-line 1)
c567ac01 3080 (if (not before)
96b83743
EZ
3081 (newline 1)))))
3082 (if (and dbl-space (not (> relative-depth 0)))
3083 (newline 1))
c567ac01
RS
3084 (if (and (not (eobp))
3085 (not (bolp)))
3086 (forward-char 1))))
1977b8f6 3087 ))
96b83743
EZ
3088 (insert (concat (allout-make-topic-prefix opening-numbered t depth)
3089 " "))
3090
3091 (allout-rebullet-heading (and offer-recent-bullet ref-bullet)
3092 depth nil nil t)
3093 (if (> relative-depth 0)
3094 (save-excursion (goto-char ref-topic)
3095 (allout-show-children)))
d82979ea 3096 (end-of-line)
1977b8f6
RS
3097 )
3098 )
fd5359c6
MR
3099;;;_ > allout-open-subtopic (arg)
3100(defun allout-open-subtopic (arg)
c567ac01
RS
3101 "Open new topic header at deeper level than the current one.
3102
3103Negative universal arg means to open deeper, but place the new topic
3104prior to the current one."
1977b8f6 3105 (interactive "p")
d82979ea 3106 (allout-open-topic 1 (> 0 arg) (< 1 arg)))
fd5359c6
MR
3107;;;_ > allout-open-sibtopic (arg)
3108(defun allout-open-sibtopic (arg)
19b84ba3
RS
3109 "Open new topic header at same level as the current one.
3110
9179616f
DL
3111Positive universal arg means to use the bullet of the prior sibling.
3112
19b84ba3 3113Negative universal arg means to place the new topic prior to the current
c567ac01 3114one."
1977b8f6 3115 (interactive "p")
d82979ea 3116 (allout-open-topic 0 (> 0 arg) (not (= 1 arg))))
fd5359c6
MR
3117;;;_ > allout-open-supertopic (arg)
3118(defun allout-open-supertopic (arg)
c567ac01 3119 "Open new topic header at shallower level than the current one.
19b84ba3 3120
c567ac01
RS
3121Negative universal arg means to open shallower, but place the new
3122topic prior to the current one."
1977b8f6
RS
3123
3124 (interactive "p")
d82979ea 3125 (allout-open-topic -1 (> 0 arg) (< 1 arg)))
c567ac01
RS
3126
3127;;;_ - Outline Alteration
3128;;;_ : Topic Modification
fd5359c6
MR
3129;;;_ = allout-former-auto-filler
3130(defvar allout-former-auto-filler nil
2265e017 3131 "Name of modal fill function being wrapped by `allout-auto-fill'.")
fd5359c6
MR
3132;;;_ > allout-auto-fill ()
3133(defun allout-auto-fill ()
aad94676 3134 "`allout-mode' autofill function.
19b84ba3
RS
3135
3136Maintains outline hanging topic indentation if
fd5359c6
MR
3137`allout-use-hanging-indents' is set."
3138 (let ((fill-prefix (if allout-use-hanging-indents
c567ac01
RS
3139 ;; Check for topic header indentation:
3140 (save-excursion
3141 (beginning-of-line)
fd5359c6 3142 (if (looking-at allout-regexp)
c567ac01
RS
3143 ;; ... construct indentation to account for
3144 ;; length of topic prefix:
fd5359c6 3145 (make-string (progn (allout-end-of-prefix)
c567ac01 3146 (current-column))
96b83743
EZ
3147 ?\ )))))
3148 (use-auto-fill-function (or allout-outside-normal-auto-fill-function
3149 auto-fill-function
3150 'do-auto-fill)))
fd5359c6 3151 (if (or allout-former-auto-filler allout-use-hanging-indents)
96b83743 3152 (funcall use-auto-fill-function))))
fd5359c6
MR
3153;;;_ > allout-reindent-body (old-depth new-depth &optional number)
3154(defun allout-reindent-body (old-depth new-depth &optional number)
e126900f 3155 "Reindent body lines which were indented at OLD-DEPTH to NEW-DEPTH.
c567ac01
RS
3156
3157Optional arg NUMBER indicates numbering is being added, and it must
a0776d6b 3158be accommodated.
c567ac01
RS
3159
3160Note that refill of indented paragraphs is not done."
1977b8f6
RS
3161
3162 (save-excursion
fd5359c6 3163 (allout-end-of-prefix)
c567ac01
RS
3164 (let* ((new-margin (current-column))
3165 excess old-indent-begin old-indent-end
c567ac01
RS
3166 ;; We want the column where the header-prefix text started
3167 ;; *before* the prefix was changed, so we infer it relative
3168 ;; to the new margin and the shift in depth:
3169 (old-margin (+ old-depth (- new-margin new-depth))))
353e2ef2 3170
c567ac01 3171 ;; Process lines up to (but excluding) next topic header:
fd5359c6 3172 (allout-unprotected
c567ac01
RS
3173 (save-match-data
3174 (while
96b83743 3175 (and (re-search-forward "\n\\(\\s-*\\)"
c567ac01
RS
3176 nil
3177 t)
3178 ;; Register the indent data, before we reset the
353e2ef2 3179 ;; match data with a subsequent `looking-at':
c567ac01
RS
3180 (setq old-indent-begin (match-beginning 1)
3181 old-indent-end (match-end 1))
fd5359c6 3182 (not (looking-at allout-regexp)))
d82979ea
EZ
3183 (if (> 0 (setq excess (- (- old-indent-end old-indent-begin)
3184 old-margin)))
c567ac01
RS
3185 ;; Text starts left of old margin - don't adjust:
3186 nil
3187 ;; Text was hanging at or right of old left margin -
3188 ;; reindent it, preserving its existing indentation
3189 ;; beyond the old margin:
3190 (delete-region old-indent-begin old-indent-end)
d82979ea 3191 (indent-to (+ new-margin excess (current-column))))))))))
fd5359c6
MR
3192;;;_ > allout-rebullet-current-heading (arg)
3193(defun allout-rebullet-current-heading (arg)
9179616f
DL
3194 "Solicit new bullet for current visible heading."
3195 (interactive "p")
3196 (let ((initial-col (current-column))
fd5359c6 3197 (on-bullet (eq (point)(allout-current-bullet-pos)))
9179616f
DL
3198 (backwards (if (< arg 0)
3199 (setq arg (* arg -1)))))
3200 (while (> arg 0)
fd5359c6
MR
3201 (save-excursion (allout-back-to-current-heading)
3202 (allout-end-of-prefix)
3203 (allout-rebullet-heading t ;;; solicit
9179616f
DL
3204 nil ;;; depth
3205 nil ;;; number-control
3206 nil ;;; index
3207 t)) ;;; do-successors
3208 (setq arg (1- arg))
3209 (if (<= arg 0)
3210 nil
3211 (setq initial-col nil) ; Override positioning back to init col
3212 (if (not backwards)
fd5359c6
MR
3213 (allout-next-visible-heading 1)
3214 (allout-goto-prefix)
3215 (allout-next-visible-heading -1))))
9179616f 3216 (message "Done.")
fd5359c6 3217 (cond (on-bullet (goto-char (allout-current-bullet-pos)))
9179616f 3218 (initial-col (move-to-column initial-col)))))
fd5359c6
MR
3219;;;_ > allout-rebullet-heading (&optional solicit ...)
3220(defun allout-rebullet-heading (&optional solicit
1977b8f6
RS
3221 new-depth
3222 number-control
3223 index
3224 do-successors)
3225
c567ac01 3226 "Adjust bullet of current topic prefix.
1977b8f6 3227
d82979ea
EZ
3228All args are optional.
3229
9179616f
DL
3230If SOLICIT is non-nil, then the choice of bullet is solicited from
3231user. If it's a character, then that character is offered as the
3232default, otherwise the one suited to the context \(according to
3233distinction or depth) is offered. If non-nil, then the
3234context-specific bullet is just used.
1977b8f6 3235
d82979ea 3236Second arg DEPTH forces the topic prefix to that depth, regardless
9179616f 3237of the topic's current depth.
1977b8f6 3238
c567ac01 3239Third arg NUMBER-CONTROL can force the prefix to or away from
fd5359c6 3240numbered form. It has effect only if `allout-numbered-bullet' is
c567ac01
RS
3241non-nil and soliciting was not explicitly invoked (via first arg).
3242Its effect, numbering or denumbering, then depends on the setting
d82979ea 3243of the forth arg, INDEX.
1977b8f6 3244
d82979ea 3245If NUMBER-CONTROL is non-nil and forth arg INDEX is nil, then the
c567ac01
RS
3246prefix of the topic is forced to be non-numbered. Null index and
3247non-nil NUMBER-CONTROL forces denumbering. Non-nil INDEX (and
3248non-nil NUMBER-CONTROL) forces a numbered-prefix form. If non-nil
3249INDEX is a number, then that number is used for the numbered
3250prefix. Non-nil and non-number means that the index for the
d82979ea 3251numbered prefix will be derived by allout-make-topic-prefix.
1977b8f6 3252
c567ac01
RS
3253Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
3254siblings.
1977b8f6 3255
fd5359c6
MR
3256Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
3257and `allout-numbered-bullet', which all affect the behavior of
c567ac01 3258this function."
1977b8f6 3259
fd5359c6 3260 (let* ((current-depth (allout-depth))
1977b8f6 3261 (new-depth (or new-depth current-depth))
fd5359c6
MR
3262 (mb allout-recent-prefix-beginning)
3263 (me allout-recent-prefix-end)
1977b8f6 3264 (current-bullet (buffer-substring (- me 1) me))
fd5359c6 3265 (new-prefix (allout-make-topic-prefix current-bullet
1977b8f6
RS
3266 nil
3267 new-depth
3268 solicit
3269 number-control
3270 index)))
3271
c567ac01 3272 ;; Is new one is identical to old?
1977b8f6
RS
3273 (if (and (= current-depth new-depth)
3274 (string= current-bullet
3275 (substring new-prefix (1- (length new-prefix)))))
c567ac01 3276 ;; Nothing to do:
1977b8f6
RS
3277 t
3278
3279 ;; New prefix probably different from old:
c567ac01 3280 ; get rid of old one:
fd5359c6 3281 (allout-unprotected (delete-region mb me))
1977b8f6 3282 (goto-char mb)
c567ac01
RS
3283 ; Dispense with number if
3284 ; numbered-bullet prefix:
fd5359c6
MR
3285 (if (and allout-numbered-bullet
3286 (string= allout-numbered-bullet current-bullet)
1977b8f6 3287 (looking-at "[0-9]+"))
fd5359c6 3288 (allout-unprotected
c567ac01 3289 (delete-region (match-beginning 0)(match-end 0))))
1977b8f6 3290
c567ac01 3291 ; Put in new prefix:
fd5359c6 3292 (allout-unprotected (insert new-prefix))
1977b8f6 3293
d82979ea 3294 ;; Reindent the body if elected, margin changed, and not encrypted body:
fd5359c6 3295 (if (and allout-reindent-bodies
d82979ea
EZ
3296 (not (= new-depth current-depth))
3297 (not (allout-encrypted-topic-p)))
fd5359c6 3298 (allout-reindent-body current-depth new-depth))
1977b8f6 3299
c567ac01
RS
3300 ;; Recursively rectify successive siblings of orig topic if
3301 ;; caller elected for it:
3302 (if do-successors
3303 (save-excursion
fd5359c6 3304 (while (allout-next-sibling new-depth nil)
c567ac01
RS
3305 (setq index
3306 (cond ((numberp index) (1+ index))
fd5359c6
MR
3307 ((not number-control) (allout-sibling-index))))
3308 (if (allout-numbered-type-prefix)
3309 (allout-rebullet-heading nil ;;; solicit
c567ac01
RS
3310 new-depth ;;; new-depth
3311 number-control;;; number-control
3312 index ;;; index
3313 nil))))) ;;;(dont!)do-successors
3314 ) ; (if (and (= current-depth new-depth)...))
fd5359c6 3315 ) ; let* ((current-depth (allout-depth))...)
c567ac01 3316 ) ; defun
fd5359c6
MR
3317;;;_ > allout-rebullet-topic (arg)
3318(defun allout-rebullet-topic (arg)
d82979ea 3319 "Rebullet the visible topic containing point and all contained subtopics.
19b84ba3 3320
c567ac01 3321Descends into invisible as well as visible topics, however.
1977b8f6 3322
c567ac01 3323With repeat count, shift topic depth by that amount."
1977b8f6 3324 (interactive "P")
96b83743 3325 (let ((start-col (current-column)))
1977b8f6
RS
3326 (save-excursion
3327 ;; Normalize arg:
3328 (cond ((null arg) (setq arg 0))
3329 ((listp arg) (setq arg (car arg))))
3330 ;; Fill the user in, in case we're shifting a big topic:
3331 (if (not (zerop arg)) (message "Shifting..."))
fd5359c6
MR
3332 (allout-back-to-current-heading)
3333 (if (<= (+ (allout-recent-depth) arg) 0)
1977b8f6 3334 (error "Attempt to shift topic below level 1"))
fd5359c6 3335 (allout-rebullet-topic-grunt arg)
1977b8f6 3336 (if (not (zerop arg)) (message "Shifting... done.")))
c567ac01 3337 (move-to-column (max 0 (+ start-col arg)))))
fd5359c6
MR
3338;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...)
3339(defun allout-rebullet-topic-grunt (&optional relative-depth
1977b8f6
RS
3340 starting-depth
3341 starting-point
3342 index
3343 do-successors)
d82979ea
EZ
3344 "Like `allout-rebullet-topic', but on nearest containing topic
3345\(visible or not).
1977b8f6 3346
d82979ea 3347See `allout-rebullet-heading' for rebulleting behavior.
1977b8f6 3348
d82979ea 3349All arguments are optional.
1977b8f6 3350
d82979ea
EZ
3351First arg RELATIVE-DEPTH means to shift the depth of the entire
3352topic that amount.
e126900f 3353
d82979ea
EZ
3354The rest of the args are for internal recursive use by the function
3355itself. The are STARTING-DEPTH, STARTING-POINT, and INDEX."
1977b8f6
RS
3356
3357 (let* ((relative-depth (or relative-depth 0))
fd5359c6 3358 (new-depth (allout-depth))
1977b8f6
RS
3359 (starting-depth (or starting-depth new-depth))
3360 (on-starting-call (null starting-point))
3361 (index (or index
3362 ;; Leave index null on starting call, so rebullet-heading
3363 ;; calculates it at what might be new depth:
3364 (and (or (zerop relative-depth)
3365 (not on-starting-call))
fd5359c6 3366 (allout-sibling-index))))
1977b8f6
RS
3367 (moving-outwards (< 0 relative-depth))
3368 (starting-point (or starting-point (point))))
3369
3370 ;; Sanity check for excessive promotion done only on starting call:
3371 (and on-starting-call
3372 moving-outwards
3373 (> 0 (+ starting-depth relative-depth))
6a05d05f 3374 (error "Attempt to shift topic out beyond level 1")) ;;; ====>
1977b8f6
RS
3375
3376 (cond ((= starting-depth new-depth)
3377 ;; We're at depth to work on this one:
fd5359c6 3378 (allout-rebullet-heading nil ;;; solicit
1977b8f6
RS
3379 (+ starting-depth ;;; starting-depth
3380 relative-depth)
3381 nil ;;; number
3382 index ;;; index
3383 ;; Every contained topic will get hit,
3384 ;; and we have to get to outside ones
3385 ;; deliberately:
3386 nil) ;;; do-successors
3387 ;; ... and work on subsequent ones which are at greater depth:
3388 (setq index 0)
fd5359c6 3389 (allout-next-heading)
1977b8f6 3390 (while (and (not (eobp))
fd5359c6 3391 (< starting-depth (allout-recent-depth)))
1977b8f6 3392 (setq index (1+ index))
fd5359c6 3393 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
1977b8f6
RS
3394 (1+ starting-depth);;;starting-depth
3395 starting-point ;;; starting-point
3396 index))) ;;; index
3397
3398 ((< starting-depth new-depth)
3399 ;; Rare case - subtopic more than one level deeper than parent.
3400 ;; Treat this one at an even deeper level:
fd5359c6 3401 (allout-rebullet-topic-grunt relative-depth ;;; relative-depth
1977b8f6
RS
3402 new-depth ;;; starting-depth
3403 starting-point ;;; starting-point
3404 index))) ;;; index
3405
3406 (if on-starting-call
3407 (progn
3408 ;; Rectify numbering of former siblings of the adjusted topic,
3409 ;; if topic has changed depth
3410 (if (or do-successors
3411 (and (not (zerop relative-depth))
fd5359c6
MR
3412 (or (= (allout-recent-depth) starting-depth)
3413 (= (allout-recent-depth) (+ starting-depth
1977b8f6 3414 relative-depth)))))
fd5359c6 3415 (allout-rebullet-heading nil nil nil nil t))
1977b8f6
RS
3416 ;; Now rectify numbering of new siblings of the adjusted topic,
3417 ;; if depth has been changed:
3418 (progn (goto-char starting-point)
3419 (if (not (zerop relative-depth))
fd5359c6 3420 (allout-rebullet-heading nil nil nil nil t)))))
1977b8f6
RS
3421 )
3422 )
fd5359c6
MR
3423;;;_ > allout-renumber-to-depth (&optional depth)
3424(defun allout-renumber-to-depth (&optional depth)
19b84ba3
RS
3425 "Renumber siblings at current depth.
3426
3427Affects superior topics if optional arg DEPTH is less than current depth.
c567ac01
RS
3428
3429Returns final depth."
3430
3431 ;; Proceed by level, processing subsequent siblings on each,
3432 ;; ascending until we get shallower than the start depth:
3433
fd5359c6 3434 (let ((ascender (allout-depth))
9179616f 3435 was-eobp)
c567ac01 3436 (while (and (not (eobp))
fd5359c6
MR
3437 (allout-depth)
3438 (>= (allout-recent-depth) depth)
c567ac01
RS
3439 (>= ascender depth))
3440 ; Skip over all topics at
3441 ; lesser depths, which can not
3442 ; have been disturbed:
9179616f 3443 (while (and (not (setq was-eobp (eobp)))
fd5359c6
MR
3444 (> (allout-recent-depth) ascender))
3445 (allout-next-heading))
c567ac01 3446 ; Prime ascender for ascension:
fd5359c6
MR
3447 (setq ascender (1- (allout-recent-depth)))
3448 (if (>= (allout-recent-depth) depth)
3449 (allout-rebullet-heading nil ;;; solicit
c567ac01
RS
3450 nil ;;; depth
3451 nil ;;; number-control
3452 nil ;;; index
9179616f
DL
3453 t)) ;;; do-successors
3454 (if was-eobp (goto-char (point-max)))))
fd5359c6
MR
3455 (allout-recent-depth))
3456;;;_ > allout-number-siblings (&optional denumber)
3457(defun allout-number-siblings (&optional denumber)
c567ac01 3458 "Assign numbered topic prefix to this topic and its siblings.
1977b8f6 3459
c567ac01
RS
3460With universal argument, denumber - assign default bullet to this
3461topic and its siblings.
1977b8f6 3462
c567ac01
RS
3463With repeated universal argument (`^U^U'), solicit bullet for each
3464rebulleting each topic at this level."
1977b8f6
RS
3465
3466 (interactive "P")
3467
3468 (save-excursion
fd5359c6
MR
3469 (allout-back-to-current-heading)
3470 (allout-beginning-of-level)
3471 (let ((depth (allout-recent-depth))
c567ac01 3472 (index (if (not denumber) 1))
1977b8f6
RS
3473 (use-bullet (equal '(16) denumber))
3474 (more t))
3475 (while more
fd5359c6 3476 (allout-rebullet-heading use-bullet ;;; solicit
c567ac01 3477 depth ;;; depth
1977b8f6
RS
3478 t ;;; number-control
3479 index ;;; index
3480 nil) ;;; do-successors
3481 (if index (setq index (1+ index)))
fd5359c6
MR
3482 (setq more (allout-next-sibling depth nil))))))
3483;;;_ > allout-shift-in (arg)
3484(defun allout-shift-in (arg)
d82979ea
EZ
3485 "Increase depth of current heading and any topics collapsed within it.
3486
3487We disallow shifts that would result in the topic having a depth more than
3488one level greater than the immediately previous topic, to avoid containment
3489discontinuity. The first topic in the file can be adjusted to any positive
3490depth, however."
1977b8f6 3491 (interactive "p")
d82979ea
EZ
3492 (if (> arg 0)
3493 (save-excursion
3494 (allout-back-to-current-heading)
3495 (if (not (bobp))
3496 (let* ((current-depth (allout-recent-depth))
3497 (start-point (point))
3498 (predecessor-depth (progn
3499 (forward-char -1)
3500 (allout-goto-prefix)
3501 (if (< (point) start-point)
3502 (allout-recent-depth)
3503 0))))
3504 (if (and (> predecessor-depth 0)
3505 (> (+ current-depth arg)
3506 (1+ predecessor-depth)))
96b83743
EZ
3507 (error (concat "Disallowed shift deeper than"
3508 " containing topic's children.")))))))
fd5359c6
MR
3509 (allout-rebullet-topic arg))
3510;;;_ > allout-shift-out (arg)
3511(defun allout-shift-out (arg)
d82979ea
EZ
3512 "Decrease depth of current heading and any topics collapsed within it.
3513
3514We disallow shifts that would result in the topic having a depth more than
3515one level greater than the immediately previous topic, to avoid containment
3516discontinuity. The first topic in the file can be adjusted to any positive
3517depth, however."
1977b8f6 3518 (interactive "p")
d82979ea
EZ
3519 (if (< arg 0)
3520 (allout-shift-in (* arg -1)))
fd5359c6 3521 (allout-rebullet-topic (* arg -1)))
c567ac01 3522;;;_ : Surgery (kill-ring) functions with special provisions for outlines:
fd5359c6
MR
3523;;;_ > allout-kill-line (&optional arg)
3524(defun allout-kill-line (&optional arg)
c567ac01 3525 "Kill line, adjusting subsequent lines suitably for outline mode."
1977b8f6
RS
3526
3527 (interactive "*P")
d82979ea 3528
96b83743
EZ
3529 (if (or (not (allout-mode-p))
3530 (not (bolp))
3531 (not (looking-at allout-regexp)))
4034b0e2 3532 ;; Just do a regular kill:
96b83743
EZ
3533 (kill-line arg)
3534 ;; Ah, have to watch out for adjustments:
3535 (let* ((beg (point))
3536 (beg-hidden (allout-hidden-p))
3537 (end-hidden (save-excursion (allout-end-of-current-line)
3538 (allout-hidden-p)))
3539 (depth (allout-depth))
3540 (collapsed (allout-current-topic-collapsed-p)))
3541
3542 (if collapsed
3543 (put-text-property beg (1+ beg) 'allout-was-collapsed t)
3544 (remove-text-properties beg (1+ beg) '(allout-was-collapsed t)))
3545
3546 (if (and (not beg-hidden) (not end-hidden))
3547 (allout-unprotected (kill-line arg))
3548 (kill-line arg))
c567ac01 3549 ; Provide some feedback:
96b83743
EZ
3550 (sit-for 0)
3551 (if allout-numbered-bullet
3552 (save-excursion ; Renumber subsequent topics if needed:
d82979ea
EZ
3553 (if (not (looking-at allout-regexp))
3554 (allout-next-heading))
96b83743 3555 (allout-renumber-to-depth depth))))))
fd5359c6
MR
3556;;;_ > allout-kill-topic ()
3557(defun allout-kill-topic ()
c567ac01
RS
3558 "Kill topic together with subtopics.
3559
96b83743
EZ
3560Trailing whitespace is killed with a topic if that whitespace:
3561
3562 - would separate the topic from a subsequent sibling
3563 - would separate the topic from the end of buffer
3564 - would not be added to whitespace already separating the topic from the
3565 previous one.
3566
3567Completely collapsed topics are marked as such, for re-collapse
3568when yank with allout-yank into an outline as a heading."
1977b8f6
RS
3569
3570 ;; Some finagling is done to make complex topic kills appear faster
3571 ;; than they actually are. A redisplay is performed immediately
96b83743 3572 ;; after the region is deleted, though the renumbering process
1977b8f6 3573 ;; has yet to be performed. This means that there may appear to be
96b83743 3574 ;; a lag *after* a kill has been performed.
1977b8f6
RS
3575
3576 (interactive)
96b83743
EZ
3577 (let* ((collapsed (allout-current-topic-collapsed-p))
3578 (beg (prog1 (allout-back-to-current-heading) (beginning-of-line)))
fd5359c6
MR
3579 (depth (allout-recent-depth)))
3580 (allout-end-of-current-subtree)
96b83743
EZ
3581 (if (and (/= (current-column) 0) (not (eobp)))
3582 (forward-char 1))
1977b8f6 3583 (if (not (eobp))
96b83743
EZ
3584 (if (and (looking-at "\n")
3585 (or (save-excursion
3586 (or (not (allout-next-heading))
3587 (= depth (allout-recent-depth))))
3588 (and (> (- beg (point-min)) 3)
3589 (string= (buffer-substring (- beg 2) beg) "\n\n"))))
c567ac01 3590 (forward-char 1)))
353e2ef2 3591
96b83743
EZ
3592 (if collapsed
3593 (put-text-property beg (1+ beg) 'allout-was-collapsed t)
3594 (remove-text-properties beg (1+ beg) '(allout-was-collapsed t)))
d82979ea 3595 (allout-unprotected (kill-region beg (point)))
1977b8f6
RS
3596 (sit-for 0)
3597 (save-excursion
fd5359c6
MR
3598 (allout-renumber-to-depth depth))))
3599;;;_ > allout-yank-processing ()
3600(defun allout-yank-processing (&optional arg)
c567ac01 3601
96b83743 3602 "Incidental allout-specific business to be done just after text yanks.
19b84ba3 3603
c567ac01 3604Does depth adjustment of yanked topics, when:
1977b8f6 3605
c567ac01
RS
36061 the stuff being yanked starts with a valid outline header prefix, and
36072 it is being yanked at the end of a line which consists of only a valid
1977b8f6
RS
3608 topic prefix.
3609
a0776d6b 3610Also, adjusts numbering of subsequent siblings when appropriate.
1977b8f6 3611
c567ac01
RS
3612Depth adjustment alters the depth of all the topics being yanked
3613the amount it takes to make the first topic have the depth of the
3614header into which it's being yanked.
1977b8f6 3615
c567ac01
RS
3616The point is left in front of yanked, adjusted topics, rather than
3617at the end (and vice-versa with the mark). Non-adjusted yanks,
d82979ea 3618however, are left exactly like normal, non-allout-specific yanks."
c567ac01
RS
3619
3620 (interactive "*P")
3621 ; Get to beginning, leaving
3622 ; region around subject:
96b83743 3623 (if (< (allout-mark-marker t) (point))
c567ac01
RS
3624 (exchange-point-and-mark))
3625 (let* ((subj-beg (point))
96b83743
EZ
3626 (into-bol (bolp))
3627 (subj-end (allout-mark-marker t))
3628 (was-collapsed (get-text-property subj-beg 'allout-was-collapsed))
9179616f 3629 ;; 'resituate' if yanking an entire topic into topic header:
fd5359c6
MR
3630 (resituate (and (allout-e-o-prefix-p)
3631 (looking-at (concat "\\(" allout-regexp "\\)"))
3632 (allout-prefix-data (match-beginning 1)
c567ac01 3633 (match-end 1))))
353e2ef2 3634 ;; `rectify-numbering' if resituating (where several topics may
c567ac01
RS
3635 ;; be resituating) or yanking a topic into a topic slot (bol):
3636 (rectify-numbering (or resituate
96b83743 3637 (and into-bol (looking-at allout-regexp)))))
c567ac01
RS
3638 (if resituate
3639 ; The yanked stuff is a topic:
3640 (let* ((prefix-len (- (match-end 1) subj-beg))
fd5359c6
MR
3641 (subj-depth (allout-recent-depth))
3642 (prefix-bullet (allout-recent-bullet))
c567ac01
RS
3643 (adjust-to-depth
3644 ;; Nil if adjustment unnecessary, otherwise depth to which
3645 ;; adjustment should be made:
3646 (save-excursion
3647 (and (goto-char subj-end)
3648 (eolp)
3649 (goto-char subj-beg)
fd5359c6 3650 (and (looking-at allout-regexp)
c567ac01
RS
3651 (progn
3652 (beginning-of-line)
3653 (not (= (point) subj-beg)))
fd5359c6
MR
3654 (looking-at allout-regexp)
3655 (allout-prefix-data (match-beginning 0)
c567ac01 3656 (match-end 0)))
fd5359c6 3657 (allout-recent-depth))))
c567ac01 3658 (more t))
fd5359c6 3659 (setq rectify-numbering allout-numbered-bullet)
c567ac01
RS
3660 (if adjust-to-depth
3661 ; Do the adjustment:
3662 (progn
3663 (message "... yanking") (sit-for 0)
3664 (save-restriction
3665 (narrow-to-region subj-beg subj-end)
3666 ; Trim off excessive blank
3667 ; line at end, if any:
3668 (goto-char (point-max))
3669 (if (looking-at "^$")
fd5359c6 3670 (allout-unprotected (delete-char -1)))
c567ac01
RS
3671 ; Work backwards, with each
3672 ; shallowest level,
3673 ; successively excluding the
3674 ; last processed topic from
3675 ; the narrow region:
3676 (while more
fd5359c6 3677 (allout-back-to-current-heading)
c567ac01 3678 ; go as high as we can in each bunch:
fd5359c6 3679 (while (allout-ascend-to-depth (1- (allout-depth))))
c567ac01 3680 (save-excursion
fd5359c6 3681 (allout-rebullet-topic-grunt (- adjust-to-depth
c567ac01 3682 subj-depth))
fd5359c6 3683 (allout-depth))
c567ac01
RS
3684 (if (setq more (not (bobp)))
3685 (progn (widen)
3686 (forward-char -1)
3687 (narrow-to-region subj-beg (point))))))
3688 (message "")
3689 ;; Preserve new bullet if it's a distinctive one, otherwise
3690 ;; use old one:
3691 (if (string-match (regexp-quote prefix-bullet)
fd5359c6 3692 allout-distinctive-bullets-string)
c567ac01
RS
3693 ; Delete from bullet of old to
3694 ; before bullet of new:
3695 (progn
3696 (beginning-of-line)
3697 (delete-region (point) subj-beg)
96b83743 3698 (set-marker (allout-mark-marker t) subj-end)
c567ac01 3699 (goto-char subj-beg)
fd5359c6 3700 (allout-end-of-prefix))
c567ac01
RS
3701 ; Delete base subj prefix,
3702 ; leaving old one:
3703 (delete-region (point) (+ (point)
3704 prefix-len
3705 (- adjust-to-depth subj-depth)))
3706 ; and delete residual subj
3707 ; prefix digits and space:
3708 (while (looking-at "[0-9]") (delete-char 1))
3709 (if (looking-at " ") (delete-char 1))))
3710 (exchange-point-and-mark))))
3711 (if rectify-numbering
353e2ef2 3712 (progn
c567ac01
RS
3713 (save-excursion
3714 ; Give some preliminary feedback:
3715 (message "... reconciling numbers") (sit-for 0)
3716 ; ... and renumber, in case necessary:
3717 (goto-char subj-beg)
fd5359c6
MR
3718 (if (allout-goto-prefix)
3719 (allout-rebullet-heading nil ;;; solicit
3720 (allout-depth) ;;; depth
c567ac01
RS
3721 nil ;;; number-control
3722 nil ;;; index
3723 t))
3724 (message ""))))
96b83743
EZ
3725 (when (and (or into-bol resituate) was-collapsed)
3726 (remove-text-properties subj-beg (1+ subj-beg) '(allout-was-collapsed))
3727 (allout-hide-current-subtree))
c567ac01
RS
3728 (if (not resituate)
3729 (exchange-point-and-mark))))
fd5359c6
MR
3730;;;_ > allout-yank (&optional arg)
3731(defun allout-yank (&optional arg)
aad94676 3732 "`allout-mode' yank, with depth and numbering adjustment of yanked topics.
19b84ba3 3733
a0776d6b 3734Non-topic yanks work no differently than normal yanks.
c567ac01
RS
3735
3736If a topic is being yanked into a bare topic prefix, the depth of the
3737yanked topic is adjusted to the depth of the topic prefix.
3738
2265e017 3739 1 we're yanking in an `allout-mode' buffer
c567ac01
RS
3740 2 the stuff being yanked starts with a valid outline header prefix, and
3741 3 it is being yanked at the end of a line which consists of only a valid
3742 topic prefix.
3743
3744If these conditions hold then the depth of the yanked topics are all
3745adjusted the amount it takes to make the first one at the depth of the
3746header into which it's being yanked.
3747
3748The point is left in front of yanked, adjusted topics, rather than
3749at the end (and vice-versa with the mark). Non-adjusted yanks,
3750however, (ones that don't qualify for adjustment) are handled
3751exactly like normal yanks.
3752
a0776d6b 3753Numbering of yanked topics, and the successive siblings at the depth
c567ac01
RS
3754into which they're being yanked, is adjusted.
3755
539d7736
JB
3756`allout-yank-pop' works with `allout-yank' just like normal `yank-pop'
3757works with normal `yank' in non-outline buffers."
1977b8f6
RS
3758
3759 (interactive "*P")
3760 (setq this-command 'yank)
c567ac01 3761 (yank arg)
fd5359c6 3762 (if (allout-mode-p)
96b83743
EZ
3763 (allout-yank-processing))
3764)
fd5359c6
MR
3765;;;_ > allout-yank-pop (&optional arg)
3766(defun allout-yank-pop (&optional arg)
2265e017 3767 "Yank-pop like `allout-yank' when popping to bare outline prefixes.
19b84ba3
RS
3768
3769Adapts level of popped topics to level of fresh prefix.
c567ac01
RS
3770
3771Note - prefix changes to distinctive bullets will stick, if followed
3772by pops to non-distinctive yanks. Bug..."
1977b8f6
RS
3773
3774 (interactive "*p")
1977b8f6 3775 (setq this-command 'yank)
c567ac01 3776 (yank-pop arg)
fd5359c6
MR
3777 (if (allout-mode-p)
3778 (allout-yank-processing)))
1977b8f6 3779
c567ac01
RS
3780;;;_ - Specialty bullet functions
3781;;;_ : File Cross references
fd5359c6
MR
3782;;;_ > allout-resolve-xref ()
3783(defun allout-resolve-xref ()
19b84ba3
RS
3784 "Pop to file associated with current heading, if it has an xref bullet.
3785
fd5359c6 3786\(Works according to setting of `allout-file-xref-bullet')."
1977b8f6 3787 (interactive)
fd5359c6 3788 (if (not allout-file-xref-bullet)
1977b8f6 3789 (error
635ca796 3790 "Outline cross references disabled - no `allout-file-xref-bullet'")
fd5359c6 3791 (if (not (string= (allout-current-bullet) allout-file-xref-bullet))
635ca796 3792 (error "Current heading lacks cross-reference bullet `%s'"
fd5359c6 3793 allout-file-xref-bullet)
1977b8f6
RS
3794 (let (file-name)
3795 (save-excursion
fd5359c6 3796 (let* ((text-start allout-recent-prefix-end)
fa29cfef 3797 (heading-end (progn (end-of-line) (point))))
1977b8f6
RS
3798 (goto-char text-start)
3799 (setq file-name
3800 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t)
3801 (buffer-substring (match-beginning 1) (match-end 1))))))
69027dea 3802 (setq file-name (expand-file-name file-name))
1977b8f6
RS
3803 (if (or (file-exists-p file-name)
3804 (if (file-writable-p file-name)
3805 (y-or-n-p (format "%s not there, create one? "
3806 file-name))
3807 (error "%s not found and can't be created" file-name)))
3808 (condition-case failure
3809 (find-file-other-window file-name)
9179616f 3810 ('error failure))
1977b8f6
RS
3811 (error "%s not found" file-name))
3812 )
3813 )
3814 )
3815 )
19b84ba3 3816
9179616f 3817;;;_ #6 Exposure Control
c567ac01
RS
3818
3819;;;_ - Fundamental
d82979ea
EZ
3820;;;_ > allout-flag-region (from to flag)
3821(defun allout-flag-region (from to flag)
96b83743
EZ
3822 "Conceal text from FROM to TO if FLAG is non-nil, else reveal it.
3823
3824Text is shown if flag is nil and hidden otherwise."
3825 ;; We use outline invisibility spec.
3826 (remove-overlays from to 'category 'allout-overlay-category)
3827 (when flag
3828 (let ((o (make-overlay from to)))
3829 (overlay-put o 'category 'allout-overlay-category)
3830 (when (featurep 'xemacs)
3831 (let ((props (symbol-plist 'allout-overlay-category)))
3832 (while props
3833 (overlay-put o (pop props) (pop props)))))))
3834 (run-hooks 'allout-view-change-hook))
fd5359c6
MR
3835;;;_ > allout-flag-current-subtree (flag)
3836(defun allout-flag-current-subtree (flag)
96b83743 3837 "Conceal currently-visible topic's subtree if FLAG non-nil, else reveal it."
19b84ba3 3838
c567ac01 3839 (save-excursion
fd5359c6 3840 (allout-back-to-current-heading)
96b83743
EZ
3841 (end-of-line)
3842 (allout-flag-region (point)
3843 ;; Exposing must not leave trailing blanks hidden,
3844 ;; but can leave them exposed when hiding, so we
3845 ;; can use flag's inverse as the
3846 ;; include-trailing-blank cue:
3847 (allout-end-of-current-subtree (not flag))
3848 flag)))
c567ac01 3849
c567ac01 3850;;;_ - Topic-specific
96b83743
EZ
3851;;;_ > allout-show-entry (&optional inclusive)
3852(defun allout-show-entry (&optional inclusive)
fd5359c6 3853 "Like `allout-show-current-entry', reveals entries nested in hidden topics.
c567ac01
RS
3854
3855This is a way to give restricted peek at a concealed locality without the
3856expense of exposing its context, but can leave the outline with aberrant
96b83743
EZ
3857exposure. `allout-show-offshoot' should be used after the peek to rectify
3858the exposure."
c567ac01
RS
3859
3860 (interactive)
3861 (save-excursion
96b83743 3862 (let (beg end)
fd5359c6 3863 (allout-goto-prefix)
96b83743
EZ
3864 (setq beg (if (allout-hidden-p) (1- (point)) (point)))
3865 (setq end (allout-pre-next-prefix))
3866 (allout-flag-region beg end nil)
9179616f 3867 (list beg end))))
fd5359c6
MR
3868;;;_ > allout-show-children (&optional level strict)
3869(defun allout-show-children (&optional level strict)
c567ac01
RS
3870
3871 "If point is visible, show all direct subheadings of this heading.
19b84ba3 3872
2265e017 3873Otherwise, do `allout-show-to-offshoot', and then show subheadings.
c567ac01
RS
3874
3875Optional LEVEL specifies how many levels below the current level
3876should be shown, or all levels if t. Default is 1.
3877
3878Optional STRICT means don't resort to -show-to-offshoot, no matter
3879what. This is basically so -show-to-offshoot, which is called by
3880this function, can employ the pure offspring-revealing capabilities of
19b84ba3
RS
3881it.
3882
3883Returns point at end of subtree that was opened, if any. (May get a
3884point of non-opened subtree?)"
c567ac01
RS
3885
3886 (interactive "p")
96b83743 3887 (let ((start-point (point)))
19b84ba3 3888 (if (and (not strict)
96b83743 3889 (allout-hidden-p))
c567ac01 3890
96b83743
EZ
3891 (progn (allout-show-to-offshoot) ; Point's concealed, open to
3892 ; expose it.
3893 ;; Then recurse, but with "strict" set so we don't
3894 ;; infinite regress:
3895 (allout-show-children level t))
c567ac01 3896
19b84ba3 3897 (save-excursion
96b83743
EZ
3898 (allout-beginning-of-current-line)
3899 (save-restriction
3900 (let* ((chart (allout-chart-subtree (or level 1)))
3901 (to-reveal (allout-chart-to-reveal chart (or level 1))))
3902 (goto-char start-point)
3903 (when (and strict (allout-hidden-p))
3904 ;; Concealed root would already have been taken care of,
3905 ;; unless strict was set.
3906 (allout-flag-region (point) (allout-snug-back) nil)
3907 (when allout-show-bodies
3908 (goto-char (car to-reveal))
3909 (allout-show-current-entry)))
3910 (while to-reveal
3911 (goto-char (car to-reveal))
3912 (allout-flag-region (save-excursion (allout-snug-back) (point))
3913 (progn (search-forward "\n" nil t)
3914 (1- (point)))
3915 nil)
3916 (when allout-show-bodies
3917 (goto-char (car to-reveal))
3918 (allout-show-current-entry))
3919 (setq to-reveal (cdr to-reveal)))))))
3920 ;; Compensate for `save-excursion's maintenance of point
3921 ;; within invisible text:
3922 (goto-char start-point)))
fd5359c6
MR
3923;;;_ > allout-show-to-offshoot ()
3924(defun allout-show-to-offshoot ()
2265e017 3925 "Like `allout-show-entry', but reveals all concealed ancestors, as well.
c567ac01 3926
96b83743 3927Useful for coherently exposing to a random point in a hidden region."
c567ac01
RS
3928 (interactive)
3929 (save-excursion
3930 (let ((orig-pt (point))
fd5359c6 3931 (orig-pref (allout-goto-prefix))
c567ac01
RS
3932 (last-at (point))
3933 bag-it)
96b83743
EZ
3934 (while (or bag-it (allout-hidden-p))
3935 (while (allout-hidden-p)
3936 ;; XXX We would use `(move-beginning-of-line 1)', but it gets
3937 ;; stuck on hidden newlines at column 80, as of GNU Emacs 22.0.50.
3938 (beginning-of-line)
3939 (if (allout-hidden-p) (forward-char -1)))
c567ac01
RS
3940 (if (= last-at (setq last-at (point)))
3941 ;; Oops, we're not making any progress! Show the current
3942 ;; topic completely, and bag this try.
3943 (progn (beginning-of-line)
fd5359c6 3944 (allout-show-current-subtree)
c567ac01
RS
3945 (goto-char orig-pt)
3946 (setq bag-it t)
3947 (beep)
3948 (message "%s: %s"
fd5359c6 3949 "allout-show-to-offshoot: "
c567ac01 3950 "Aberrant nesting encountered.")))
fd5359c6 3951 (allout-show-children)
c567ac01 3952 (goto-char orig-pref))
19b84ba3 3953 (goto-char orig-pt)))
fd5359c6
MR
3954 (if (allout-hidden-p)
3955 (allout-show-entry)))
3956;;;_ > allout-hide-current-entry ()
3957(defun allout-hide-current-entry ()
c567ac01
RS
3958 "Hide the body directly following this heading."
3959 (interactive)
fd5359c6 3960 (allout-back-to-current-heading)
c567ac01 3961 (save-excursion
96b83743
EZ
3962 (end-of-line)
3963 (allout-flag-region (point)
d82979ea 3964 (progn (allout-end-of-entry) (point))
96b83743 3965 t)))
fd5359c6
MR
3966;;;_ > allout-show-current-entry (&optional arg)
3967(defun allout-show-current-entry (&optional arg)
c567ac01 3968
96b83743 3969 "Show body following current heading, or hide entry with universal argument."
c567ac01
RS
3970
3971 (interactive "P")
3972 (if arg
fd5359c6 3973 (allout-hide-current-entry)
96b83743 3974 (save-excursion (allout-show-to-offshoot))
c567ac01 3975 (save-excursion
fd5359c6 3976 (allout-flag-region (point)
96b83743
EZ
3977 (progn (allout-end-of-entry t) (point))
3978 nil)
d82979ea 3979 )))
fd5359c6
MR
3980;;;_ > allout-show-current-subtree (&optional arg)
3981(defun allout-show-current-subtree (&optional arg)
19b84ba3 3982 "Show everything within the current topic. With a repeat-count,
353e2ef2 3983expose this topic and its siblings."
19b84ba3
RS
3984 (interactive "P")
3985 (save-excursion
fd5359c6 3986 (if (<= (allout-current-depth) 0)
19b84ba3 3987 ;; Outside any topics - try to get to the first:
fd5359c6 3988 (if (not (allout-next-heading))
6a05d05f 3989 (error "No topics")
19b84ba3
RS
3990 ;; got to first, outermost topic - set to expose it and siblings:
3991 (message "Above outermost topic - exposing all.")
96b83743
EZ
3992 (allout-flag-region (point-min)(point-max) nil))
3993 (allout-beginning-of-current-line)
19b84ba3 3994 (if (not arg)
96b83743 3995 (allout-flag-current-subtree nil)
fd5359c6
MR
3996 (allout-beginning-of-level)
3997 (allout-expose-topic '(* :))))))
96b83743
EZ
3998;;;_ > allout-current-topic-collapsed-p (&optional include-single-liners)
3999(defun allout-current-topic-collapsed-p (&optional include-single-liners)
4000 "True if the currently visible containing topic is already collapsed.
4001
4002If optional INCLUDE-SINGLE-LINERS is true, then include single-line
4003topics \(which intrinsically can be considered both collapsed and
4004not\), as collapsed. Otherwise they are considered uncollapsed."
4005 (save-excursion
4034b0e2 4006 (and
96b83743
EZ
4007 (= (progn (allout-back-to-current-heading)
4008 (move-end-of-line 1)
4009 (point))
4010 (allout-end-of-current-subtree))
4011 (or include-single-liners
4012 (progn (backward-char 1) (allout-hidden-p))))))
fd5359c6
MR
4013;;;_ > allout-hide-current-subtree (&optional just-close)
4014(defun allout-hide-current-subtree (&optional just-close)
19b84ba3 4015 "Close the current topic, or containing topic if this one is already closed.
c567ac01 4016
19b84ba3 4017If this topic is closed and it's a top level topic, close this topic
353e2ef2 4018and its siblings.
19b84ba3 4019
96b83743 4020If optional arg JUST-CLOSE is non-nil, do not close the parent or
19b84ba3 4021siblings, even if the target topic is already closed."
c567ac01
RS
4022
4023 (interactive)
96b83743
EZ
4024 (let* ((from (point))
4025 (sibs-msg "Top-level topic already closed - closing siblings...")
4026 (current-exposed (not (allout-current-topic-collapsed-p t))))
4027 (cond (current-exposed (allout-flag-current-subtree t))
4028 (just-close nil)
4029 ((allout-up-current-level 1 t) (allout-hide-current-subtree))
4030 (t (goto-char 0)
4031 (message sibs-msg)
4032 (allout-expose-topic '(0 :))
4033 (message (concat sibs-msg " Done."))))
4034 (goto-char from)))
fd5359c6
MR
4035;;;_ > allout-show-current-branches ()
4036(defun allout-show-current-branches ()
c567ac01
RS
4037 "Show all subheadings of this heading, but not their bodies."
4038 (interactive)
4039 (beginning-of-line)
fd5359c6
MR
4040 (allout-show-children t))
4041;;;_ > allout-hide-current-leaves ()
4042(defun allout-hide-current-leaves ()
353e2ef2 4043 "Hide the bodies of the current topic and all its offspring."
c567ac01 4044 (interactive)
fd5359c6
MR
4045 (allout-back-to-current-heading)
4046 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
c567ac01
RS
4047 (point))))
4048
4049;;;_ - Region and beyond
fd5359c6
MR
4050;;;_ > allout-show-all ()
4051(defun allout-show-all ()
c567ac01
RS
4052 "Show all of the text in the buffer."
4053 (interactive)
19b84ba3 4054 (message "Exposing entire buffer...")
96b83743 4055 (allout-flag-region (point-min) (point-max) nil)
19b84ba3 4056 (message "Exposing entire buffer... Done."))
fd5359c6
MR
4057;;;_ > allout-hide-bodies ()
4058(defun allout-hide-bodies ()
c567ac01
RS
4059 "Hide all of buffer except headings."
4060 (interactive)
fd5359c6
MR
4061 (allout-hide-region-body (point-min) (point-max)))
4062;;;_ > allout-hide-region-body (start end)
4063(defun allout-hide-region-body (start end)
c567ac01
RS
4064 "Hide all body lines in the region, but not headings."
4065 (save-excursion
4066 (save-restriction
4067 (narrow-to-region start end)
4068 (goto-char (point-min))
4069 (while (not (eobp))
96b83743
EZ
4070 (end-of-line)
4071 (allout-flag-region (point) (allout-end-of-entry) t)
c567ac01
RS
4072 (if (not (eobp))
4073 (forward-char
96b83743 4074 (if (looking-at "\n\n")
c567ac01 4075 2 1)))))))
c567ac01 4076
fd5359c6
MR
4077;;;_ > allout-expose-topic (spec)
4078(defun allout-expose-topic (spec)
19b84ba3 4079 "Apply exposure specs to successive outline topic items.
c567ac01 4080
fd5359c6
MR
4081Use the more convenient frontend, `allout-new-exposure', if you don't
4082need evaluation of the arguments, or even better, the `allout-layout'
19b84ba3
RS
4083variable-keyed mode-activation/auto-exposure feature of allout outline
4084mode. See the respective documentation strings for more details.
c567ac01
RS
4085
4086Cursor is left at start position.
4087
19b84ba3
RS
4088SPEC is either a number or a list.
4089
4090Successive specs on a list are applied to successive sibling topics.
c567ac01
RS
4091
4092A simple spec \(either a number, one of a few symbols, or the null
19b84ba3
RS
4093list) dictates the exposure for the corresponding topic.
4094
4095Non-null lists recursively designate exposure specs for respective
4096subtopics of the current topic.
c567ac01 4097
353e2ef2 4098The `:' repeat spec is used to specify exposure for any number of
19b84ba3 4099successive siblings, up to the trailing ones for which there are
353e2ef2 4100explicit specs following the `:'.
c567ac01
RS
4101
4102Simple (numeric and null-list) specs are interpreted as follows:
4103
19b84ba3
RS
4104 Numbers indicate the relative depth to open the corresponding topic.
4105 - negative numbers force the topic to be closed before opening to the
4106 absolute value of the number, so all siblings are open only to
4107 that level.
4108 - positive numbers open to the relative depth indicated by the
4109 number, but do not force already opened subtopics to be closed.
4110 - 0 means to close topic - hide all offspring.
353e2ef2 4111 : - `repeat'
c567ac01 4112 apply prior element to all siblings at current level, *up to*
353e2ef2 4113 those siblings that would be covered by specs following the `:'
c567ac01
RS
4114 on the list. Ie, apply to all topics at level but the last
4115 ones. \(Only first of multiple colons at same level is
4116 respected - subsequent ones are discarded.)
19b84ba3
RS
4117 * - completely opens the topic, including bodies.
4118 + - shows all the sub headers, but not the bodies
4119 - - exposes the body of the corresponding topic.
c567ac01
RS
4120
4121Examples:
fd5359c6 4122\(allout-expose-topic '(-1 : 0))
c567ac01
RS
4123 Close this and all following topics at current level, exposing
4124 only their immediate children, but close down the last topic
4125 at this current level completely.
fd5359c6 4126\(allout-expose-topic '(-1 () : 1 0))
c567ac01
RS
4127 Close current topic so only the immediate subtopics are shown;
4128 show the children in the second to last topic, and completely
4129 close the last one.
fd5359c6 4130\(allout-expose-topic '(-2 : -1 *))
c567ac01
RS
4131 Expose children and grandchildren of all topics at current
4132 level except the last two; expose children of the second to
4133 last and completely open the last one."
4134
4135 (interactive "xExposure spec: ")
19b84ba3
RS
4136 (if (not (listp spec))
4137 nil
fd5359c6 4138 (let ((depth (allout-depth))
19b84ba3
RS
4139 (max-pos 0)
4140 prev-elem curr-elem
96b83743 4141 stay)
19b84ba3
RS
4142 (while spec
4143 (setq prev-elem curr-elem
4144 curr-elem (car spec)
4145 spec (cdr spec))
4146 (cond ; Do current element:
4147 ((null curr-elem) nil)
4148 ((symbolp curr-elem)
fd5359c6
MR
4149 (cond ((eq curr-elem '*) (allout-show-current-subtree)
4150 (if (> allout-recent-end-of-subtree max-pos)
4151 (setq max-pos allout-recent-end-of-subtree)))
4152 ((eq curr-elem '+) (allout-show-current-branches)
4153 (if (> allout-recent-end-of-subtree max-pos)
4154 (setq max-pos allout-recent-end-of-subtree)))
4155 ((eq curr-elem '-) (allout-show-current-entry))
19b84ba3
RS
4156 ((eq curr-elem ':)
4157 (setq stay t)
353e2ef2 4158 ;; Expand the `repeat' spec to an explicit version,
19b84ba3
RS
4159 ;; w.r.t. remaining siblings:
4160 (let ((residue ; = # of sibs not covered by remaining spec
4161 ;; Dang - could be nice to make use of the chart, sigh:
fd5359c6 4162 (- (length (allout-chart-siblings))
19b84ba3
RS
4163 (length spec))))
4164 (if (< 0 residue)
4165 ;; Some residue - cover it with prev-elem:
4166 (setq spec (append (make-list residue prev-elem)
4167 spec)))))))
4168 ((numberp curr-elem)
96b83743 4169 (if (and (>= 0 curr-elem) (not (allout-hidden-p)))
fd5359c6 4170 (save-excursion (allout-hide-current-subtree t)
19b84ba3
RS
4171 (if (> 0 curr-elem)
4172 nil
fd5359c6 4173 (if (> allout-recent-end-of-subtree max-pos)
19b84ba3 4174 (setq max-pos
fd5359c6 4175 allout-recent-end-of-subtree)))))
19b84ba3 4176 (if (> (abs curr-elem) 0)
fd5359c6
MR
4177 (progn (allout-show-children (abs curr-elem))
4178 (if (> allout-recent-end-of-subtree max-pos)
4179 (setq max-pos allout-recent-end-of-subtree)))))
19b84ba3 4180 ((listp curr-elem)
fd5359c6
MR
4181 (if (allout-descend-to-depth (1+ depth))
4182 (let ((got (allout-expose-topic curr-elem)))
19b84ba3
RS
4183 (if (and got (> got max-pos)) (setq max-pos got))))))
4184 (cond (stay (setq stay nil))
4185 ((listp (car spec)) nil)
4186 ((> max-pos (point))
4187 ;; Capitalize on max-pos state to get us nearer next sibling:
4188 (progn (goto-char (min (point-max) max-pos))
fd5359c6
MR
4189 (allout-next-heading)))
4190 ((allout-next-sibling depth))))
19b84ba3 4191 max-pos)))
fd5359c6
MR
4192;;;_ > allout-old-expose-topic (spec &rest followers)
4193(defun allout-old-expose-topic (spec &rest followers)
d82979ea
EZ
4194
4195 "Deprecated. Use `allout-expose-topic' \(with different schema
4196format) instead.
4197
4198Dictate wholesale exposure scheme for current topic, according to SPEC.
c567ac01
RS
4199
4200SPEC is either a number or a list. Optional successive args
4201dictate exposure for subsequent siblings of current topic.
4202
4203A simple spec (either a number, a special symbol, or the null list)
4204dictates the overall exposure for a topic. Non null lists are
4205composite specs whose first element dictates the overall exposure for
4206a topic, with the subsequent elements in the list interpreted as specs
4207that dictate the exposure for the successive offspring of the topic.
4208
4209Simple (numeric and null-list) specs are interpreted as follows:
4210
4211 - Numbers indicate the relative depth to open the corresponding topic:
4212 - negative numbers force the topic to be close before opening to the
4213 absolute value of the number.
4214 - positive numbers just open to the relative depth indicated by the number.
4215 - 0 just closes
353e2ef2
KH
4216 - `*' completely opens the topic, including bodies.
4217 - `+' shows all the sub headers, but not the bodies
4218 - `-' exposes the body and immediate offspring of the corresponding topic.
c567ac01
RS
4219
4220If the spec is a list, the first element must be a number, which
4221dictates the exposure depth of the topic as a whole. Subsequent
4222elements of the list are nested SPECs, dictating the specific exposure
4223for the corresponding offspring of the topic.
4224
e126900f 4225Optional FOLLOWERS arguments dictate exposure for succeeding siblings."
c567ac01
RS
4226
4227 (interactive "xExposure spec: ")
fd5359c6 4228 (let ((depth (allout-current-depth))
c567ac01
RS
4229 max-pos)
4230 (cond ((null spec) nil)
4231 ((symbolp spec)
fd5359c6
MR
4232 (if (eq spec '*) (allout-show-current-subtree))
4233 (if (eq spec '+) (allout-show-current-branches))
4234 (if (eq spec '-) (allout-show-current-entry)))
c567ac01
RS
4235 ((numberp spec)
4236 (if (>= 0 spec)
fd5359c6 4237 (save-excursion (allout-hide-current-subtree t)
c567ac01
RS
4238 (end-of-line)
4239 (if (or (not max-pos)
4240 (> (point) max-pos))
4241 (setq max-pos (point)))
4242 (if (> 0 spec)
4243 (setq spec (* -1 spec)))))
4244 (if (> spec 0)
fd5359c6 4245 (allout-show-children spec)))
c567ac01 4246 ((listp spec)
fd5359c6 4247 ;(let ((got (allout-old-expose-topic (car spec))))
c567ac01
RS
4248 ; (if (and got (or (not max-pos) (> got max-pos)))
4249 ; (setq max-pos got)))
fd5359c6 4250 (let ((new-depth (+ (allout-current-depth) 1))
c567ac01 4251 got)
fd5359c6 4252 (setq max-pos (allout-old-expose-topic (car spec)))
c567ac01
RS
4253 (setq spec (cdr spec))
4254 (if (and spec
fd5359c6
MR
4255 (allout-descend-to-depth new-depth)
4256 (not (allout-hidden-p)))
4257 (progn (setq got (apply 'allout-old-expose-topic spec))
c567ac01
RS
4258 (if (and got (or (not max-pos) (> got max-pos)))
4259 (setq max-pos got)))))))
4260 (while (and followers
4261 (progn (if (and max-pos (< (point) max-pos))
4262 (progn (goto-char max-pos)
4263 (setq max-pos nil)))
4264 (end-of-line)
fd5359c6
MR
4265 (allout-next-sibling depth)))
4266 (allout-old-expose-topic (car followers))
c567ac01
RS
4267 (setq followers (cdr followers)))
4268 max-pos))
fd5359c6
MR
4269;;;_ > allout-new-exposure '()
4270(defmacro allout-new-exposure (&rest spec)
4271 "Literal frontend for `allout-expose-topic', doesn't evaluate arguments.
2265e017
MR
4272Some arguments that would need to be quoted in `allout-expose-topic'
4273need not be quoted in `allout-new-exposure'.
c567ac01
RS
4274
4275Cursor is left at start position.
4276
d82979ea
EZ
4277Use this instead of obsolete `allout-exposure'.
4278
c567ac01 4279Examples:
bff05d9e 4280\(allout-new-exposure (-1 () () () 1) 0)
c567ac01
RS
4281 Close current topic at current level so only the immediate
4282 subtopics are shown, except also show the children of the
4283 third subtopic; and close the next topic at the current level.
bff05d9e 4284\(allout-new-exposure : -1 0)
c567ac01
RS
4285 Close all topics at current level to expose only their
4286 immediate children, except for the last topic at the current
353e2ef2 4287 level, in which even its immediate children are hidden.
bff05d9e 4288\(allout-new-exposure -2 : -1 *)
c567ac01
RS
4289 Expose children and grandchildren of first topic at current
4290 level, and expose children of subsequent topics at current
4291 level *except* for the last, which should be opened completely."
4292 (list 'save-excursion
fd5359c6
MR
4293 '(if (not (or (allout-goto-prefix)
4294 (allout-next-heading)))
4295 (error "allout-new-exposure: Can't find any outline topics"))
4296 (list 'allout-expose-topic (list 'quote spec))))
c567ac01 4297
9179616f 4298;;;_ #7 Systematic outline presentation - copying, printing, flattening
19b84ba3 4299
9179616f
DL
4300;;;_ - Mapping and processing of topics
4301;;;_ ( See also Subtree Charting, in Navigation code.)
fd5359c6
MR
4302;;;_ > allout-stringify-flat-index (flat-index)
4303(defun allout-stringify-flat-index (flat-index &optional context)
9179616f
DL
4304 "Convert list representing section/subsection/... to document string.
4305
4306Optional arg CONTEXT indicates interior levels to include."
4307 (let ((delim ".")
71296446 4308 result
9179616f
DL
4309 numstr
4310 (context-depth (or (and context 2) 1)))
4311 ;; Take care of the explicit context:
4312 (while (> context-depth 0)
4313 (setq numstr (int-to-string (car flat-index))
4314 flat-index (cdr flat-index)
4315 result (if flat-index
4316 (cons delim (cons numstr result))
4317 (cons numstr result))
4318 context-depth (if flat-index (1- context-depth) 0)))
4319 (setq delim " ")
4320 ;; Take care of the indentation:
4321 (if flat-index
4322 (progn
4323 (while flat-index
4324 (setq result
4325 (cons delim
4326 (cons (make-string
4327 (1+ (truncate (if (zerop (car flat-index))
4328 1
4329 (log10 (car flat-index)))))
4330 ? )
4331 result)))
4332 (setq flat-index (cdr flat-index)))
4333 ;; Dispose of single extra delim:
4334 (setq result (cdr result))))
4335 (apply 'concat result)))
fd5359c6
MR
4336;;;_ > allout-stringify-flat-index-plain (flat-index)
4337(defun allout-stringify-flat-index-plain (flat-index)
9179616f
DL
4338 "Convert list representing section/subsection/... to document string."
4339 (let ((delim ".")
4340 result)
4341 (while flat-index
4342 (setq result (cons (int-to-string (car flat-index))
4343 (if result
4344 (cons delim result))))
4345 (setq flat-index (cdr flat-index)))
4346 (apply 'concat result)))
fd5359c6
MR
4347;;;_ > allout-stringify-flat-index-indented (flat-index)
4348(defun allout-stringify-flat-index-indented (flat-index)
9179616f
DL
4349 "Convert list representing section/subsection/... to document string."
4350 (let ((delim ".")
71296446 4351 result
9179616f
DL
4352 numstr)
4353 ;; Take care of the explicit context:
4354 (setq numstr (int-to-string (car flat-index))
4355 flat-index (cdr flat-index)
4356 result (if flat-index
4357 (cons delim (cons numstr result))
4358 (cons numstr result)))
4359 (setq delim " ")
4360 ;; Take care of the indentation:
4361 (if flat-index
4362 (progn
4363 (while flat-index
4364 (setq result
4365 (cons delim
4366 (cons (make-string
4367 (1+ (truncate (if (zerop (car flat-index))
4368 1
4369 (log10 (car flat-index)))))
4370 ? )
4371 result)))
4372 (setq flat-index (cdr flat-index)))
4373 ;; Dispose of single extra delim:
4374 (setq result (cdr result))))
4375 (apply 'concat result)))
fd5359c6
MR
4376;;;_ > allout-listify-exposed (&optional start end format)
4377(defun allout-listify-exposed (&optional start end format)
19b84ba3 4378
9179616f 4379 "Produce a list representing exposed topics in current region.
c567ac01 4380
fd5359c6 4381This list can then be used by `allout-process-exposed' to manipulate
9179616f 4382the subject region.
353e2ef2 4383
9179616f 4384Optional START and END indicate bounds of region.
19b84ba3 4385
9179616f
DL
4386optional arg, FORMAT, designates an alternate presentation form for
4387the prefix:
c567ac01 4388
9179616f
DL
4389 list - Present prefix as numeric section.subsection..., starting with
4390 section indicated by the list, innermost nesting first.
4391 `indent' \(symbol) - Convert header prefixes to all white space,
4392 except for distinctive bullets.
c567ac01 4393
9179616f
DL
4394The elements of the list produced are lists that represents a topic
4395header and body. The elements of that list are:
c567ac01 4396
9179616f
DL
4397 - a number representing the depth of the topic,
4398 - a string representing the header-prefix, including trailing whitespace and
4399 bullet.
4400 - a string representing the bullet character,
4401 - and a series of strings, each containing one line of the exposed
4402 portion of the topic entry."
c567ac01 4403
9179616f
DL
4404 (interactive "r")
4405 (save-excursion
4406 (let*
4407 ;; state vars:
96b83743 4408 (strings prefix result depth new-depth out gone-out bullet beg
9179616f 4409 next done)
c567ac01 4410
9179616f
DL
4411 (goto-char start)
4412 (beginning-of-line)
4413 ;; Goto initial topic, and register preceeding stuff, if any:
fd5359c6 4414 (if (> (allout-goto-prefix) start)
9179616f
DL
4415 ;; First topic follows beginning point - register preliminary stuff:
4416 (setq result (list (list 0 "" nil
4417 (buffer-substring start (1- (point)))))))
4418 (while (and (not done)
4419 (not (eobp)) ; Loop until we've covered the region.
4420 (not (> (point) end)))
fd5359c6
MR
4421 (setq depth (allout-recent-depth) ; Current topics depth,
4422 bullet (allout-recent-bullet) ; ... bullet,
4423 prefix (allout-recent-prefix)
4424 beg (progn (allout-end-of-prefix t) (point))) ; and beginning.
9179616f 4425 (setq done ; The boundary for the current topic:
fd5359c6
MR
4426 (not (allout-next-visible-heading 1)))
4427 (setq new-depth (allout-recent-depth))
9179616f
DL
4428 (setq gone-out out
4429 out (< new-depth depth))
4430 (beginning-of-line)
4431 (setq next (point))
4432 (goto-char beg)
4433 (setq strings nil)
4434 (while (> next (point)) ; Get all the exposed text in
4435 (setq strings
4436 (cons (buffer-substring
4437 beg
4438 ;To hidden text or end of line:
4439 (progn
96b83743
EZ
4440 (end-of-line)
4441 (allout-back-to-visible-text)))
9179616f 4442 strings))
96b83743
EZ
4443 (when (< (point) next) ; Resume from after hid text, if any.
4444 (line-move 1))
9179616f
DL
4445 (setq beg (point)))
4446 ;; Accumulate list for this topic:
4447 (setq strings (nreverse strings))
4448 (setq result
4449 (cons
4450 (if format
4451 (let ((special (if (string-match
4452 (regexp-quote bullet)
fd5359c6 4453 allout-distinctive-bullets-string)
9179616f
DL
4454 bullet)))
4455 (cond ((listp format)
4456 (list depth
fd5359c6
MR
4457 (if allout-abbreviate-flattened-numbering
4458 (allout-stringify-flat-index format
9179616f 4459 gone-out)
fd5359c6 4460 (allout-stringify-flat-index-plain
9179616f
DL
4461 format))
4462 strings
4463 special))
4464 ((eq format 'indent)
4465 (if special
4466 (list depth
4467 (concat (make-string (1+ depth) ? )
4468 (substring prefix -1))
4469 strings)
4470 (list depth
4471 (make-string depth ? )
4472 strings)))
fd5359c6 4473 (t (error "allout-listify-exposed: %s %s"
9179616f
DL
4474 "invalid format" format))))
4475 (list depth prefix strings))
4476 result))
4477 ;; Reasses format, if any:
4478 (if (and format (listp format))
4479 (cond ((= new-depth depth)
4480 (setq format (cons (1+ (car format))
4481 (cdr format))))
4482 ((> new-depth depth) ; descending - assume by 1:
4483 (setq format (cons 1 format)))
4484 (t
4485 ; Pop the residue:
4486 (while (< new-depth depth)
4487 (setq format (cdr format))
4488 (setq depth (1- depth)))
4489 ; And increment the current one:
4490 (setq format
4491 (cons (1+ (or (car format)
4492 -1))
4493 (cdr format)))))))
4494 ;; Put the list with first at front, to last at back:
4495 (nreverse result))))
d82979ea
EZ
4496;;;_ > my-region-active-p ()
4497(defmacro my-region-active-p ()
4498 (if (fboundp 'region-active-p)
4499 '(region-active-p)
4500 'mark-active))
fd5359c6 4501;;;_ > allout-process-exposed (&optional func from to frombuf
9179616f 4502;;; tobuf format)
fd5359c6 4503(defun allout-process-exposed (&optional func from to frombuf tobuf
96b83743 4504 format start-num)
9179616f 4505 "Map function on exposed parts of current topic; results to another buffer.
353e2ef2 4506
d82979ea
EZ
4507All args are options; default values itemized below.
4508
4509Apply FUNCTION to exposed portions FROM position TO position in buffer
9179616f
DL
4510FROMBUF to buffer TOBUF. Sixth optional arg, FORMAT, designates an
4511alternate presentation form:
c567ac01 4512
9179616f
DL
4513 `flat' - Present prefix as numeric section.subsection..., starting with
4514 section indicated by the start-num, innermost nesting first.
4515 X`flat-indented' - Prefix is like `flat' for first topic at each
4516 X level, but subsequent topics have only leaf topic
4517 X number, padded with blanks to line up with first.
4518 `indent' \(symbol) - Convert header prefixes to all white space,
4519 except for distinctive bullets.
c567ac01 4520
9179616f 4521Defaults:
d82979ea 4522 FUNCTION: `allout-insert-listified'
9179616f
DL
4523 FROM: region start, if region active, else start of buffer
4524 TO: region end, if region active, else end of buffer
4525 FROMBUF: current buffer
4526 TOBUF: buffer name derived: \"*current-buffer-name exposed*\"
4527 FORMAT: nil"
4528
4529 ; Resolve arguments,
4530 ; defaulting if necessary:
fd5359c6 4531 (if (not func) (setq func 'allout-insert-listified))
9179616f
DL
4532 (if (not (and from to))
4533 (if (my-region-active-p)
4534 (setq from (region-beginning) to (region-end))
4535 (setq from (point-min) to (point-max))))
4536 (if frombuf
4537 (if (not (bufferp frombuf))
4538 ;; Specified but not a buffer - get it:
4539 (let ((got (get-buffer frombuf)))
4540 (if (not got)
fd5359c6 4541 (error (concat "allout-process-exposed: source buffer "
9179616f
DL
4542 frombuf
4543 " not found."))
4544 (setq frombuf got))))
4545 ;; not specified - default it:
4546 (setq frombuf (current-buffer)))
4547 (if tobuf
4548 (if (not (bufferp tobuf))
4549 (setq tobuf (get-buffer-create tobuf)))
4550 ;; not specified - default it:
4551 (setq tobuf (concat "*" (buffer-name frombuf) " exposed*")))
4552 (if (listp format)
4553 (nreverse format))
4554
4555 (let* ((listified
4556 (progn (set-buffer frombuf)
fd5359c6 4557 (allout-listify-exposed from to format))))
9179616f
DL
4558 (set-buffer tobuf)
4559 (mapcar func listified)
4560 (pop-to-buffer tobuf)))
4561
4562;;;_ - Copy exposed
fd5359c6
MR
4563;;;_ > allout-insert-listified (listified)
4564(defun allout-insert-listified (listified)
9179616f
DL
4565 "Insert contents of listified outline portion in current buffer.
4566
e126900f 4567LISTIFIED is a list representing each topic header and body:
9179616f
DL
4568
4569 \`(depth prefix text)'
4570
d82979ea 4571or \`(depth prefix text bullet-plus)'
9179616f
DL
4572
4573If `bullet-plus' is specified, it is inserted just after the entire prefix."
4574 (setq listified (cdr listified))
4575 (let ((prefix (prog1
4576 (car listified)
4577 (setq listified (cdr listified))))
4578 (text (prog1
4579 (car listified)
4580 (setq listified (cdr listified))))
4581 (bullet-plus (car listified)))
eac9cf5f
PJ
4582 (insert prefix)
4583 (if bullet-plus (insert (concat " " bullet-plus)))
9179616f 4584 (while text
eac9cf5f 4585 (insert (car text))
9179616f 4586 (if (setq text (cdr text))
0949617b 4587 (insert "\n")))
eac9cf5f 4588 (insert "\n")))
fd5359c6
MR
4589;;;_ > allout-copy-exposed-to-buffer (&optional arg tobuf format)
4590(defun allout-copy-exposed-to-buffer (&optional arg tobuf format)
9179616f
DL
4591 "Duplicate exposed portions of current outline to another buffer.
4592
4593Other buffer has current buffers name with \" exposed\" appended to it.
4594
4595With repeat count, copy the exposed parts of only the current topic.
4596
4597Optional second arg TOBUF is target buffer name.
4598
4599Optional third arg FORMAT, if non-nil, symbolically designates an
4600alternate presentation format for the outline:
4601
4602 `flat' - Convert topic header prefixes to numeric
4603 section.subsection... identifiers.
4604 `indent' - Convert header prefixes to all white space, except for
4605 distinctive bullets.
4606 `indent-flat' - The best of both - only the first of each level has
4607 the full path, the rest have only the section number
4608 of the leaf, preceded by the right amount of indentation."
c567ac01
RS
4609
4610 (interactive "P")
4611 (if (not tobuf)
4612 (setq tobuf (get-buffer-create (concat "*" (buffer-name) " exposed*"))))
4613 (let* ((start-pt (point))
fd5359c6
MR
4614 (beg (if arg (allout-back-to-current-heading) (point-min)))
4615 (end (if arg (allout-end-of-current-subtree) (point-max)))
9179616f
DL
4616 (buf (current-buffer))
4617 (start-list ()))
4618 (if (eq format 'flat)
4619 (setq format (if arg (save-excursion
4620 (goto-char beg)
fd5359c6 4621 (allout-topic-flat-index))
9179616f 4622 '(1))))
c567ac01 4623 (save-excursion (set-buffer tobuf)(erase-buffer))
fd5359c6 4624 (allout-process-exposed 'allout-insert-listified
c567ac01
RS
4625 beg
4626 end
4627 (current-buffer)
9179616f
DL
4628 tobuf
4629 format start-list)
c567ac01
RS
4630 (goto-char (point-min))
4631 (pop-to-buffer buf)
4632 (goto-char start-pt)))
fd5359c6
MR
4633;;;_ > allout-flatten-exposed-to-buffer (&optional arg tobuf)
4634(defun allout-flatten-exposed-to-buffer (&optional arg tobuf)
9179616f
DL
4635 "Present numeric outline of outline's exposed portions in another buffer.
4636
e126900f 4637The resulting outline is not compatible with outline mode - use
fd5359c6 4638`allout-copy-exposed-to-buffer' if you want that.
9179616f 4639
fd5359c6 4640Use `allout-indented-exposed-to-buffer' for indented presentation.
9179616f
DL
4641
4642With repeat count, copy the exposed portions of only current topic.
4643
e126900f 4644Other buffer has current buffer's name with \" exposed\" appended to
9179616f
DL
4645it, unless optional second arg TOBUF is specified, in which case it is
4646used verbatim."
4647 (interactive "P")
fd5359c6
MR
4648 (allout-copy-exposed-to-buffer arg tobuf 'flat))
4649;;;_ > allout-indented-exposed-to-buffer (&optional arg tobuf)
4650(defun allout-indented-exposed-to-buffer (&optional arg tobuf)
9179616f
DL
4651 "Present indented outline of outline's exposed portions in another buffer.
4652
e126900f 4653The resulting outline is not compatible with outline mode - use
fd5359c6 4654`allout-copy-exposed-to-buffer' if you want that.
9179616f 4655
fd5359c6 4656Use `allout-flatten-exposed-to-buffer' for numeric sectional presentation.
9179616f
DL
4657
4658With repeat count, copy the exposed portions of only current topic.
4659
e126900f 4660Other buffer has current buffer's name with \" exposed\" appended to
9179616f
DL
4661it, unless optional second arg TOBUF is specified, in which case it is
4662used verbatim."
4663 (interactive "P")
fd5359c6 4664 (allout-copy-exposed-to-buffer arg tobuf 'indent))
c567ac01
RS
4665
4666;;;_ - LaTeX formatting
e126900f
JB
4667;;;_ > allout-latex-verb-quote (string &optional flow)
4668(defun allout-latex-verb-quote (string &optional flow)
539d7736 4669 "Return copy of STRING for literal reproduction across LaTeX processing.
19b84ba3 4670Expresses the original characters \(including carriage returns) of the
539d7736 4671string across LaTeX processing."
9179616f
DL
4672 (mapconcat (function
4673 (lambda (char)
c567ac01
RS
4674 (cond ((memq char '(?\\ ?$ ?% ?# ?& ?{ ?} ?_ ?^ ?- ?*))
4675 (concat "\\char" (number-to-string char) "{}"))
4676 ((= char ?\n) "\\\\")
9179616f 4677 (t (char-to-string char)))))
e126900f 4678 string
c567ac01 4679 ""))
fd5359c6
MR
4680;;;_ > allout-latex-verbatim-quote-curr-line ()
4681(defun allout-latex-verbatim-quote-curr-line ()
539d7736 4682 "Express line for exact \(literal) representation across LaTeX processing.
19b84ba3
RS
4683
4684Adjust line contents so it is unaltered \(from the original line)
539d7736 4685across LaTeX processing, within the context of a `verbatim'
c567ac01
RS
4686environment. Leaves point at the end of the line."
4687 (beginning-of-line)
4688 (let ((beg (point))
4689 (end (progn (end-of-line)(point))))
4690 (goto-char beg)
4691 (while (re-search-forward "\\\\"
4692 ;;"\\\\\\|\\{\\|\\}\\|\\_\\|\\$\\|\\\"\\|\\&\\|\\^\\|\\-\\|\\*\\|#"
4693 end ; bounded by end-of-line
4694 1) ; no matches, move to end & return nil
4695 (goto-char (match-beginning 0))
eac9cf5f 4696 (insert "\\")
c567ac01
RS
4697 (setq end (1+ end))
4698 (goto-char (1+ (match-end 0))))))
e126900f
JB
4699;;;_ > allout-insert-latex-header (buffer)
4700(defun allout-insert-latex-header (buffer)
539d7736 4701 "Insert initial LaTeX commands at point in BUFFER."
c567ac01
RS
4702 ;; Much of this is being derived from the stuff in appendix of E in
4703 ;; the TeXBook, pg 421.
e126900f 4704 (set-buffer buffer)
c567ac01
RS
4705 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4706 "report"))
fd5359c6 4707 (page-numbering (if allout-number-pages
c567ac01
RS
4708 "\\pagestyle{empty}\n"
4709 ""))
c567ac01 4710 (titlecmd (format "\\newcommand{\\titlecmd}[1]{{%s #1}}\n"
fd5359c6 4711 allout-title-style))
c567ac01 4712 (labelcmd (format "\\newcommand{\\labelcmd}[1]{{%s #1}}\n"
fd5359c6 4713 allout-label-style))
c567ac01 4714 (headlinecmd (format "\\newcommand{\\headlinecmd}[1]{{%s #1}}\n"
fd5359c6 4715 allout-head-line-style))
c567ac01 4716 (bodylinecmd (format "\\newcommand{\\bodylinecmd}[1]{{%s #1}}\n"
fd5359c6 4717 allout-body-line-style))
c567ac01
RS
4718 (setlength (format "%s%s%s%s"
4719 "\\newlength{\\stepsize}\n"
4720 "\\setlength{\\stepsize}{"
fd5359c6 4721 allout-indent
c567ac01
RS
4722 "}\n"))
4723 (oneheadline (format "%s%s%s%s%s%s%s"
4724 "\\newcommand{\\OneHeadLine}[3]{%\n"
4725 "\\noindent%\n"
4726 "\\hspace*{#2\\stepsize}%\n"
4727 "\\labelcmd{#1}\\hspace*{.2cm}"
4728 "\\headlinecmd{#3}\\\\["
fd5359c6 4729 allout-line-skip
c567ac01
RS
4730 "]\n}\n"))
4731 (onebodyline (format "%s%s%s%s%s%s"
4732 "\\newcommand{\\OneBodyLine}[2]{%\n"
4733 "\\noindent%\n"
4734 "\\hspace*{#1\\stepsize}%\n"
4735 "\\bodylinecmd{#2}\\\\["
fd5359c6 4736 allout-line-skip
c567ac01
RS
4737 "]\n}\n"))
4738 (begindoc "\\begin{document}\n\\begin{center}\n")
4739 (title (format "%s%s%s%s"
4740 "\\titlecmd{"
fd5359c6 4741 (allout-latex-verb-quote (if allout-title
96b83743 4742 (condition-case nil
fd5359c6 4743 (eval allout-title)
9179616f 4744 ('error "<unnamed buffer>"))
c567ac01
RS
4745 "Unnamed Outline"))
4746 "}\n"
4747 "\\end{center}\n\n"))
4748 (hsize "\\hsize = 7.5 true in\n")
4749 (hoffset "\\hoffset = -1.5 true in\n")
4750 (vspace "\\vspace{.1cm}\n\n"))
4751 (insert (concat doc-style
4752 page-numbering
4753 titlecmd
4754 labelcmd
4755 headlinecmd
4756 bodylinecmd
4757 setlength
4758 oneheadline
4759 onebodyline
4760 begindoc
4761 title
4762 hsize
4763 hoffset
4764 vspace)
4765 )))
e126900f
JB
4766;;;_ > allout-insert-latex-trailer (buffer)
4767(defun allout-insert-latex-trailer (buffer)
539d7736 4768 "Insert concluding LaTeX commands at point in BUFFER."
e126900f 4769 (set-buffer buffer)
c567ac01 4770 (insert "\n\\end{document}\n"))
fd5359c6
MR
4771;;;_ > allout-latexify-one-item (depth prefix bullet text)
4772(defun allout-latexify-one-item (depth prefix bullet text)
19b84ba3
RS
4773 "Insert LaTeX commands for formatting one outline item.
4774
9179616f 4775Args are the topics numeric DEPTH, the header PREFIX lead string, the
19b84ba3 4776BULLET string, and a list of TEXT strings for the body."
c567ac01
RS
4777 (let* ((head-line (if text (car text)))
4778 (body-lines (cdr text))
4779 (curr-line)
4780 body-content bop)
4781 ; Do the head line:
71296446 4782 (insert (concat "\\OneHeadLine{\\verb\1 "
d82979ea
EZ
4783 (allout-latex-verb-quote bullet)
4784 "\1}{"
4785 depth
4786 "}{\\verb\1 "
4787 (if head-line
4788 (allout-latex-verb-quote head-line)
4789 "")
4790 "\1}\n"))
c567ac01
RS
4791 (if (not body-lines)
4792 nil
eac9cf5f
PJ
4793 ;;(insert "\\beginlines\n")
4794 (insert "\\begin{verbatim}\n")
c567ac01
RS
4795 (while body-lines
4796 (setq curr-line (car body-lines))
4797 (if (and (not body-content)
4798 (not (string-match "^\\s-*$" curr-line)))
4799 (setq body-content t))
4800 ; Mangle any occurrences of
4801 ; "\end{verbatim}" in text,
4802 ; it's special:
4803 (if (and body-content
4804 (setq bop (string-match "\\end{verbatim}" curr-line)))
4805 (setq curr-line (concat (substring curr-line 0 bop)
4806 ">"
4807 (substring curr-line bop))))
eac9cf5f
PJ
4808 ;;(insert "|" (car body-lines) "|")
4809 (insert curr-line)
fd5359c6 4810 (allout-latex-verbatim-quote-curr-line)
eac9cf5f 4811 (insert "\n")
c567ac01
RS
4812 (setq body-lines (cdr body-lines)))
4813 (if body-content
4814 (setq body-content nil)
4815 (forward-char -1)
eac9cf5f 4816 (insert "\\ ")
c567ac01 4817 (forward-char 1))
eac9cf5f
PJ
4818 ;;(insert "\\endlines\n")
4819 (insert "\\end{verbatim}\n")
c567ac01 4820 )))
fd5359c6
MR
4821;;;_ > allout-latexify-exposed (arg &optional tobuf)
4822(defun allout-latexify-exposed (arg &optional tobuf)
539d7736 4823 "Format current topics exposed portions to TOBUF for LaTeX processing.
19b84ba3
RS
4824TOBUF defaults to a buffer named the same as the current buffer, but
4825with \"*\" prepended and \" latex-formed*\" appended.
c567ac01
RS
4826
4827With repeat count, copy the exposed portions of entire buffer."
4828
4829 (interactive "P")
4830 (if (not tobuf)
4831 (setq tobuf
4832 (get-buffer-create (concat "*" (buffer-name) " latexified*"))))
4833 (let* ((start-pt (point))
fd5359c6
MR
4834 (beg (if arg (point-min) (allout-back-to-current-heading)))
4835 (end (if arg (point-max) (allout-end-of-current-subtree)))
c567ac01
RS
4836 (buf (current-buffer)))
4837 (set-buffer tobuf)
1977b8f6 4838 (erase-buffer)
fd5359c6 4839 (allout-insert-latex-header tobuf)
c567ac01 4840 (goto-char (point-max))
fd5359c6 4841 (allout-process-exposed 'allout-latexify-one-item
c567ac01
RS
4842 beg
4843 end
4844 buf
4845 tobuf)
4846 (goto-char (point-max))
fd5359c6 4847 (allout-insert-latex-trailer tobuf)
1977b8f6 4848 (goto-char (point-min))
c567ac01
RS
4849 (pop-to-buffer buf)
4850 (goto-char start-pt)))
4851
d82979ea 4852;;;_ #8 Encryption
0949617b
EZ
4853;;;_ > allout-toggle-current-subtree-encryption (&optional fetch-pass)
4854(defun allout-toggle-current-subtree-encryption (&optional fetch-pass)
69027dea 4855 "Encrypt clear or decrypt encoded text of visibly-containing topic's contents.
d82979ea 4856
0949617b
EZ
4857Optional FETCH-PASS universal argument provokes key-pair encryption with
4858single universal argument. With doubled universal argument \(value = 16),
4859it forces prompting for the passphrase regardless of availability from the
4860passphrase cache. With no universal argument, the appropriate passphrase
69027dea 4861is obtained from the cache, if available, else from the user.
d82979ea
EZ
4862
4863Currently only GnuPG encryption is supported.
4864
4865\**NOTE WELL** that the encrypted text must be ascii-armored. For gnupg
4866encryption, include the option ``armor'' in your ~/.gnupg/gpg.conf file.
4867
4868Both symmetric-key and key-pair encryption is implemented. Symmetric is
4869the default, use a single \(x4) universal argument for keypair mode.
4870
4871Encrypted topic's bullet is set to a `~' to signal that the contents of the
4872topic \(body and subtopics, but not heading) is pending encryption or
0949617b
EZ
4873encrypted. `*' asterisk immediately after the bullet signals that the body
4874is encrypted, its' absence means the topic is meant to be encrypted but is
4875not. When a file with topics pending encryption is saved, topics pending
4876encryption are encrypted. See allout-encrypt-unencrypted-on-saves for
4877auto-encryption specifics.
4878
4879\**NOTE WELL** that automatic encryption that happens during saves will
4880default to symmetric encryption - you must manually \(re)encrypt key-pair
4881encrypted topics if you want them to continue to use the key-pair cipher.
d82979ea
EZ
4882
4883Level-1 topics, with prefix consisting solely of an `*' asterisk, cannot be
4884encrypted. If you want to encrypt the contents of a top-level topic, use
4885\\[allout-shift-in] to increase its depth.
4886
0949617b
EZ
4887 Passphrase Caching
4888
4889The encryption passphrase is solicited if not currently available in the
4890passphrase cache from a recent encryption action.
4891
4892The solicited passphrase is retained for reuse in a buffer-specific cache
4893for some set period of time \(default, 60 seconds), after which the string
4894is nulled. The passphrase cache timeout is customized by setting
4895`pgg-passphrase-cache-expiry'.
4896
4897 Symmetric Passphrase Hinting and Verification
4898
4899If the file previously had no associated passphrase, or had a different
4900passphrase than specified, the user is prompted to repeat the new one for
4901corroboration. A random string encrypted by the new passphrase is set on
4902the buffer-specific variable `allout-passphrase-verifier-string', for
4903confirmation of the passphrase when next obtained, before encrypting or
4904decrypting anything with it. This helps avoid mistakenly shifting between
4905keys.
4906
4907If allout customization var `allout-passphrase-verifier-handling' is
4908non-nil, an entry for `allout-passphrase-verifier-string' and its value is
4909added to an Emacs 'local variables' section at the end of the file, which
4910is created if necessary. That setting is for retention of the passphrase
4911verifier across emacs sessions.
4912
4913Similarly, `allout-passphrase-hint-string' stores a user-provided reminder
4914about their passphrase, and `allout-passphrase-hint-handling' specifies
4915when the hint is presented, or if passphrase hints are disabled. If
4916enabled \(see the `allout-passphrase-hint-handling' docstring for details),
4917the hint string is stored in the local-variables section of the file, and
4918solicited whenever the passphrase is changed."
69027dea
EZ
4919 (interactive "P")
4920 (save-excursion
4921 (allout-back-to-current-heading)
96b83743 4922 (allout-toggle-subtree-encryption fetch-pass)
69027dea
EZ
4923 )
4924 )
4925;;;_ > allout-toggle-subtree-encryption (&optional fetch-pass)
4926(defun allout-toggle-subtree-encryption (&optional fetch-pass)
4927 "Encrypt clear text or decrypt encoded topic contents \(body and subtopics.)
4928
4929Optional FETCH-PASS universal argument provokes key-pair encryption with
4930single universal argument. With doubled universal argument \(value = 16),
4931it forces prompting for the passphrase regardless of availability from the
4932passphrase cache. With no universal argument, the appropriate passphrase
4933is obtained from the cache, if available, else from the user.
4934
4935Currently only GnuPG encryption is supported.
4936
4937\**NOTE WELL** that the encrypted text must be ascii-armored. For gnupg
4938encryption, include the option ``armor'' in your ~/.gnupg/gpg.conf file.
4939
4940See `allout-toggle-current-subtree-encryption' for more details."
d82979ea
EZ
4941
4942 (interactive "P")
4943 (save-excursion
4944 (allout-end-of-prefix t)
4945
4946 (if (= (allout-recent-depth) 1)
4947 (error (concat "Cannot encrypt or decrypt level 1 topics -"
4948 " shift it in to make it encryptable")))
4949
d82979ea
EZ
4950 (let* ((allout-buffer (current-buffer))
4951 ;; Asses location:
4952 (after-bullet-pos (point))
4953 (was-encrypted
4954 (progn (if (= (point-max) after-bullet-pos)
4955 (error "no body to encrypt"))
0949617b 4956 (allout-encrypted-topic-p)))
96b83743 4957 (was-collapsed (if (not (search-forward "\n" nil t))
d82979ea
EZ
4958 nil
4959 (backward-char 1)
96b83743 4960 (allout-hidden-p)))
d82979ea
EZ
4961 (subtree-beg (1+ (point)))
4962 (subtree-end (allout-end-of-subtree))
4963 (subject-text (buffer-substring-no-properties subtree-beg
4964 subtree-end))
4965 (subtree-end-char (char-after (1- subtree-end)))
96b83743
EZ
4966 (subtree-trailing-char (char-after subtree-end))
4967 ;; kluge - result-text needs to be nil, but we also want to
4968 ;; check for the error condition
4969 (result-text (if (or (string= "" subject-text)
4970 (string= "\n" subject-text))
4971 (error "No topic contents to %scrypt"
4972 (if was-encrypted "de" "en"))
4973 nil))
d82979ea 4974 ;; Assess key parameters:
0949617b 4975 (key-info (or
d82979ea
EZ
4976 ;; detect the type by which it is already encrypted
4977 (and was-encrypted
0949617b
EZ
4978 (allout-encrypted-key-info subject-text))
4979 (and (member fetch-pass '(4 (4)))
4980 '(keypair nil))
4981 '(symmetric nil)))
4982 (for-key-type (car key-info))
4983 (for-key-identity (cadr key-info))
96b83743 4984 (fetch-pass (and fetch-pass (member fetch-pass '(16 (16))))))
d82979ea
EZ
4985
4986 (setq result-text
4987 (allout-encrypt-string subject-text was-encrypted
0949617b
EZ
4988 (current-buffer)
4989 for-key-type for-key-identity fetch-pass))
d82979ea
EZ
4990
4991 ;; Replace the subtree with the processed product.
4992 (allout-unprotected
4993 (progn
4994 (set-buffer allout-buffer)
4995 (delete-region subtree-beg subtree-end)
4996 (insert result-text)
4997 (if was-collapsed
96b83743
EZ
4998 (allout-flag-region (1- subtree-beg) (point) t))
4999 ;; adjust trailing-blank-lines to preserve topic spacing:
d82979ea 5000 (if (not was-encrypted)
96b83743
EZ
5001 (if (and (= subtree-end-char ?\n)
5002 (= subtree-trailing-char ?\n))
5003 (insert subtree-trailing-char)))
d82979ea
EZ
5004 ;; Ensure that the item has an encrypted-entry bullet:
5005 (if (not (string= (buffer-substring-no-properties
5006 (1- after-bullet-pos) after-bullet-pos)
5007 allout-topic-encryption-bullet))
5008 (progn (goto-char (1- after-bullet-pos))
5009 (delete-char 1)
5010 (insert allout-topic-encryption-bullet)))
5011 (if was-encrypted
5012 ;; Remove the is-encrypted bullet qualifier:
5013 (progn (goto-char after-bullet-pos)
5014 (delete-char 1))
5015 ;; Add the is-encrypted bullet qualifier:
5016 (goto-char after-bullet-pos)
5017 (insert "*"))
5018 )
5019 )
5020 )
5021 )
5022 )
0949617b
EZ
5023;;;_ > allout-encrypt-string (text decrypt allout-buffer key-type for-key
5024;;; fetch-pass &optional retried verifying
5025;;; passphrase)
5026(defun allout-encrypt-string (text decrypt allout-buffer key-type for-key
5027 fetch-pass &optional retried verifying
5028 passphrase)
5029 "Encrypt or decrypt message TEXT.
d82979ea 5030
0949617b 5031If DECRYPT is true (default false), then decrypt instead of encrypt.
d82979ea 5032
0949617b 5033FETCH-PASS (default false) forces fresh prompting for the passphrase.
d82979ea 5034
0949617b 5035KEY-TYPE indicates whether to use a 'symmetric or 'keypair cipher.
d82979ea 5036
0949617b
EZ
5037FOR-KEY is human readable identification of the first of the user's
5038eligible secret keys a keypair decryption targets, or else nil.
d82979ea 5039
0949617b
EZ
5040Optional RETRIED is for internal use - conveys the number of failed keys
5041that have been solicited in sequence leading to this current call.
5042
5043Optional PASSPHRASE enables explicit delivery of the decryption passphrase,
5044for verification purposes.
d82979ea 5045
0949617b 5046Returns the resulting string, or nil if the transformation fails."
d82979ea 5047
0949617b
EZ
5048 (require 'pgg)
5049
69027dea
EZ
5050 (if (not (fboundp 'pgg-encrypt-symmetric))
5051 (error "Allout encryption depends on a newer version of pgg"))
5052
0949617b
EZ
5053 (let* ((scheme (upcase
5054 (format "%s" (or pgg-scheme pgg-default-scheme "GPG"))))
5055 (for-key (and (equal key-type 'keypair)
5056 (or for-key
5057 (split-string (read-string
5058 (format "%s message recipients: "
5059 scheme))
5060 "[ \t,]+"))))
5061 (target-prompt-id (if (equal key-type 'keypair)
5062 (if (= (length for-key) 1)
5063 (car for-key) for-key)
5064 (buffer-name allout-buffer)))
5065 (target-cache-id (format "%s-%s"
5066 key-type
5067 (if (equal key-type 'keypair)
5068 target-prompt-id
5069 (or (buffer-file-name allout-buffer)
5070 target-prompt-id))))
96b83743 5071 result-text status)
0949617b
EZ
5072
5073 (if (and fetch-pass (not passphrase))
5074 ;; Force later fetch by evicting passphrase from the cache.
5075 (pgg-remove-passphrase-from-cache target-cache-id t))
5076
5077 (catch 'encryption-failed
5078
5079 ;; Obtain the passphrase if we don't already have one and we're not
5080 ;; doing a keypair encryption:
5081 (if (not (or passphrase
5082 (and (equal key-type 'keypair)
5083 (not decrypt))))
5084
5085 (setq passphrase (allout-obtain-passphrase for-key
5086 target-cache-id
5087 target-prompt-id
5088 key-type
5089 allout-buffer
5090 retried fetch-pass)))
5091 (with-temp-buffer
5092
96b83743 5093 (insert text)
d82979ea 5094
0949617b 5095 (cond
d82979ea 5096
0949617b
EZ
5097 ;; symmetric:
5098 ((equal key-type 'symmetric)
5099 (setq status
5100 (if decrypt
5101
5102 (pgg-decrypt (point-min) (point-max) passphrase)
5103
5104 (pgg-encrypt-symmetric (point-min) (point-max)
5105 passphrase)))
5106
5107 (if status
5108 (pgg-situate-output (point-min) (point-max))
5109 ;; failed - handle passphrase caching
5110 (if verifying
5111 (throw 'encryption-failed nil)
5112 (pgg-remove-passphrase-from-cache target-cache-id t)
5113 (error "Symmetric-cipher encryption failed - %s"
5114 "try again with different passphrase."))))
5115
5116 ;; encrypt 'keypair:
5117 ((not decrypt)
5118
5119 (setq status
5120
5121 (pgg-encrypt for-key
5122 nil (point-min) (point-max) passphrase))
5123
5124 (if status
5125 (pgg-situate-output (point-min) (point-max))
5126 (error (pgg-remove-passphrase-from-cache target-cache-id t)
5127 (error "encryption failed"))))
5128
5129 ;; decrypt 'keypair:
5130 (t
5131
5132 (setq status
5133 (pgg-decrypt (point-min) (point-max) passphrase))
5134
5135 (if status
5136 (pgg-situate-output (point-min) (point-max))
5137 (error (pgg-remove-passphrase-from-cache target-cache-id t)
5138 (error "decryption failed"))))
5139 )
5140
5141 (setq result-text
5142 (buffer-substring 1 (- (point-max) (if decrypt 0 1))))
5143
5144 ;; validate result - non-empty
5145 (cond ((not result-text)
5146 (if verifying
5147 nil
5148 ;; transform was fruitless, retry w/new passphrase.
5149 (pgg-remove-passphrase-from-cache target-cache-id t)
5150 (allout-encrypt-string text allout-buffer decrypt nil
5151 (if retried (1+ retried) 1)
5152 passphrase)))
5153
5154 ;; Barf if encryption yields extraordinary control chars:
5155 ((and (not decrypt)
5156 (string-match "[\C-a\C-k\C-o-\C-z\C-@]"
5157 result-text))
5158 (error (concat "encryption produced unusable"
5159 " non-armored text - reconfigure!")))
5160
5161 ;; valid result and just verifying or non-symmetric:
5162 ((or verifying (not (equal key-type 'symmetric)))
5163 (if (or verifying decrypt)
5164 (pgg-add-passphrase-to-cache target-cache-id
5165 passphrase t))
5166 result-text)
5167
5168 ;; valid result and regular symmetric - "register"
5169 ;; passphrase with mnemonic aids/cache.
5170 (t
5171 (set-buffer allout-buffer)
5172 (if passphrase
5173 (pgg-add-passphrase-to-cache target-cache-id
5174 passphrase t))
5175 (allout-update-passphrase-mnemonic-aids for-key passphrase
5176 allout-buffer)
5177 result-text)
5178 )
d82979ea
EZ
5179 )
5180 )
d82979ea
EZ
5181 )
5182 )
0949617b
EZ
5183;;;_ > allout-obtain-passphrase (for-key cache-id prompt-id key-type
5184;;; allout-buffer retried fetch-pass)
4034b0e2 5185(defun allout-obtain-passphrase (for-key cache-id prompt-id key-type
0949617b
EZ
5186 allout-buffer retried fetch-pass)
5187 "Obtain passphrase for a key from the cache or else from the user.
5188
5189When obtaining from the user, symmetric-cipher passphrases are verified
5190against either, if available and enabled, a random string that was
5191encrypted against the passphrase, or else against repeated entry by the
5192user for corroboration.
5193
5194FOR-KEY is the key for which the passphrase is being obtained.
5195
5196CACHE-ID is the cache id of the key for the passphrase.
5197
5198PROMPT-ID is the id for use when prompting the user.
5199
5200KEY-TYPE is either 'symmetric or 'keypair.
5201
5202ALLOUT-BUFFER is the buffer containing the entry being en/decrypted.
5203
5204RETRIED is the number of this attempt to obtain this passphrase.
5205
5206FETCH-PASS causes the passphrase to be solicited from the user, regardless
5207of the availability of a cached copy."
d82979ea
EZ
5208
5209 (if (not (equal key-type 'symmetric))
0949617b
EZ
5210 ;; do regular passphrase read on non-symmetric passphrase:
5211 (pgg-read-passphrase (format "%s passphrase%s: "
5212 (upcase (format "%s" (or pgg-scheme
5213 pgg-default-scheme
5214 "GPG")))
5215 (if prompt-id
5216 (format " for %s" prompt-id)
5217 ""))
5218 cache-id t)
d82979ea
EZ
5219
5220 ;; Symmetric hereon:
5221
5222 (save-excursion
5223 (set-buffer allout-buffer)
0949617b
EZ
5224 (let* ((hint (if (and (not (string= allout-passphrase-hint-string ""))
5225 (or (equal allout-passphrase-hint-handling 'always)
5226 (and (equal allout-passphrase-hint-handling
5227 'needed)
d82979ea 5228 retried)))
0949617b 5229 (format " [%s]" allout-passphrase-hint-string)
d82979ea
EZ
5230 ""))
5231 (retry-message (if retried (format " (%s retry)" retried) ""))
0949617b
EZ
5232 (prompt-sans-hint (format "'%s' symmetric passphrase%s: "
5233 prompt-id retry-message))
5234 (full-prompt (format "'%s' symmetric passphrase%s%s: "
5235 prompt-id hint retry-message))
d82979ea 5236 (prompt full-prompt)
0949617b
EZ
5237 (verifier-string (allout-get-encryption-passphrase-verifier))
5238
5239 (cached (and (not fetch-pass)
5240 (pgg-read-passphrase-from-cache cache-id t)))
5241 (got-pass (or cached
5242 (pgg-read-passphrase full-prompt cache-id t)))
5243
d82979ea
EZ
5244 confirmation)
5245
0949617b 5246 (if (not got-pass)
d82979ea
EZ
5247 nil
5248
0949617b 5249 ;; Duplicate our handle on the passphrase so it's not clobbered by
d82979ea 5250 ;; deactivate-passwd memory clearing:
0949617b 5251 (setq got-pass (format "%s" got-pass))
d82979ea
EZ
5252
5253 (cond (verifier-string
0949617b
EZ
5254 (save-window-excursion
5255 (if (allout-encrypt-string verifier-string 'decrypt
5256 allout-buffer 'symmetric
5257 for-key nil 0 'verifying
5258 got-pass)
5259 (setq confirmation (format "%s" got-pass))))
5260
5261 (if (and (not confirmation)
d82979ea 5262 (if (yes-or-no-p
0949617b 5263 (concat "Passphrase differs from established"
d82979ea
EZ
5264 " - use new one instead? "))
5265 ;; deactivate password for subsequent
5266 ;; confirmation:
0949617b
EZ
5267 (progn
5268 (pgg-remove-passphrase-from-cache cache-id t)
5269 (setq prompt prompt-sans-hint)
5270 nil)
d82979ea 5271 t))
0949617b
EZ
5272 (progn (pgg-remove-passphrase-from-cache cache-id t)
5273 (error "Wrong passphrase."))))
5274 ;; No verifier string - force confirmation by repetition of
5275 ;; (new) passphrase:
5276 ((or fetch-pass (not cached))
5277 (pgg-remove-passphrase-from-cache cache-id t))))
5278 ;; confirmation vs new input - doing pgg-read-passphrase will do the
d82979ea 5279 ;; right thing, in either case:
0949617b
EZ
5280 (if (not confirmation)
5281 (setq confirmation
5282 (pgg-read-passphrase (concat prompt
5283 " ... confirm spelling: ")
5284 cache-id t)))
d82979ea 5285 (prog1
0949617b 5286 (if (equal got-pass confirmation)
d82979ea
EZ
5287 confirmation
5288 (if (yes-or-no-p (concat "spelling of original and"
5289 " confirmation differ - retry? "))
5290 (progn (setq retried (if retried (1+ retried) 1))
0949617b 5291 (pgg-remove-passphrase-from-cache cache-id t)
d82979ea 5292 ;; recurse to this routine:
0949617b
EZ
5293 (pgg-read-passphrase prompt-sans-hint cache-id t))
5294 (pgg-remove-passphrase-from-cache cache-id t)
d82979ea
EZ
5295 (error "Confirmation failed.")))
5296 ;; reduce opportunity for memory cherry-picking by zeroing duplicate:
0949617b
EZ
5297 (dotimes (i (length got-pass))
5298 (aset got-pass i 0))
d82979ea
EZ
5299 )
5300 )
5301 )
5302 )
5303 )
d82979ea
EZ
5304;;;_ > allout-encrypted-topic-p ()
5305(defun allout-encrypted-topic-p ()
5306 "True if the current topic is encryptable and encrypted."
5307 (save-excursion
5308 (allout-end-of-prefix t)
5309 (and (string= (buffer-substring-no-properties (1- (point)) (point))
5310 allout-topic-encryption-bullet)
5311 (looking-at "\\*"))
5312 )
5313 )
0949617b
EZ
5314;;;_ > allout-encrypted-key-info (text)
5315;; XXX gpg-specific, alas
5316(defun allout-encrypted-key-info (text)
5317 "Return a pair of the key type and identity of a recipient's secret key.
5318
5319The key type is one of 'symmetric or 'keypair.
d82979ea 5320
0949617b
EZ
5321if 'keypair, and some of the user's secret keys are among those for which
5322the message was encoded, return the identity of the first. otherwise,
5323return nil for the second item of the pair.
d82979ea 5324
0949617b
EZ
5325An error is raised if the text is not encrypted."
5326 (require 'pgg-parse)
d82979ea 5327 (save-excursion
0949617b 5328 (with-temp-buffer
96b83743 5329 (insert text)
0949617b
EZ
5330 (let* ((parsed-armor (pgg-parse-armor-region (point-min) (point-max)))
5331 (type (if (pgg-gpg-symmetric-key-p parsed-armor)
5332 'symmetric
5333 'keypair))
5334 secret-keys first-secret-key for-key-owner)
5335 (if (equal type 'keypair)
5336 (setq secret-keys (pgg-gpg-lookup-all-secret-keys)
5337 first-secret-key (pgg-gpg-select-matching-key parsed-armor
5338 secret-keys)
5339 for-key-owner (and first-secret-key
5340 (pgg-gpg-lookup-key-owner
5341 first-secret-key))))
5342 (list type (pgg-gpg-key-id-from-key-owner for-key-owner))
5343 )
d82979ea
EZ
5344 )
5345 )
5346 )
0949617b
EZ
5347;;;_ > allout-create-encryption-passphrase-verifier (passphrase)
5348(defun allout-create-encryption-passphrase-verifier (passphrase)
5349 "Encrypt random message for later validation of symmetric key's passphrase."
d82979ea
EZ
5350 ;; use 20 random ascii characters, across the entire ascii range.
5351 (random t)
5352 (let ((spew (make-string 20 ?\0)))
5353 (dotimes (i (length spew))
5354 (aset spew i (1+ (random 254))))
0949617b
EZ
5355 (allout-encrypt-string spew nil (current-buffer) 'symmetric
5356 nil nil 0 passphrase))
d82979ea 5357 )
0949617b 5358;;;_ > allout-update-passphrase-mnemonic-aids (for-key passphrase
4034b0e2 5359;;; outline-buffer)
0949617b
EZ
5360(defun allout-update-passphrase-mnemonic-aids (for-key passphrase
5361 outline-buffer)
5362 "Update passphrase verifier and hint strings if necessary.
5363
5364See `allout-passphrase-verifier-string' and `allout-passphrase-hint-string'
5365settings.
5366
5367PASSPHRASE is the passphrase being mnemonicized
5368
5369OUTLINE-BUFFER is the buffer of the outline being adjusted.
5370
5371These are used to help the user keep track of the passphrase they use for
5372symmetric encryption in the file.
5373
5374Behavior is governed by `allout-passphrase-verifier-handling',
5375`allout-passphrase-hint-handling', and also, controlling whether the values
5376are preserved on Emacs local file variables,
5377`allout-enable-file-variable-adjustment'."
5378
5379 ;; If passphrase doesn't agree with current verifier:
5380 ;; - adjust the verifier
5381 ;; - if passphrase hint handling is enabled, adjust the passphrase hint
5382 ;; - if file var settings are enabled, adjust the file vars
5383
5384 (let* ((new-verifier-needed (not (allout-verify-passphrase
5385 for-key passphrase outline-buffer)))
5386 (new-verifier-string
5387 (if new-verifier-needed
5388 ;; Collapse to a single line and enclose in string quotes:
5389 (subst-char-in-string
5390 ?\n ?\C-a (allout-create-encryption-passphrase-verifier
5391 passphrase))))
5392 new-hint)
5393 (when new-verifier-string
5394 ;; do the passphrase hint first, since it's interactive
5395 (when (and allout-passphrase-hint-handling
5396 (not (equal allout-passphrase-hint-handling 'disabled)))
5397 (setq new-hint
5398 (read-from-minibuffer "Passphrase hint to jog your memory: "
5399 allout-passphrase-hint-string))
5400 (when (not (string= new-hint allout-passphrase-hint-string))
5401 (setq allout-passphrase-hint-string new-hint)
5402 (allout-adjust-file-variable "allout-passphrase-hint-string"
5403 allout-passphrase-hint-string)))
5404 (when allout-passphrase-verifier-handling
5405 (setq allout-passphrase-verifier-string new-verifier-string)
5406 (allout-adjust-file-variable "allout-passphrase-verifier-string"
5407 allout-passphrase-verifier-string))
5408 )
d82979ea
EZ
5409 )
5410 )
0949617b
EZ
5411;;;_ > allout-get-encryption-passphrase-verifier ()
5412(defun allout-get-encryption-passphrase-verifier ()
5413 "Return text of the encrypt passphrase verifier, unmassaged, or nil if none.
d82979ea 5414
4034b0e2 5415Derived from value of `allout-passphrase-verifier-string'."
d82979ea 5416
0949617b
EZ
5417 (let ((verifier-string (and (boundp 'allout-passphrase-verifier-string)
5418 allout-passphrase-verifier-string)))
d82979ea
EZ
5419 (if verifier-string
5420 ;; Return it uncollapsed
0949617b 5421 (subst-char-in-string ?\C-a ?\n verifier-string))
d82979ea
EZ
5422 )
5423 )
0949617b
EZ
5424;;;_ > allout-verify-passphrase (key passphrase allout-buffer)
5425(defun allout-verify-passphrase (key passphrase allout-buffer)
5426 "True if passphrase successfully decrypts verifier, nil otherwise.
d82979ea 5427
0949617b 5428\"Otherwise\" includes absence of passphrase verifier."
d82979ea
EZ
5429 (save-excursion
5430 (set-buffer allout-buffer)
0949617b
EZ
5431 (and (boundp 'allout-passphrase-verifier-string)
5432 allout-passphrase-verifier-string
5433 (allout-encrypt-string (allout-get-encryption-passphrase-verifier)
d82979ea 5434 'decrypt allout-buffer 'symmetric
0949617b 5435 key nil 0 'verifying passphrase)
d82979ea
EZ
5436 t)))
5437;;;_ > allout-next-topic-pending-encryption (&optional except-mark)
5438(defun allout-next-topic-pending-encryption (&optional except-mark)
5439 "Return the point of the next topic pending encryption, or nil if none.
5440
5441EXCEPT-MARK identifies a point whose containing topics should be excluded
5442from encryption. This supports 'except-current mode of
5443`allout-encrypt-unencrypted-on-saves'.
5444
5445Such a topic has the allout-topic-encryption-bullet without an
5446immediately following '*' that would mark the topic as being encrypted. It
5447must also have content."
5448 (let (done got content-beg)
5449 (while (not done)
5450
5451 (if (not (re-search-forward
96b83743 5452 (format "\\(\\`\\|\n\\)%s *%s[^*]"
d82979ea
EZ
5453 (regexp-quote allout-header-prefix)
5454 (regexp-quote allout-topic-encryption-bullet))
5455 nil t))
5456 (setq got nil
5457 done t)
5458 (goto-char (setq got (match-beginning 0)))
96b83743 5459 (if (looking-at "\n")
d82979ea
EZ
5460 (forward-char 1))
5461 (setq got (point)))
5462
5463 (cond ((not got)
5464 (setq done t))
5465
96b83743 5466 ((not (search-forward "\n"))
d82979ea
EZ
5467 (setq got nil
5468 done t))
5469
5470 ((eobp)
5471 (setq got nil
5472 done t))
5473
5474 (t
5475 (setq content-beg (point))
5476 (backward-char 1)
5477 (allout-end-of-subtree)
5478 (if (or (<= (point) content-beg)
5479 (and except-mark
5480 (<= content-beg except-mark)
5481 (>= (point) except-mark)))
5482 ;; Continue looking
5483 (setq got nil)
5484 ;; Got it!
5485 (setq done t)))
5486 )
5487 )
5488 (if got
5489 (goto-char got))
5490 )
5491 )
5492;;;_ > allout-encrypt-decrypted (&optional except-mark)
5493(defun allout-encrypt-decrypted (&optional except-mark)
5494 "Encrypt topics pending encryption except those containing exemption point.
5495
5496EXCEPT-MARK identifies a point whose containing topics should be excluded
5497from encryption. This supports 'except-current mode of
5498`allout-encrypt-unencrypted-on-saves'.
5499
5500If a topic that is currently being edited was encrypted, we return a list
5501containing the location of the topic and the location of the cursor just
5502before the topic was encrypted. This can be used, eg, to decrypt the topic
5503and exactly resituate the cursor if this is being done as part of a file
5504save. See `allout-encrypt-unencrypted-on-saves' for more info."
5505
5506 (interactive "p")
5507 (save-excursion
96b83743
EZ
5508 (let* ((current-mark (point-marker))
5509 (current-mark-position (marker-position current-mark))
5510 was-modified
5511 bo-subtree
5512 editing-topic editing-point)
d82979ea
EZ
5513 (goto-char (point-min))
5514 (while (allout-next-topic-pending-encryption except-mark)
5515 (setq was-modified (buffer-modified-p))
96b83743
EZ
5516 (when (save-excursion
5517 (and (boundp 'allout-encrypt-unencrypted-on-saves)
5518 allout-encrypt-unencrypted-on-saves
5519 (setq bo-subtree (re-search-forward "$"))
5520 (not (allout-hidden-p))
5521 (>= current-mark (point))
5522 (allout-end-of-current-subtree)
5523 (<= current-mark (point))))
d82979ea
EZ
5524 (setq editing-topic (point)
5525 ;; we had to wait for this 'til now so prior topics are
5526 ;; encrypted, any relevant text shifts are in place:
96b83743
EZ
5527 editing-point (- current-mark-position
5528 (count-trailing-whitespace-region
5529 bo-subtree current-mark-position))))
69027dea 5530 (allout-toggle-subtree-encryption)
d82979ea
EZ
5531 (if (not was-modified)
5532 (set-buffer-modified-p nil))
5533 )
5534 (if (not was-modified)
5535 (set-buffer-modified-p nil))
5536 (if editing-topic (list editing-topic editing-point))
5537 )
5538 )
5539 )
5540
5541;;;_ #9 miscellaneous
fd5359c6
MR
5542;;;_ > allout-mark-topic ()
5543(defun allout-mark-topic ()
c567ac01
RS
5544 "Put the region around topic currently containing point."
5545 (interactive)
5546 (beginning-of-line)
fd5359c6 5547 (allout-goto-prefix)
c567ac01 5548 (push-mark (point))
fd5359c6 5549 (allout-end-of-current-subtree)
c567ac01
RS
5550 (exchange-point-and-mark))
5551;;;_ > outlineify-sticky ()
19b84ba3 5552;; outlinify-sticky is correct spelling; provide this alias for sticklers:
0949617b 5553;;;###autoload
19b84ba3 5554(defalias 'outlinify-sticky 'outlineify-sticky)
0949617b 5555;;;###autoload
c567ac01 5556(defun outlineify-sticky (&optional arg)
a0776d6b 5557 "Activate outline mode and establish file var so it is started subsequently.
1977b8f6 5558
fd5359c6 5559See doc-string for `allout-layout' and `allout-init' for details on
19b84ba3
RS
5560setup for auto-startup."
5561
5562 (interactive "P")
5563
fd5359c6 5564 (allout-mode t)
19b84ba3
RS
5565
5566 (save-excursion
5567 (goto-char (point-min))
fd5359c6 5568 (if (looking-at allout-regexp)
19b84ba3 5569 t
fd5359c6 5570 (allout-open-topic 2)
eac9cf5f 5571 (insert (concat "Dummy outline topic header - see"
d82979ea
EZ
5572 "`allout-mode' docstring: `^Hm'."))
5573 (allout-adjust-file-variable
4034b0e2 5574 "allout-layout" (or allout-layout '(-1 : 0))))))
d82979ea
EZ
5575;;;_ > allout-file-vars-section-data ()
5576(defun allout-file-vars-section-data ()
5577 "Return data identifying the file-vars section, or nil if none.
5578
5579Returns list `(beginning-point prefix-string suffix-string)'."
5580 ;; minimally gleaned from emacs 21.4 files.el hack-local-variables function.
5581 (let (beg prefix suffix)
5582 (save-excursion
1977b8f6 5583 (goto-char (point-max))
d82979ea
EZ
5584 (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
5585 (if (let ((case-fold-search t))
5586 (not (search-forward "Local Variables:" nil t)))
5587 nil
5588 (setq beg (- (point) 16))
5589 (setq suffix (buffer-substring-no-properties
5590 (point)
96b83743 5591 (progn (if (search-forward "\n" nil t)
d82979ea
EZ
5592 (forward-char -1))
5593 (point))))
5594 (setq prefix (buffer-substring-no-properties
96b83743 5595 (progn (if (search-backward "\n" nil t)
d82979ea
EZ
5596 (forward-char 1))
5597 (point))
5598 beg))
5599 (list beg prefix suffix))
5600 )
5601 )
5602 )
5603;;;_ > allout-adjust-file-variable (varname value)
5604(defun allout-adjust-file-variable (varname value)
5605 "Adjust the setting of an emacs file variable named VARNAME to VALUE.
5606
5607This activity is inhibited if either `enable-local-variables'
5608`allout-enable-file-variable-adjustment' are nil.
5609
5610When enabled, an entry for the variable is created if not already present,
5611or changed if established with a different value. The section for the file
5612variables, itself, is created if not already present. When created, the
5613section lines \(including the section line) exist as second-level topics in
5614a top-level topic at the end of the file.
5615
5616enable-local-variables must be true for any of this to happen."
5617 (if (not (and enable-local-variables
5618 allout-enable-file-variable-adjustment))
5619 nil
5620 (save-excursion
5621 (let ((section-data (allout-file-vars-section-data))
5622 beg prefix suffix)
5623 (if section-data
5624 (setq beg (car section-data)
5625 prefix (cadr section-data)
5626 suffix (car (cddr section-data)))
5627 ;; create the section
5628 (goto-char (point-max))
5629 (open-line 1)
5630 (allout-open-topic 0)
5631 (end-of-line)
5632 (insert "Local emacs vars.\n")
5633 (allout-open-topic 1)
5634 (setq beg (point)
5635 suffix ""
5636 prefix (buffer-substring-no-properties (progn
5637 (beginning-of-line)
5638 (point))
5639 beg))
5640 (goto-char beg)
5641 (insert "Local variables:\n")
5642 (allout-open-topic 0)
5643 (insert "End:\n")
5644 )
5645 ;; look for existing entry or create one, leaving point for insertion
5646 ;; of new value:
5647 (goto-char beg)
5648 (allout-show-to-offshoot)
5649 (if (search-forward (concat "\n" prefix varname ":") nil t)
5650 (let* ((value-beg (point))
96b83743 5651 (line-end (progn (if (search-forward "\n" nil t)
d82979ea
EZ
5652 (forward-char -1))
5653 (point)))
5654 (value-end (- line-end (length suffix))))
5655 (if (> value-end value-beg)
5656 (delete-region value-beg value-end)))
5657 (end-of-line)
5658 (open-line 1)
5659 (forward-line 1)
5660 (insert (concat prefix varname ":")))
5661 (insert (format " %S%s" value suffix))
5662 )
5663 )
5664 )
5665 )
c567ac01 5666;;;_ > solicit-char-in-string (prompt string &optional do-defaulting)
1977b8f6 5667(defun solicit-char-in-string (prompt string &optional do-defaulting)
c567ac01 5668 "Solicit (with first arg PROMPT) choice of a character from string STRING.
1977b8f6 5669
c567ac01 5670Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
1977b8f6
RS
5671
5672 (let ((new-prompt prompt)
5673 got)
5674
5675 (while (not got)
5676 (message "%s" new-prompt)
5677
5678 ;; We do our own reading here, so we can circumvent, eg, special
9179616f 5679 ;; treatment for `?' character. (Oughta use minibuffer keymap instead.)
1977b8f6 5680 (setq got
c567ac01 5681 (char-to-string (let ((cursor-in-echo-area nil)) (read-char))))
1977b8f6 5682
9179616f
DL
5683 (setq got
5684 (cond ((string-match (regexp-quote got) string) got)
5685 ((and do-defaulting (string= got "\r"))
5686 ;; Return empty string to default:
5687 "")
5688 ((string= got "\C-g") (signal 'quit nil))
5689 (t
5690 (setq new-prompt (concat prompt
5691 got
5692 " ...pick from: "
5693 string
5694 ""))
5695 nil))))
5696 ;; got something out of loop - return it:
5697 got)
1977b8f6 5698 )
c567ac01
RS
5699;;;_ > regexp-sans-escapes (string)
5700(defun regexp-sans-escapes (regexp &optional successive-backslashes)
5701 "Return a copy of REGEXP with all character escapes stripped out.
19b84ba3 5702
c567ac01
RS
5703Representations of actual backslashes - '\\\\\\\\' - are left as a
5704single backslash.
5705
d82979ea 5706Optional arg SUCCESSIVE-BACKSLASHES is used internally for recursion."
c567ac01
RS
5707
5708 (if (string= regexp "")
5709 ""
5710 ;; Set successive-backslashes to number if current char is
5711 ;; backslash, or else to nil:
5712 (setq successive-backslashes
5713 (if (= (aref regexp 0) ?\\)
5714 (if successive-backslashes (1+ successive-backslashes) 1)
5715 nil))
5716 (if (or (not successive-backslashes) (= 2 successive-backslashes))
5717 ;; Include first char:
5718 (concat (substring regexp 0 1)
5719 (regexp-sans-escapes (substring regexp 1)))
5720 ;; Exclude first char, but maintain count:
5721 (regexp-sans-escapes (substring regexp 1) successive-backslashes))))
96b83743
EZ
5722;;;_ > count-trailing-whitespace-region (beg end)
5723(defun count-trailing-whitespace-region (beg end)
5724 "Return number of trailing whitespace chars between BEG and END.
5725
5726If BEG is bigger than END we return 0."
5727 (if (> beg end)
5728 0
5729 (save-excursion
5730 (goto-char beg)
5731 (let ((count 0))
5732 (while (re-search-forward "[ ][ ]*$" end t)
5733 (goto-char (1+ (match-beginning 0)))
5734 (setq count (1+ count)))
5735 count))))
5736;;;_ > allout-mark-marker to accommodate divergent emacsen:
5737(defun allout-mark-marker (&optional force buffer)
5738 "Accommodate the different signature for `mark-marker' across Emacsen.
5739
5740XEmacs takes two optional args, while mainline GNU Emacs does not,
5741so pass them along when appropriate."
5742 (if (featurep 'xemacs)
5743 (apply 'mark-marker force buffer)
5744 (mark-marker)))
d82979ea
EZ
5745;;;_ > subst-char-in-string if necessary
5746(if (not (fboundp 'subst-char-in-string))
5747 (defun subst-char-in-string (fromchar tochar string &optional inplace)
5748 "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
5749Unless optional argument INPLACE is non-nil, return a new string."
5750 (let ((i (length string))
5751 (newstr (if inplace string (copy-sequence string))))
5752 (while (> i 0)
5753 (setq i (1- i))
5754 (if (eq (aref newstr i) fromchar)
5755 (aset newstr i tochar)))
5756 newstr)))
96b83743
EZ
5757;;;_ > wholenump if necessary
5758(if (not (fboundp 'wholenump))
5759 (defalias 'wholenump 'natnump))
5760;;;_ > remove-overlays if necessary
5761(if (not (fboundp 'remove-overlays))
5762 (defun remove-overlays (&optional beg end name val)
5763 "Clear BEG and END of overlays whose property NAME has value VAL.
5764Overlays might be moved and/or split.
5765BEG and END default respectively to the beginning and end of buffer."
5766 (unless beg (setq beg (point-min)))
5767 (unless end (setq end (point-max)))
5768 (if (< end beg)
5769 (setq beg (prog1 end (setq end beg))))
5770 (save-excursion
5771 (dolist (o (overlays-in beg end))
5772 (when (eq (overlay-get o name) val)
5773 ;; Either push this overlay outside beg...end
5774 ;; or split it to exclude beg...end
5775 ;; or delete it entirely (if it is contained in beg...end).
5776 (if (< (overlay-start o) beg)
5777 (if (> (overlay-end o) end)
5778 (progn
5779 (move-overlay (copy-overlay o)
5780 (overlay-start o) beg)
5781 (move-overlay o end (overlay-end o)))
5782 (move-overlay o (overlay-start o) beg))
5783 (if (> (overlay-end o) end)
5784 (move-overlay o end (overlay-end o))
5785 (delete-overlay o)))))))
5786 )
5787;;;_ > copy-overlay if necessary - xemacs ~ 21.4
5788(if (not (fboundp 'copy-overlay))
5789 (defun copy-overlay (o)
5790 "Return a copy of overlay O."
5791 (let ((o1 (make-overlay (overlay-start o) (overlay-end o)
5792 ;; FIXME: there's no easy way to find the
5793 ;; insertion-type of the two markers.
5794 (overlay-buffer o)))
5795 (props (overlay-properties o)))
5796 (while props
5797 (overlay-put o1 (pop props) (pop props)))
5798 o1)))
5799;;;_ > add-to-invisibility-spec if necessary - xemacs ~ 21.4
5800(if (not (fboundp 'add-to-invisibility-spec))
5801 (defun add-to-invisibility-spec (element)
5802 "Add ELEMENT to `buffer-invisibility-spec'.
5803See documentation for `buffer-invisibility-spec' for the kind of elements
5804that can be added."
5805 (if (eq buffer-invisibility-spec t)
5806 (setq buffer-invisibility-spec (list t)))
5807 (setq buffer-invisibility-spec
5808 (cons element buffer-invisibility-spec))))
5809;;;_ > remove-from-invisibility-spec if necessary - xemacs ~ 21.4
5810(if (not (fboundp 'remove-from-invisibility-spec))
5811 (defun remove-from-invisibility-spec (element)
5812 "Remove ELEMENT from `buffer-invisibility-spec'."
5813 (if (consp buffer-invisibility-spec)
5814 (setq buffer-invisibility-spec (delete element
5815 buffer-invisibility-spec)))))
5816;;;_ > move-beginning-of-line if necessary - older emacs, xemacs
5817(if (not (fboundp 'move-beginning-of-line))
5818 (defun move-beginning-of-line (arg)
5819 "Move point to beginning of current line as displayed.
5820\(This disregards invisible newlines such as those
5821which are part of the text that an image rests on.)
5822
5823With argument ARG not nil or 1, move forward ARG - 1 lines first.
5824If point reaches the beginning or end of buffer, it stops there.
4034b0e2 5825To ignore intangibility, bind `inhibit-point-motion-hooks' to t."
96b83743
EZ
5826 (interactive "p")
5827 (or arg (setq arg 1))
5828 (if (/= arg 1)
5829 (condition-case nil (line-move (1- arg)) (error nil)))
5830
8570ce80
SM
5831 ;; Move to beginning-of-line, ignoring fields and invisibles.
5832 (skip-chars-backward "^\n")
5833 (while (and (not (bobp)) (line-move-invisible-p (1- (point))))
5834 (goto-char (if (featurep 'xemacs)
5835 (previous-property-change (point))
5836 (previous-char-property-change (point))))
5837 (skip-chars-backward "^\n"))
5838 (vertical-motion 0))
96b83743
EZ
5839)
5840;;;_ > move-end-of-line if necessary - older emacs, xemacs
5841(if (not (fboundp 'move-end-of-line))
5842 (defun move-end-of-line (arg)
5843 "Move point to end of current line as displayed.
5844\(This disregards invisible newlines such as those
5845which are part of the text that an image rests on.)
5846
5847With argument ARG not nil or 1, move forward ARG - 1 lines first.
5848If point reaches the beginning or end of buffer, it stops there.
4034b0e2 5849To ignore intangibility, bind `inhibit-point-motion-hooks' to t."
96b83743
EZ
5850 (interactive "p")
5851 (or arg (setq arg 1))
8570ce80 5852 (let (done)
96b83743
EZ
5853 (while (not done)
5854 (let ((newpos
5855 (save-excursion
5856 (let ((goal-column 0))
5857 (and (condition-case nil
5858 (or (line-move arg) t)
5859 (error nil))
5860 (not (bobp))
5861 (progn
8570ce80
SM
5862 (while (and (not (bobp))
5863 (line-move-invisible-p (1- (point))))
5864 (goto-char
5865 (previous-char-property-change (point))))
96b83743
EZ
5866 (backward-char 1)))
5867 (point)))))
5868 (goto-char newpos)
5869 (if (and (> (point) newpos)
5870 (eq (preceding-char) ?\n))
5871 (backward-char 1)
5872 (if (and (> (point) newpos) (not (eobp))
5873 (not (eq (following-char) ?\n)))
5874 ;; If we skipped something intangible
5875 ;; and now we're not really at eol,
5876 ;; keep going.
5877 (setq arg 1)
8570ce80 5878 (setq done t)))))))
96b83743
EZ
5879 )
5880;;;_ > line-move-invisible-p if necessary
5881(if (not (fboundp 'line-move-invisible-p))
5882 (defun line-move-invisible-p (pos)
5883 "Return non-nil if the character after POS is currently invisible."
5884 (let ((prop
5885 (get-char-property pos 'invisible)))
5886 (if (eq buffer-invisibility-spec t)
5887 prop
5888 (or (memq prop buffer-invisibility-spec)
5889 (assq prop buffer-invisibility-spec))))))
5890
5891
5892;;;_ #10 Unfinished
fd5359c6
MR
5893;;;_ > allout-bullet-isearch (&optional bullet)
5894(defun allout-bullet-isearch (&optional bullet)
9179616f 5895 "Isearch \(regexp) for topic with bullet BULLET."
c567ac01
RS
5896 (interactive)
5897 (if (not bullet)
5898 (setq bullet (solicit-char-in-string
5899 "ISearch for topic with bullet: "
fd5359c6 5900 (regexp-sans-escapes allout-bullets-string))))
353e2ef2 5901
c567ac01
RS
5902 (let ((isearch-regexp t)
5903 (isearch-string (concat "^"
fd5359c6 5904 allout-header-prefix
c567ac01
RS
5905 "[ \t]*"
5906 bullet)))
5907 (isearch-repeat 'forward)
5908 (isearch-mode t)))
96b83743
EZ
5909
5910;;;_ #11 Provide
5911(provide 'allout)
1977b8f6
RS
5912
5913;;;_* Local emacs vars.
31468dcb
SM
5914;; The following `allout-layout' local variable setting:
5915;; - closes all topics from the first topic to just before the third-to-last,
5916;; - shows the children of the third to last (config vars)
5917;; - and the second to last (code section),
5918;; - and closes the last topic (this local-variables section).
5919;;Local variables:
5920;;allout-layout: (0 : -1 -1 0)
5921;;End:
5922
5923;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
6a05d05f 5924;;; allout.el ends here