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