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