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