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