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