1 ;;; allout.el --- extensive outline mode for use alone and with other modes
3 ;; Copyright (C) 1992, 1993, 1994, 2001, 2002, 2003, 2004,
4 ;; 2005 Free Software Foundation, Inc.
6 ;; Author: Ken Manheimer <ken dot manheimer at gmail dot com>
7 ;; Maintainer: Ken Manheimer <ken dot manheimer at gmail dot com>
8 ;; Created: Dec 1991 - first release to usenet
10 ;; Keywords: outlines wp languages
12 ;; This file is part of GNU Emacs.
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)
19 ;; GNU Emacs is distributed in the hope that it will be useful,
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.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
31 ;; Allout outline mode provides extensive outline formatting and
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.)
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
48 ;; - configurable per-file initial exposure settings
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.)
53 ;; - automatic topic-number maintenance
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
61 ;; The outline menubar additions provide quick reference to many of
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.
66 ;; See the docstring of the variables `allout-layout' and
67 ;; `allout-auto-activation' for details on automatic activation of
68 ;; `allout-mode' as a minor mode. (It has changed since allout
69 ;; 3.x, for those of you that depend on the old method.)
71 ;; Note - the lines beginning with `;;;_' are outline topic headers.
72 ;; Just `ESC-x eval-current-buffer' to give it a whirl.
74 ;; ken manheimer (ken dot manheimer at gmail dot com)
82 ;;;_* Dependency autoloads
83 (eval-when-compile (progn (require 'pgg
)
85 (fset 'allout-real-isearch-abort
86 (symbol-function 'isearch-abort
))
88 (autoload 'pgg-gpg-symmetric-key-p
"pgg-gpg"
89 "True if decoded armor MESSAGE-KEYS has symmetric encryption indicator.")
91 ;;;_* USER CUSTOMIZATION VARIABLES:
93 "Extensive outline mode for use alone and with other modes."
97 ;;;_ + Layout, Mode, and Topic Header Configuration
99 ;;;_ = allout-auto-activation
100 (defcustom allout-auto-activation nil
101 "*Regulates auto-activation modality of allout outlines - see `allout-init'.
103 Setq-default by `allout-init' to regulate whether or not allout
104 outline mode is automatically activated when the buffer-specific
105 variable `allout-layout' is non-nil, and whether or not the layout
106 dictated by `allout-layout' should be imposed on mode activation.
108 With value t, auto-mode-activation and auto-layout are enabled.
109 \(This also depends on `allout-find-file-hook' being installed in
110 `find-file-hook', which is also done by `allout-init'.)
112 With value `ask', auto-mode-activation is enabled, and endorsement for
113 performing auto-layout is asked of the user each time.
115 With value `activate', only auto-mode-activation is enabled,
118 With value nil, neither auto-mode-activation nor auto-layout are
121 See the docstring for `allout-init' for the proper interface to
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
))
129 (defvar allout-layout nil
130 "*Layout specification and provisional mode trigger for allout outlines.
134 A list value specifies a default layout for the current buffer, to be
135 applied upon activation of `allout-mode'. Any non-nil value will
136 automatically trigger `allout-mode' \(provided `allout-init' has been called
137 to enable this behavior).
139 See the docstring for `allout-init' for details on setting up for
140 auto-mode-activation, and for `allout-expose-topic' for the format of
141 the layout specification.
143 You can associate a particular outline layout with a file by setting
144 this var via the file's local variables. For example, the following
145 lines at the bottom of an Emacs Lisp file:
148 ;;;allout-layout: \(0 : -1 -1 0)
151 will, modulo the above-mentioned conditions, cause the mode to be
152 activated when the file is visited, followed by the equivalent of
153 `\(allout-expose-topic 0 : -1 -1 0)'. \(This is the layout used for
154 the allout.el, itself.)
156 Also, allout's mode-specific provisions will make topic prefixes default
157 to the comment-start string, if any, of the language of the file. This
158 is 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
162 "*If non-nil, show entire body when exposing a topic, rather than
166 (make-variable-buffer-local 'allout-show-bodies
)
168 ;;;_ = allout-header-prefix
169 (defcustom allout-header-prefix
"."
170 "*Leading string which helps distinguish topic headers.
172 Outline topic header lines are identified by a leading topic
173 header prefix, which mostly have the value of this var at their front.
174 \(Level 1 topics are exceptions. They consist of only a single
175 character, which is typically set to the `allout-primary-bullet'. Many
176 outlines start at level 2 to avoid this discrepancy."
179 (make-variable-buffer-local 'allout-header-prefix
)
180 ;;;_ = allout-primary-bullet
181 (defcustom allout-primary-bullet
"*"
182 "Bullet used for top-level outline topics.
184 Outline topic header lines are identified by a leading topic header
185 prefix, which is concluded by bullets that includes the value of this
186 var and the respective allout-*-bullets-string vars.
188 The value of an asterisk (`*') provides for backwards compatibility
189 with the original Emacs outline mode. See `allout-plain-bullets-string'
190 and `allout-distinctive-bullets-string' for the range of available
194 (make-variable-buffer-local 'allout-primary-bullet
)
195 ;;;_ = allout-plain-bullets-string
196 (defcustom allout-plain-bullets-string
".,"
197 "*The bullets normally used in outline topic prefixes.
199 See `allout-distinctive-bullets-string' for the other kind of
202 DO NOT include the close-square-bracket, `]', as a bullet.
204 Outline mode has to be reactivated in order for changes to the value
205 of this var to take effect."
208 (make-variable-buffer-local 'allout-plain-bullets-string
)
209 ;;;_ = allout-distinctive-bullets-string
210 (defcustom allout-distinctive-bullets-string
"*+-=>()[{}&!?#%\"X@$~_\\:;^"
211 "*Persistent outline header bullets used to distinguish special topics.
213 These bullets are used to distinguish topics from the run-of-the-mill
214 ones. They are not used in the standard topic headers created by
215 the topic-opening, shifting, and rebulleting \(eg, on topic shift,
216 topic paste, blanket rebulleting) routines, but are offered among the
217 choices for rebulleting. They are not altered by the above automatic
218 rebulleting, so they can be used to characterize topics, eg:
221 `\(' parenthetic comment \(with a matching close paren inside)
222 `[' meta-note \(with a matching close ] inside)
228 ... for example. (`#' typically has a special meaning to the software,
229 according to the value of `allout-numbered-bullet'.)
231 See `allout-plain-bullets-string' for the selection of
234 You must run `set-allout-regexp' in order for outline mode to
235 reconcile to changes of this value.
237 DO NOT include the close-square-bracket, `]', on either of the bullet
241 (make-variable-buffer-local 'allout-distinctive-bullets-string
)
243 ;;;_ = allout-use-mode-specific-leader
244 (defcustom allout-use-mode-specific-leader t
245 "*When non-nil, use mode-specific topic-header prefixes.
247 Allout outline mode will use the mode-specific `allout-mode-leaders'
248 and/or comment-start string, if any, to lead the topic prefix string,
249 so topic headers look like comments in the programming language.
251 String values are used as they stand.
253 Value t means to first check for assoc value in `allout-mode-leaders'
254 alist, then use comment-start string, if any, then use default \(`.').
255 \(See note about use of comment-start strings, below.)
257 Set to the symbol for either of `allout-mode-leaders' or
258 `comment-start' to use only one of them, respectively.
260 Value nil means to always use the default \(`.').
262 comment-start strings that do not end in spaces are tripled, and an
263 `_' underscore is tacked on the end, to distinguish them from regular
264 comment strings. comment-start strings that do end in spaces are not
265 tripled, but an underscore is substituted for the space. [This
266 presumes that the space is for appearance, not comment syntax. You
267 can use `allout-mode-leaders' to override this behavior, when
269 :type
'(choice (const t
) (const nil
) string
270 (const allout-mode-leaders
)
271 (const comment-start
))
273 ;;;_ = allout-mode-leaders
274 (defvar allout-mode-leaders
'()
275 "Specific allout-prefix leading strings per major modes.
277 Entries will be used instead or in lieu of mode-specific
278 comment-start strings. See also `allout-use-mode-specific-leader'.
280 If you're constructing a string that will comment-out outline
281 structuring so it can be included in program code, append an extra
282 character, like an \"_\" underscore, to distinguish the lead string
283 from regular comments that start at bol.")
285 ;;;_ = allout-old-style-prefixes
286 (defcustom allout-old-style-prefixes nil
287 "*When non-nil, use only old-and-crusty `outline-mode' `*' topic prefixes.
289 Non-nil restricts the topic creation and modification
290 functions to asterix-padded prefixes, so they look exactly
291 like the original Emacs-outline style prefixes.
293 Whatever the setting of this variable, both old and new style prefixes
294 are always respected by the topic maneuvering functions."
297 (make-variable-buffer-local 'allout-old-style-prefixes
)
298 ;;;_ = allout-stylish-prefixes - alternating bullets
299 (defcustom allout-stylish-prefixes t
300 "*Do fancy stuff with topic prefix bullets according to level, etc.
302 Non-nil enables topic creation, modification, and repositioning
303 functions to vary the topic bullet char (the char that marks the topic
304 depth) just preceding the start of the topic text) according to level.
305 Otherwise, only asterisks (`*') and distinctive bullets are used.
307 This is how an outline can look (but sans indentation) with stylish
312 . + One level 3 subtopic
313 . . One level 4 subtopic
314 . . A second 4 subtopic
315 . + Another level 3 subtopic
316 . #1 A numbered level 4 subtopic
318 . ! Another level 4 subtopic with a different distinctive bullet
319 . #4 And another numbered level 4 subtopic
321 This would be an outline with stylish prefixes inhibited (but the
322 numbered and other distinctive bullets retained):
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
332 . ! Another level 4 subtopic with a different distinctive bullet
333 . #4 And another numbered level 4 subtopic
335 Stylish and constant prefixes (as well as old-style prefixes) are
336 always respected by the topic maneuvering functions, regardless of
337 this variable setting.
339 The setting of this var is not relevant when `allout-old-style-prefixes'
343 (make-variable-buffer-local 'allout-stylish-prefixes
)
345 ;;;_ = allout-numbered-bullet
346 (defcustom allout-numbered-bullet
"#"
347 "*String designating bullet of topics that have auto-numbering; nil for none.
349 Topics having this bullet have automatic maintenance of a sibling
350 sequence-number tacked on, just after the bullet. Conventionally set
351 to \"#\", you can set it to a bullet of your choice. A nil value
352 disables numbering maintenance."
353 :type
'(choice (const nil
) string
)
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'.
360 Set this var to the bullet you want to use for file cross-references."
361 :type
'(choice (const nil
) string
)
363 ;;;_ = allout-presentation-padding
364 (defcustom allout-presentation-padding
2
365 "*Presentation-format white-space padding factor, for greater indent."
369 (make-variable-buffer-local 'allout-presentation-padding
)
371 ;;;_ = allout-abbreviate-flattened-numbering
372 (defcustom allout-abbreviate-flattened-numbering nil
373 "*If non-nil, `allout-flatten-exposed-to-buffer' abbreviates topic
374 numbers to minimal amount with some context. Otherwise, entire
375 numbers are always used."
379 ;;;_ + LaTeX formatting
380 ;;;_ - allout-number-pages
381 (defcustom allout-number-pages nil
382 "*Non-nil turns on page numbering for LaTeX formatting of an outline."
385 ;;;_ - allout-label-style
386 (defcustom allout-label-style
"\\large\\bf"
387 "*Font and size of labels for LaTeX formatting of an outline."
390 ;;;_ - allout-head-line-style
391 (defcustom allout-head-line-style
"\\large\\sl "
392 "*Font and size of entries for LaTeX formatting of an outline."
395 ;;;_ - allout-body-line-style
396 (defcustom allout-body-line-style
" "
397 "*Font and size of entries for LaTeX formatting of an outline."
400 ;;;_ - allout-title-style
401 (defcustom allout-title-style
"\\Large\\bf"
402 "*Font and size of titles for LaTeX formatting of an outline."
406 (defcustom allout-title
'(or buffer-file-name
(buffer-name))
407 "*Expression to be evaluated to determine the title for LaTeX
411 ;;;_ - allout-line-skip
412 (defcustom allout-line-skip
".05cm"
413 "*Space between lines for LaTeX formatting of an outline."
417 (defcustom allout-indent
".3cm"
418 "*LaTeX formatted depth-indent spacing."
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
)
428 ;;;_ = allout-passphrase-verifier-handling
429 (defcustom allout-passphrase-verifier-handling t
430 "*Enable use of symmetric encryption passphrase verifier if non-nil.
432 See the docstring for the `allout-enable-file-variable-adjustment'
433 variable for details about allout ajustment of file variables."
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:
441 always - always show reminder when prompting
442 needed - show reminder on passphrase entry failure
443 disabled - never present or adjust reminder
445 See the docstring for the `allout-enable-file-variable-adjustment'
446 variable for details about allout ajustment of file variables."
447 :type
'(choice (const always
)
451 (make-variable-buffer-local 'allout-passphrase-hint-handling
)
452 ;;;_ = allout-encrypt-unencrypted-on-saves
453 (defcustom allout-encrypt-unencrypted-on-saves
'except-current
454 "*When saving, should topics pending encryption be encrypted?
456 The idea is to prevent file-system exposure of any un-encrypted stuff, and
457 mostly covers both deliberate file writes and auto-saves.
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
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
469 passphrase in the middle of editing for, eg, autosaves.
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.
473 For practical reasons, auto-saves always use the 'except-current policy
474 when auto-encryption is enabled. \(Otherwise, spurious passphrase prompts
475 and unavoidable timing collisions are too disruptive.) If security for a
476 file requires that even the current topic is never auto-saved in the clear,
477 disable auto-saves for that file."
479 :type
'(choice (const :tag
"Yes" t
)
480 (const :tag
"All except current topic" except-current
)
481 (const :tag
"No" nil
))
483 (make-variable-buffer-local 'allout-encrypt-unencrypted-on-saves
)
485 ;;;_ + Miscellaneous customization
487 ;;;_ = allout-command-prefix
488 (defcustom allout-command-prefix
"\C-c"
489 "*Key sequence to be used as prefix for outline mode command key bindings."
493 ;;;_ = allout-keybindings-list
494 ;;; You have to reactivate allout-mode - `(allout-mode t)' - to
495 ;;; institute changes to this var.
496 (defvar allout-keybindings-list
()
497 "*List of `allout-mode' key / function bindings, for `allout-mode-map'.
499 String or vector key will be prefaced with `allout-command-prefix',
500 unless optional third, non-nil element is present.")
501 (setq allout-keybindings-list
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
)
510 ("\C-e" allout-end-of-entry
)
512 ("\C-i" allout-show-children
)
513 ("\C-s" allout-show-current-subtree
)
514 ("\C-h" allout-hide-current-subtree
)
515 ("h" allout-hide-current-subtree
)
516 ("\C-o" allout-show-current-entry
)
517 ("!" allout-show-all
)
518 ("x" allout-toggle-current-subtree-encryption
)
519 ; Alteration commands:
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
)
533 ; Miscellaneous commands:
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
)))
541 ;;;_ = allout-isearch-dynamic-expose
542 (defcustom allout-isearch-dynamic-expose t
543 "*Non-nil enable dynamic exposure of hidden incremental-search
544 targets as they're encountered."
547 (make-variable-buffer-local 'allout-isearch-dynamic-expose
)
549 ;;;_ = allout-use-hanging-indents
550 (defcustom allout-use-hanging-indents t
551 "*If non-nil, topic body text auto-indent defaults to indent of the header.
552 Ie, it is indented to be just past the header prefix. This is
553 relevant mostly for use with indented-text-mode, or other situations
554 where auto-fill occurs.
556 \[This feature no longer depends in any way on the `filladapt.el'
557 lisp-archive package.\]"
560 (make-variable-buffer-local 'allout-use-hanging-indents
)
562 ;;;_ = allout-reindent-bodies
563 (defcustom allout-reindent-bodies
(if allout-use-hanging-indents
565 "*Non-nil enables auto-adjust of topic body hanging indent with depth shifts.
567 When active, topic body lines that are indented even with or beyond
568 their topic header are reindented to correspond with depth shifts of
571 A value of t enables reindent in non-programming-code buffers, ie
572 those that do not have the variable `comment-start' set. A value of
573 `force' enables reindent whether or not `comment-start' is set."
574 :type
'(choice (const nil
) (const t
) (const text
) (const force
))
577 (make-variable-buffer-local 'allout-reindent-bodies
)
579 ;;;_ = allout-enable-file-variable-adjustment
580 (defcustom allout-enable-file-variable-adjustment t
581 "*If non-nil, some allout outline actions edit Emacs local file var text.
583 This can range from changes to existing entries, addition of new ones,
584 and creation of a new local variables section when necessary.
586 Emacs file variables adjustments are also inhibited if `enable-local-variables'
589 Operations potentially causing edits include allout encryption routines.
590 For details, see `allout-toggle-current-subtree-encryption's docstring."
593 (make-variable-buffer-local 'allout-enable-file-variable-adjustment
)
595 ;;;_* CODE - no user customizations below.
597 ;;;_ #1 Internal Outline Formatting and Configuration
599 ;;;_ = allout-version
600 (defvar allout-version
"2.1"
601 "Version of currently loaded outline package. \(allout.el)")
602 ;;;_ > allout-version
603 (defun allout-version (&optional here
)
604 "Return string describing the loaded outline version."
606 (let ((msg (concat "Allout Outline Mode v " allout-version
)))
607 (if here
(insert msg
))
610 ;;;_ : Mode activation (defined here because it's referenced early)
612 (defvar allout-mode nil
"Allout outline mode minor-mode flag.")
613 (make-variable-buffer-local 'allout-mode
)
614 ;;;_ : Topic header format
616 (defvar allout-regexp
""
617 "*Regular expression to match the beginning of a heading line.
619 Any line whose beginning matches this regexp is considered a
620 heading. This var is set according to the user configuration vars
621 by `set-allout-regexp'.")
622 (make-variable-buffer-local 'allout-regexp
)
623 ;;;_ = allout-bullets-string
624 (defvar allout-bullets-string
""
625 "A string dictating the valid set of outline topic bullets.
627 This var should *not* be set by the user - it is set by `set-allout-regexp',
628 and is produced from the elements of `allout-plain-bullets-string'
629 and `allout-distinctive-bullets-string'.")
630 (make-variable-buffer-local 'allout-bullets-string
)
631 ;;;_ = allout-bullets-string-len
632 (defvar allout-bullets-string-len
0
633 "Length of current buffers' `allout-plain-bullets-string'.")
634 (make-variable-buffer-local 'allout-bullets-string-len
)
635 ;;;_ = allout-line-boundary-regexp
636 (defvar allout-line-boundary-regexp
()
637 "`allout-regexp' with outline style beginning-of-line anchor.
639 \(Ie, C-j, *or* C-m, for prefixes of hidden topics). This is properly
640 set when `allout-regexp' is produced by `set-allout-regexp', so
641 that (match-beginning 2) and (match-end 2) delimit the prefix.")
642 (make-variable-buffer-local 'allout-line-boundary-regexp
)
643 ;;;_ = allout-bob-regexp
644 (defvar allout-bob-regexp
()
645 "Like `allout-line-boundary-regexp', for headers at beginning of buffer.
646 \(match-beginning 2) and \(match-end 2) delimit the prefix.")
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
)
654 "Length of `allout-plain-bullets-string', updated by `set-allout-regexp'.")
655 (make-variable-buffer-local 'allout-plain-bullets-string-len
)
658 ;;;_ X allout-reset-header-lead (header-lead)
659 (defun allout-reset-header-lead (header-lead)
660 "*Reset the leading string used to identify topic headers."
661 (interactive "sNew lead string: ")
662 (setq allout-header-prefix header-lead
)
663 (setq allout-header-subtraction
(1- (length allout-header-prefix
)))
665 ;;;_ X allout-lead-with-comment-string (header-lead)
666 (defun allout-lead-with-comment-string (&optional header-lead
)
667 "*Set the topic-header leading string to specified string.
669 Useful when for encapsulating outline structure in programming
670 language comments. Returns the leading string."
673 (if (not (stringp header-lead
))
674 (setq header-lead
(read-string
675 "String prefix for topic headers: ")))
676 (setq allout-reindent-bodies nil
)
677 (allout-reset-header-lead header-lead
)
679 ;;;_ > allout-infer-header-lead ()
680 (defun allout-infer-header-lead ()
681 "Determine appropriate `allout-header-prefix'.
683 Works according to settings of:
686 `allout-header-prefix' (default)
687 `allout-use-mode-specific-leader'
688 and `allout-mode-leaders'.
690 Apply this via \(re)activation of `allout-mode', rather than
691 invoking it directly."
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
698 allout-use-mode-specific-leader
699 ;; Oops - garbled value, equate with effect of 't:
703 ((not use-leader
) nil
)
704 ;; Use the explicitly designated leader:
705 ((stringp use-leader
) use-leader
)
706 (t (or (and (memq use-leader
'(t allout-mode-leaders
))
707 ;; Get it from outline mode leaders?
708 (cdr (assq major-mode allout-mode-leaders
)))
709 ;; ... didn't get from allout-mode-leaders...
710 (and (memq use-leader
'(t comment-start
))
712 ;; Use comment-start, maybe tripled, and with
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:
725 (if (string= leader allout-header-prefix
)
726 nil
; no change, nothing to do.
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'.
733 Depends on default setting of `allout-reindent-bodies' \(which see)
734 and presence of setting for `comment-start', to tell whether the
735 file is programming code."
736 (if (and allout-reindent-bodies
738 (not (eq 'force allout-reindent-bodies
)))
739 (setq allout-reindent-bodies nil
)))
740 ;;;_ > set-allout-regexp ()
741 (defun set-allout-regexp ()
742 "Generate proper topic-header regexp form for outline functions.
744 Works with respect to `allout-plain-bullets-string' and
745 `allout-distinctive-bullets-string'."
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
))
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
))
764 (setq allout-bullets-string
765 (concat allout-bullets-string
767 ; Single dash would denote a
768 ; sequence, repeated denotes
770 ((eq cur-char ?-
) "--")
771 ; literal close-square-bracket
772 ; doesn't work right in the
774 ((eq cur-char ?\
]) "")
775 (t (regexp-quote (char-to-string cur-char
))))))
776 (setq index
(1+ index
)))
777 (setq strings
(cdr strings
)))
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 "\\(\\"
786 allout-bullets-string
788 allout-primary-bullet
790 (setq allout-line-boundary-regexp
791 (concat "\\([\n\r]\\)\\(" allout-regexp
"\\)"))
792 (setq allout-bob-regexp
793 (concat "\\(\\`\\)\\(" allout-regexp
"\\)"))
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
)
800 "Produce keymap for use as allout-mode-map, from KEYMAP-LIST.
802 Built on top of optional BASE-MAP, or empty sparse map if none specified.
803 See doc string for allout-keybindings-list for format of binding list."
804 (let ((map (or base-map
(make-sparse-keymap)))
805 (pref (list allout-command-prefix
)))
808 (let ((add-pref (null (cdr (cdr cell
))))
809 (key-suff (list (car cell
))))
812 (apply 'concat
(if add-pref
813 (append pref key-suff
)
815 (car (cdr cell
)))))))
818 ;;;_ = allout-prior-bindings - being deprecated.
819 (defvar allout-prior-bindings nil
820 "Variable for use in V18, with allout-added-bindings, for
821 resurrecting, on mode deactivation, bindings that existed before
822 activation. 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
826 resurrecting, on mode deactivation, bindings that existed before
827 activation. Being deprecated.")
829 (defvar allout-mode-exposure-menu
)
830 (defvar allout-mode-editing-menu
)
831 (defvar allout-mode-navigation-menu
)
832 (defvar allout-mode-misc-menu
)
833 (defun produce-allout-mode-menubar-entries ()
835 (easy-menu-define allout-mode-exposure-menu
837 "Allout outline exposure menu."
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
]
845 ["Show All" allout-show-all t
]))
846 (easy-menu-define allout-mode-editing-menu
848 "Allout outline editing menu."
850 ["Open Sibling" allout-open-sibtopic t
]
851 ["Open Subtopic" allout-open-subtopic t
]
852 ["Open Supertopic" allout-open-supertopic t
]
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
]
858 ["Number Siblings" allout-number-siblings t
]
860 ["Toggle Topic Encryption"
861 allout-toggle-current-subtree-encryption
862 (> (allout-current-depth) 1)]))
863 (easy-menu-define allout-mode-navigation-menu
865 "Allout outline navigation menu."
867 ["Next Visible Heading" allout-next-visible-heading t
]
868 ["Previous Visible Heading"
869 allout-previous-visible-heading t
]
871 ["Up Level" allout-up-current-level t
]
872 ["Forward Current Level" allout-forward-current-level t
]
873 ["Backward Current Level"
874 allout-backward-current-level t
]
876 ["Beginning of Entry"
877 allout-beginning-of-current-entry t
]
878 ["End of Entry" allout-end-of-entry t
]
879 ["End of Subtree" allout-end-of-current-subtree t
]))
880 (easy-menu-define allout-mode-misc-menu
882 "Allout outlines miscellaneous bindings."
884 ["Version" allout-version t
]
886 ["Duplicate Exposed" allout-copy-exposed-to-buffer t
]
887 ["Duplicate Exposed, numbered"
888 allout-flatten-exposed-to-buffer t
]
889 ["Duplicate Exposed, indented"
890 allout-indented-exposed-to-buffer t
]
892 ["Set Header Lead" allout-reset-header-lead t
]
893 ["Set New Exposure" allout-expose-topic t
])))
894 ;;;_ : Mode-Specific Variable Maintenance Utilities
895 ;;;_ = allout-mode-prior-settings
896 (defvar allout-mode-prior-settings nil
897 "Internal `allout-mode' use; settings to be resumed on mode deactivation.")
898 (make-variable-buffer-local 'allout-mode-prior-settings
)
899 ;;;_ > allout-resumptions (name &optional value)
900 (defun allout-resumptions (name &optional value
)
902 "Registers or resumes settings over `allout-mode' activation/deactivation.
904 First arg is NAME of variable affected. Optional second arg is list
905 containing allout-mode-specific VALUE to be imposed on named
906 variable, and to be registered. \(It's a list so you can specify
907 registrations of null values.) If no value is specified, the
908 registered value is returned (encapsulated in the list, so the caller
909 can distinguish nil vs no value), and the registration is popped
912 (let ((on-list (assq name allout-mode-prior-settings
))
913 prior-capsule
; By `capsule' i mean a list
914 ; containing a value, so we can
915 ; distinguish nil from no value.
923 nil
; Already preserved prior value - don't mess with it.
924 ;; Register the old value, or nil if previously unbound:
925 (setq allout-mode-prior-settings
927 (if (boundp name
) (list (symbol-value name
))))
928 allout-mode-prior-settings
)))
929 ; And impose the new value, locally:
930 (progn (make-local-variable name
)
931 (set name
(car value
))))
936 ;; Oops, not registered - leave it be:
939 ;; Some registration:
941 (setq prior-capsule
(car (cdr on-list
)))
943 (set name
(car prior-capsule
)) ; Some prior value - reestablish it.
944 (makunbound name
)) ; Previously unbound - demolish var.
945 ; Remove registration:
947 (while allout-mode-prior-settings
948 (if (not (eq (car allout-mode-prior-settings
)
951 (cons (car allout-mode-prior-settings
)
953 (setq allout-mode-prior-settings
954 (cdr allout-mode-prior-settings
)))
955 (setq allout-mode-prior-settings rebuild
)))))
957 ;;;_ : Mode-specific incidentals
958 ;;;_ = allout-pre-was-isearching nil
959 (defvar allout-pre-was-isearching nil
960 "Cue for isearch-dynamic-exposure mechanism, implemented in
961 allout-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
965 "Cue for isearch-dynamic-exposure tracking, used by
966 `allout-isearch-expose'.")
967 (make-variable-buffer-local 'allout-isearch-prior-pos
)
968 ;;;_ = allout-isearch-did-quit
969 (defvar allout-isearch-did-quit nil
970 "Distinguishes isearch conclusion and cancellation.
972 Maintained by allout-isearch-abort \(which is wrapped around the real
973 isearch-abort), and monitored by allout-isearch-expose for action.")
974 (make-variable-buffer-local 'allout-isearch-did-quit
)
975 ;;;_ > allout-unprotected (expr)
976 (defmacro allout-unprotected
(expr)
977 "Enable internal outline operations to alter read-only text."
978 `(let ((was-inhibit-r-o inhibit-read-only
))
981 (setq inhibit-read-only t
)
983 (setq inhibit-read-only was-inhibit-r-o
)
987 ;;;_ = allout-undo-aggregation
988 (defvar allout-undo-aggregation
30
989 "Amount of successive self-insert actions to bunch together per undo.
991 This is purely a kludge variable, regulating the compensation for a bug in
992 the way that `before-change-functions' and undo interact.")
993 (make-variable-buffer-local 'allout-undo-aggregation
)
994 ;;;_ = file-var-bug hack
995 (defvar allout-v18
/19-file-var-hack nil
996 "Horrible hack used to prevent invalid multiple triggering of outline
997 mode from prop-line file-var activation. Used by `allout-mode' function
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
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
1007 already associated with a file.
1009 It consists of an encrypted random string useful only to verify that a
1010 passphrase entered by the user is effective for decryption. The passphrase
1011 itself is \*not* recorded in the file anywhere, and the encrypted contents
1012 are random binary characters to avoid exposing greater susceptibility to
1015 The verifier string is retained as an Emacs file variable, as well as in
1016 the emacs buffer state, if file variable adjustments are enabled. See
1017 `allout-enable-file-variable-adjustment' for details about that.")
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.
1023 See the description of `allout-passphrase-hint-handling' for details about how
1024 the reminder is deployed.
1026 The hint is retained as an Emacs file variable, as well as in the emacs buffer
1027 state, if file variable adjustments are enabled. See
1028 `allout-enable-file-variable-adjustment' for details about that.")
1029 (make-variable-buffer-local 'allout-passphrase-hint-string
)
1030 (setq-default allout-passphrase-hint-string
"")
1031 ;;;_ = allout-after-save-decrypt
1032 (defvar allout-after-save-decrypt nil
1033 "Internal variable, is nil or has the value of two points:
1035 - the location of a topic to be decrypted after saving is done
1036 - where to situate the cursor after the decryption is performed
1038 This is used to decrypt the topic that was currently being edited, if it
1039 was encrypted automatically as part of a file write or autosave.")
1040 (make-variable-buffer-local 'allout-after-save-decrypt
)
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."
1047 ;;;_ > allout-write-file-hook-handler ()
1048 (defun allout-write-file-hook-handler ()
1049 "Implement `allout-encrypt-unencrypted-on-saves' policy for file writes."
1051 (if (or (not (allout-mode-p))
1052 (not (boundp 'allout-encrypt-unencrypted-on-saves
))
1053 (not allout-encrypt-unencrypted-on-saves
))
1055 (let ((except-mark (and (equal allout-encrypt-unencrypted-on-saves
1058 (if (save-excursion (goto-char (point-min))
1059 (allout-next-topic-pending-encryption except-mark
))
1061 (message "auto-encrypting pending topics")
1063 (condition-case failure
1064 (setq allout-after-save-decrypt
1065 (allout-encrypt-decrypted except-mark
))
1068 "allout-write-file-hook-handler suppressing error %s"
1073 ;;;_ > allout-auto-save-hook-handler ()
1074 (defun allout-auto-save-hook-handler ()
1075 "Implement `allout-encrypt-unencrypted-on-saves' policy for auto save."
1077 (if (and (allout-mode-p) allout-encrypt-unencrypted-on-saves
)
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.
1085 Ie, if it was pending encryption and contained the point in its body before
1088 We use values stored in `allout-after-save-decrypt' to locate the topic
1089 and 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
))
1094 (goto-char (car allout-after-save-decrypt
))
1095 (let ((was-modified (buffer-modified-p)))
1096 (allout-toggle-subtree-encryption)
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
))
1103 ;;;_ #2 Mode activation
1104 ;;;_ = allout-explicitly-deactivated
1105 (defvar allout-explicitly-deactivated nil
1106 "If t, `allout-mode's last deactivation was deliberate.
1107 So `allout-post-command-business' should not reactivate it...")
1108 (make-variable-buffer-local 'allout-explicitly-deactivated
)
1109 ;;;_ > allout-init (&optional mode)
1110 (defun allout-init (&optional mode
)
1111 "Prime `allout-mode' to enable/disable auto-activation, wrt `allout-layout'.
1113 MODE is one of the following symbols:
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
1118 confirmation for layout operation solicited from user each time;
1119 - `report', just report and return the current auto-activation state;
1120 - anything else \(eg, t) for auto-activation and auto-layout, without
1121 any confirmation check.
1123 Use this function to setup your Emacs session for automatic activation
1124 of allout outline mode, contingent to the buffer-specific setting of
1125 the `allout-layout' variable. (See `allout-layout' and
1126 `allout-expose-topic' docstrings for more details on auto layout).
1128 `allout-init' works by setting up (or removing) the `allout-mode'
1129 find-file-hook, and giving `allout-auto-activation' a suitable
1132 To prime your Emacs session for full auto-outline operation, include
1133 the following two lines in your Emacs init file:
1143 (concat "Select outline auto setup mode "
1144 "(empty for report, ? for options) ")
1145 '(("nil")("full")("activate")("deactivate")
1146 ("ask") ("report") (""))
1149 (if (string= mode
"")
1151 (setq mode
(intern-soft mode
)))))
1153 ;; convenience aliases, for consistent ref to respective vars:
1154 ((hook 'allout-find-file-hook
)
1155 (find-file-hook-var-name (if (boundp 'find-file-hook
)
1158 (curr-mode 'allout-auto-activation
))
1161 (set find-file-hook-var-name
1162 (delq hook
(symbol-value find-file-hook-var-name
)))
1164 (message "Allout outline mode auto-activation inhibited.")))
1166 (if (not (memq hook
(symbol-value find-file-hook-var-name
)))
1168 ;; Just punt and use the reports from each of the modes:
1169 (allout-init (symbol-value curr-mode
))))
1170 (t (add-hook find-file-hook-var-name hook
)
1171 (set curr-mode
; `set', not `setq'!
1172 (cond ((eq mode
'activate
)
1174 "Outline mode auto-activation enabled.")
1177 ;; Return the current mode setting:
1181 (concat "Outline mode auto-activation and "
1182 "-layout \(upon confirmation) enabled."))
1185 "Outline mode auto-activation and -layout enabled.")
1188 ;;;_ > allout-setup-menubar ()
1189 (defun allout-setup-menubar ()
1190 "Populate the current buffer's menubar with `allout-mode' stuff."
1191 (let ((menus (list allout-mode-exposure-menu
1192 allout-mode-editing-menu
1193 allout-mode-navigation-menu
1194 allout-mode-misc-menu
))
1197 (setq cur
(car menus
)
1199 (easy-menu-add cur
))))
1200 ;;;_ > allout-mode (&optional toggle)
1203 (defun allout-mode (&optional toggle
)
1205 "Toggle minor mode for controlling exposure and editing of text outlines.
1207 Optional arg forces mode to re-initialize iff arg is positive num or
1208 symbol. Allout outline mode always runs as a minor mode.
1210 Allout outline mode provides extensive outline oriented formatting and
1211 manipulation. It enables structural editing of outlines, as well as
1212 navigation and exposure. It also is specifically aimed at
1213 accommodating syntax-sensitive text like programming languages. \(For
1214 an example, see the allout code itself, which is organized as an allout
1217 In addition to outline navigation and exposure, allout includes:
1219 - topic-oriented repositioning, promotion/demotion, cut, and paste
1220 - integral outline exposure-layout
1221 - incremental search with dynamic exposure and reconcealment of hidden text
1222 - automatic topic-number maintenance
1223 - easy topic encryption and decryption
1224 - \"Hot-spot\" operation, for single-keystroke maneuvering and
1225 exposure control. \(See the allout-mode docstring.)
1227 and many other features.
1229 Below is a description of the bindings, and then explanation of
1230 special `allout-mode' features and terminology. See also the outline
1231 menubar additions for quick reference to many of the features, and see
1232 the docstring of the function `allout-init' for instructions on
1233 priming your emacs session for automatic activation of `allout-mode'.
1236 The bindings are dictated by the `allout-keybindings-list' and
1237 `allout-command-prefix' variables.
1239 Navigation: Exposure Control:
1240 ---------- ----------------
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
1249 Topic Header Production:
1250 -----------------------
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.
1255 Topic Level and Prefix Adjustment:
1256 ---------------------------------
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
1261 \\[allout-rebullet-topic] allout-rebullet-topic Reconcile bullets of topic and its offspring
1262 - distinctive bullets are not changed, others
1263 alternated according to nesting depth.
1264 \\[allout-number-siblings] allout-number-siblings Number bullets of topic and siblings - the
1265 offspring are not affected. With repeat
1266 count, revoke numbering.
1268 Topic-oriented Killing and Yanking:
1269 ----------------------------------
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
1273 depth of heading if yanking into bare topic
1274 heading (ie, prefix sans text).
1275 \\[allout-yank-pop] allout-yank-pop Is to allout-yank as yank-pop is to yank
1279 M-x outlineify-sticky Activate outline mode for current buffer,
1280 and establish a default file-var setting
1281 for `allout-layout'.
1282 \\[allout-mark-topic] allout-mark-topic
1283 \\[allout-copy-exposed-to-buffer] allout-copy-exposed-to-buffer
1284 Duplicate outline, sans concealed text, to
1285 buffer with name derived from derived from that
1286 of current buffer - \"*BUFFERNAME exposed*\".
1287 \\[allout-flatten-exposed-to-buffer] allout-flatten-exposed-to-buffer
1288 Like above 'copy-exposed', but convert topic
1289 prefixes to section.subsection... numeric
1291 ESC ESC (allout-init t) Setup Emacs session for outline mode
1296 Outline mode supports easily togglable gpg encryption of topics, with
1297 niceties like support for symmetric and key-pair modes, passphrase timeout,
1298 passphrase consistency checking, user-provided hinting for symmetric key
1299 mode, and auto-encryption of topics pending encryption on save. The aim is
1300 to enable reliable topic privacy while preventing accidents like neglected
1301 encryption, encryption with a mistaken passphrase, forgetting which
1302 passphrase was used, and other practical pitfalls.
1304 See `allout-toggle-current-subtree-encryption' function docstring and
1305 `allout-encrypt-unencrypted-on-saves' customization variable for details.
1309 Hot-spot operation provides a means for easy, single-keystroke outline
1310 navigation and exposure control.
1313 When the text cursor is positioned directly on the bullet character of
1314 a topic, regular characters (a to z) invoke the commands of the
1315 corresponding allout-mode keymap control chars. For example, \"f\"
1316 would invoke the command typically bound to \"C-c C-f\"
1317 \(\\[allout-forward-current-level] `allout-forward-current-level').
1319 Thus, by positioning the cursor on a topic bullet, you can execute
1320 the outline navigation and manipulation commands with a single
1321 keystroke. Non-literal chars never get this special translation, so
1322 you can use them to get away from the hot-spot, and back to normal
1325 Note that the command `allout-beginning-of-current-entry' \(\\[allout-beginning-of-current-entry]\)
1326 will move to the hot-spot when the cursor is already located at the
1327 beginning of the current entry, so you can simply hit \\[allout-beginning-of-current-entry]
1328 twice in a row to get to the hot-spot.
1332 Topic hierarchy constituents - TOPICS and SUBTOPICS:
1334 TOPIC: A basic, coherent component of an Emacs outline. It can
1335 contain other topics, and it can be subsumed by other topics,
1337 The visible topic most immediately containing the cursor.
1338 DEPTH: The degree of nesting of a topic; it increases with
1339 containment. Also called the:
1340 LEVEL: The same as DEPTH.
1343 The topics that contain a topic.
1344 PARENT: A topic's immediate ancestor. It has a depth one less than
1347 The topics contained by a topic;
1349 An immediate offspring of a topic;
1351 The immediate offspring of a topic.
1353 Topics having the same parent and depth.
1355 Topic text constituents:
1357 HEADER: The first line of a topic, include the topic PREFIX and header
1359 PREFIX: 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.
1365 The relative length of the PREFIX determines the nesting depth
1368 The string at the beginning of a topic prefix, normally a `.'.
1369 It can be customized by changing the setting of
1370 `allout-header-prefix' and then reinitializing `allout-mode'.
1372 By setting the prefix-lead to the comment-string of a
1373 programming language, you can embed outline structuring in
1374 program code without interfering with the language processing
1375 of that code. See `allout-use-mode-specific-leader'
1376 docstring for more detail.
1378 Spaces or asterisks which separate the prefix-lead and the
1379 bullet, according to the depth of the topic.
1380 BULLET: A character at the end of the topic prefix, it must be one of
1381 the characters listed on `allout-plain-bullets-string' or
1382 `allout-distinctive-bullets-string'. (See the documentation
1383 for these variables for more details.) The default choice of
1384 bullet when generating varies in a cycle with the depth of the
1386 ENTRY: The text contained in a topic before any offspring.
1387 BODY: Same as ENTRY.
1391 The state of a topic which determines the on-screen visibility
1392 of its offspring and contained text.
1394 Topics and entry text whose display is inhibited. Contiguous
1395 units of concealed text is represented by `...' ellipses.
1396 (Ref the `selective-display' var.)
1398 Concealed topics are effectively collapsed within an ancestor.
1399 CLOSED: A topic whose immediate offspring and body-text is concealed.
1400 OPEN: A topic that is not closed, though its offspring or body may be."
1404 (let* ((active (and (not (equal major-mode
'outline
))
1406 ; Massage universal-arg `toggle' val:
1408 (or (and (listp toggle
)(car toggle
))
1410 ; Activation specifically demanded?
1411 (explicit-activation (and toggle
1412 (or (symbolp toggle
)
1413 (and (wholenump toggle
)
1414 (not (zerop toggle
))))))
1415 ;; allout-mode already called once during this complex command?
1416 (same-complex-command (eq allout-v18
/19-file-var-hack
1417 (car command-history
)))
1418 (write-file-hook-var-name (if (boundp 'write-file-functions
)
1419 'write-file-functions
1420 'local-write-file-hooks
))
1424 ; See comments below re v19.18,.19 bug.
1425 (setq allout-v18
/19-file-var-hack
(car command-history
))
1429 ;; Provision for v19.18, 19.19 bug -
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
1434 ((and same-complex-command
; Still in same complex command
1435 ; as last time `allout-mode' invoked.
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.
1443 ((and (not explicit-activation
)
1445 ; Activation not explicitly
1446 ; requested, and either in
1447 ; active state or *de*activation
1448 ; specifically requested:
1449 (setq allout-explicitly-deactivated t
)
1450 (if (string-match "^18\." emacs-version
)
1451 ; Revoke those keys that remain
1453 (let ((curr-loc (current-local-map)))
1456 (if (eq (lookup-key curr-loc
(car 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
)))
1464 (if allout-old-style-prefixes
1466 (allout-resumptions 'allout-primary-bullet
)
1467 (allout-resumptions 'allout-old-style-prefixes
)))
1468 (allout-resumptions 'selective-display
)
1469 (if (and (boundp 'before-change-functions
) before-change-functions
)
1470 (allout-resumptions 'before-change-functions
))
1471 (set write-file-hook-var-name
1472 (delq 'allout-write-file-hook-handler
1473 (symbol-value write-file-hook-var-name
)))
1474 (setq auto-save-hook
1475 (delq 'allout-auto-save-hook-handler
1477 (allout-resumptions 'paragraph-start
)
1478 (allout-resumptions 'paragraph-separate
)
1479 (allout-resumptions (if (string-match "^18" emacs-version
)
1481 'auto-fill-function
))
1482 (allout-resumptions 'allout-former-auto-filler
)
1483 (setq allout-mode nil
))
1487 (setq allout-explicitly-deactivated nil
)
1488 (if allout-old-style-prefixes
1489 (progn ; Inhibit all the fancy formatting:
1490 (allout-resumptions 'allout-primary-bullet
'("*"))
1491 (allout-resumptions 'allout-old-style-prefixes
'(()))))
1493 (allout-infer-header-lead)
1494 (allout-infer-body-reindent)
1498 ; Produce map from current version
1499 ; of allout-keybindings-list:
1500 (if (boundp 'minor-mode-map-alist
)
1502 (progn ; V19, and maybe lucid and
1503 ; epoch, minor-mode key bindings:
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
)
1508 ; Include on minor-mode-map-alist,
1509 ; if not already there:
1510 (if (not (member '(allout-mode . allout-mode-map
)
1511 minor-mode-map-alist
))
1512 (setq minor-mode-map-alist
1513 (cons '(allout-mode . allout-mode-map
)
1514 minor-mode-map-alist
))))
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)))
1524 (use-local-map (produce-allout-mode-map allout-keybindings-list
1525 (current-local-map)))
1528 ; selective-display is the
1529 ; emacs conditional exposure
1531 (allout-resumptions 'selective-display
'(t))
1532 (add-hook 'pre-command-hook
'allout-pre-command-business
)
1533 (add-hook 'post-command-hook
'allout-post-command-business
)
1534 (add-hook write-file-hook-var-name
'allout-write-file-hook-handler
)
1535 (add-hook 'auto-save-hook
'allout-auto-save-hook-handler
)
1536 ; Custom auto-fill func, to support
1537 ; respect for topic headline,
1538 ; hanging-indents, etc:
1539 (let* ((fill-func-var (if (string-match "^18" emacs-version
)
1541 'auto-fill-function
))
1542 (fill-func (symbol-value fill-func-var
)))
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)))
1547 ;; Paragraphs are broken by topic headlines.
1548 (make-local-variable 'paragraph-start
)
1549 (allout-resumptions 'paragraph-start
1550 (list (concat paragraph-start
"\\|^\\("
1551 allout-regexp
"\\)")))
1552 (make-local-variable 'paragraph-separate
)
1553 (allout-resumptions 'paragraph-separate
1554 (list (concat paragraph-separate
"\\|^\\("
1555 allout-regexp
"\\)")))
1557 (or (assq 'allout-mode minor-mode-alist
)
1558 (setq minor-mode-alist
1559 (cons '(allout-mode " Allout") minor-mode-alist
)))
1561 (allout-setup-menubar)
1566 (if (and allout-isearch-dynamic-expose
1567 (not (fboundp 'allout-real-isearch-abort
)))
1568 (allout-enwrap-isearch))
1570 (run-hooks 'allout-mode-hook
)
1571 (setq allout-mode t
))
1575 (allout-infer-body-reindent))
1579 allout-auto-activation
1580 (listp allout-layout
)
1581 (and (not (eq allout-auto-activation
'activate
))
1582 (if (eq allout-auto-activation
'ask
)
1583 (if (y-or-n-p (format "Expose %s with layout '%s'? "
1587 (message "Skipped %s layout." (buffer-name))
1591 (message "Adjusting '%s' exposure..." (buffer-name))
1593 (allout-this-or-next-heading)
1596 (apply 'allout-expose-topic
(list allout-layout
))
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
)))
1605 ;;;_ > allout-minor-mode
1606 (defalias 'allout-minor-mode
'allout-mode
)
1608 ;;;_ #3 Internal Position State-Tracking - "allout-recent-*" funcs
1609 ;;; All the basic outline functions that directly do string matches to
1610 ;;; evaluate heading prefix location set the variables
1611 ;;; `allout-recent-prefix-beginning' and `allout-recent-prefix-end'
1612 ;;; when successful. Functions starting with `allout-recent-' all
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.
1616 ;;;_ = allout-recent-prefix-beginning
1617 (defvar allout-recent-prefix-beginning
0
1618 "Buffer point of the start of the last topic prefix encountered.")
1619 (make-variable-buffer-local 'allout-recent-prefix-beginning
)
1620 ;;;_ = allout-recent-prefix-end
1621 (defvar allout-recent-prefix-end
0
1622 "Buffer point of the end of the last topic prefix encountered.")
1623 (make-variable-buffer-local 'allout-recent-prefix-end
)
1624 ;;;_ = allout-recent-end-of-subtree
1625 (defvar allout-recent-end-of-subtree
0
1626 "Buffer point last returned by `allout-end-of-current-subtree'.")
1627 (make-variable-buffer-local 'allout-recent-end-of-subtree
)
1628 ;;;_ > allout-prefix-data (beg end)
1629 (defmacro allout-prefix-data
(beg end
)
1630 "Register allout-prefix state data - BEGINNING and END of prefix.
1632 For reference by `allout-recent' funcs. Returns BEGINNING."
1633 `(setq allout-recent-prefix-end
,end
1634 allout-recent-prefix-beginning
,beg
))
1635 ;;;_ > allout-recent-depth ()
1636 (defmacro allout-recent-depth
()
1637 "Return depth of last heading encountered by an outline maneuvering function.
1639 All outline functions which directly do string matches to assess
1640 headings set the variables `allout-recent-prefix-beginning' and
1641 `allout-recent-prefix-end' if successful. This function uses those settings
1642 to return the current depth."
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
()
1649 "Like `allout-recent-depth', but returns text of last encountered prefix.
1651 All outline functions which directly do string matches to assess
1652 headings set the variables `allout-recent-prefix-beginning' and
1653 `allout-recent-prefix-end' if successful. This function uses those settings
1654 to return the current depth."
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.
1661 All outline functions which directly do string matches to assess
1662 headings set the variables `allout-recent-prefix-beginning' and
1663 `allout-recent-prefix-end' if successful. This function uses those settings
1664 to return the current depth of the most recently matched topic."
1665 '(buffer-substring (1- allout-recent-prefix-end
)
1666 allout-recent-prefix-end
))
1670 ;;;_ - Position Assessment
1671 ;;;_ : Location Predicates
1672 ;;;_ > allout-on-current-heading-p ()
1673 (defun allout-on-current-heading-p ()
1674 "Return non-nil if point is on current visible topics' header line.
1676 Actually, returns prefix beginning point."
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 ()
1685 "True if point is located where current topic prefix ends, heading begins."
1686 (and (save-excursion (beginning-of-line)
1687 (looking-at allout-regexp
))
1688 (= (point)(save-excursion (allout-end-of-prefix)(point)))))
1689 ;;;_ > allout-hidden-p ()
1690 (defmacro allout-hidden-p
()
1691 "True if point is in hidden text."
1693 (and (re-search-backward "[\n\r]" () t
)
1694 (= ?
\r (following-char)))))
1695 ;;;_ > allout-visible-p ()
1696 (defmacro allout-visible-p
()
1697 "True if point is not in hidden text."
1699 '(not (allout-hidden-p)))
1700 ;;;_ : Location attributes
1701 ;;;_ > allout-depth ()
1702 (defsubst allout-depth
()
1703 "Like `allout-current-depth', but respects hidden as well as visible topics."
1705 (if (allout-goto-prefix)
1706 (allout-recent-depth)
1708 ;; Oops, no prefix, zero prefix data:
1709 (allout-prefix-data (point)(point))
1710 ;; ... and return 0:
1712 ;;;_ > allout-current-depth ()
1713 (defmacro allout-current-depth
()
1714 "Return nesting depth of visible topic most immediately containing point."
1716 (if (allout-back-to-current-heading)
1718 (- allout-recent-prefix-end
1719 allout-recent-prefix-beginning
1720 allout-header-subtraction
))
1722 ;;;_ > allout-get-current-prefix ()
1723 (defun allout-get-current-prefix ()
1724 "Topic prefix of the current topic."
1726 (if (allout-goto-prefix)
1727 (allout-recent-prefix))))
1728 ;;;_ > allout-get-bullet ()
1729 (defun allout-get-bullet ()
1730 "Return bullet of containing topic (visible or not)."
1732 (and (allout-goto-prefix)
1733 (allout-recent-bullet))))
1734 ;;;_ > allout-current-bullet ()
1735 (defun allout-current-bullet ()
1736 "Return bullet of current (visible) topic heading, or none if none found."
1739 (allout-back-to-current-heading)
1740 (buffer-substring (- allout-recent-prefix-end
1)
1741 allout-recent-prefix-end
))
1742 ;; Quick and dirty provision, ostensibly for missing bullet:
1743 ('args-out-of-range nil
))
1745 ;;;_ > allout-get-prefix-bullet (prefix)
1746 (defun allout-get-prefix-bullet (prefix)
1747 "Return the bullet of the header prefix string PREFIX."
1748 ;; Doesn't make sense if we're old-style prefixes, but this just
1749 ;; oughtn't be called then, so forget about it...
1750 (if (string-match allout-regexp prefix
)
1751 (substring prefix
(1- (match-end 0)) (match-end 0))))
1752 ;;;_ > allout-sibling-index (&optional depth)
1753 (defun allout-sibling-index (&optional depth
)
1754 "Item number of this prospective topic among its siblings.
1756 If optional arg DEPTH is greater than current depth, then we're
1757 opening a new level, and return 0.
1759 If less than this depth, ascend to that depth and count..."
1762 (cond ((and depth
(<= depth
0) 0))
1763 ((or (not depth
) (= depth
(allout-depth)))
1765 (while (allout-previous-sibling (allout-recent-depth) nil
)
1766 (setq index
(1+ index
)))
1768 ((< depth
(allout-recent-depth))
1769 (allout-ascend-to-depth depth
)
1770 (allout-sibling-index))
1772 ;;;_ > allout-topic-flat-index ()
1773 (defun allout-topic-flat-index ()
1774 "Return a list indicating point's numeric section.subsect.subsubsect...
1775 Outermost is first."
1776 (let* ((depth (allout-depth))
1777 (next-index (allout-sibling-index depth
))
1779 (while (> next-index
0)
1780 (setq rev-sibls
(cons next-index rev-sibls
))
1781 (setq depth
(1- depth
))
1782 (setq next-index
(allout-sibling-index depth
)))
1786 ;;;_ - Navigation macros
1787 ;;;_ > allout-next-heading ()
1788 (defsubst allout-next-heading
()
1789 "Move to the heading for the topic \(possibly invisible) before this one.
1791 Returns the location of the heading, or nil if none found."
1793 (if (and (bobp) (not (eobp)))
1796 (if (re-search-forward allout-line-boundary-regexp nil
0)
1797 (allout-prefix-data ; Got valid location state - set vars:
1798 (goto-char (or (match-beginning 2)
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 ()
1803 "Position cursor on current or next heading."
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
()
1809 "Move to the prior \(possibly invisible) heading line.
1811 Return the location of the beginning of the heading, or nil if not found."
1815 (allout-goto-prefix)
1817 ;; searches are unbounded and return nil if failed:
1818 (or (re-search-backward allout-line-boundary-regexp nil
0)
1819 (looking-at allout-bob-regexp
))
1820 (progn ; Got valid location state - set vars:
1822 (goto-char (or (match-beginning 2)
1823 allout-recent-prefix-beginning
))
1824 (or (match-end 2) allout-recent-prefix-end
))))))
1826 ;;;_ - Subtree Charting
1827 ;;;_ " These routines either produce or assess charts, which are
1828 ;;; nested lists of the locations of topics within a subtree.
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
1833 ;;; for assessment or adjustment of the subtree, without redundant
1834 ;;; traversal of the structure.
1836 ;;;_ > allout-chart-subtree (&optional levels orig-depth prev-depth)
1837 (defun allout-chart-subtree (&optional levels orig-depth prev-depth
)
1838 "Produce a location \"chart\" of subtopics of the containing topic.
1840 Optional argument LEVELS specifies the depth \(relative to start
1841 depth) for the chart. Subsequent optional args are not for public
1844 Point is left at the end of the subtree.
1846 Charts are used to capture outline structure, so that outline-altering
1847 routines need assess the structure only once, and then use the chart
1848 for their elaborate manipulations.
1850 Topics are entered in the chart so the last one is at the car.
1851 The entry for each topic consists of an integer indicating the point
1852 at the beginning of the topic. Charts for offspring consists of a
1853 list containing, recursively, the charts for the respective subtopics.
1854 The chart for a topics' offspring precedes the entry for the topic
1857 The other function parameters are for internal recursion, and should
1858 not be specified by external callers. ORIG-DEPTH is depth of topic at
1859 starting point, and PREV-DEPTH is depth of prior topic."
1861 (let ((original (not orig-depth
)) ; `orig-depth' set only in recursion.
1864 (if original
; Just starting?
1865 ; Register initial settings and
1866 ; position to first offspring:
1867 (progn (setq orig-depth
(allout-depth))
1868 (or prev-depth
(setq prev-depth
(1+ orig-depth
)))
1869 (allout-next-heading)))
1871 ;; Loop over the current levels' siblings. Besides being more
1872 ;; efficient than tail-recursing over a level, it avoids exceeding
1873 ;; the typically quite constrained Emacs max-lisp-eval-depth.
1875 ;; Probably would speed things up to implement loop-based stack
1876 ;; operation rather than recursing for lower levels. Bah.
1878 (while (and (not (eobp))
1879 ; Still within original topic?
1880 (< orig-depth
(setq curr-depth
(allout-recent-depth)))
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:
1886 (or (allout-next-sibling curr-depth
)
1887 ;; or no more siblings - proceed to
1888 ;; next heading at lesser depth:
1889 (while (and (<= curr-depth
1890 (allout-recent-depth))
1891 (allout-next-heading))))
1892 (allout-next-heading)))
1894 ((and (< prev-depth curr-depth
)
1897 ;; Recurse on deeper level of curr topic:
1899 (cons (allout-chart-subtree (and levels
1904 ;; ... then continue with this one.
1907 ;; ... else nil if we've ascended back to prev-depth.
1911 (if original
; We're at the last sibling on
1912 ; the original level. Position
1914 (progn (and (not (eobp)) (forward-char -
1))
1915 (and (memq (preceding-char) '(?
\n ?
\r))
1916 (memq (aref (buffer-substring (max 1 (- (point) 3))
1921 (setq allout-recent-end-of-subtree
(point))))
1923 chart
; (nreverse chart) not necessary,
1924 ; and maybe not preferable.
1926 ;;;_ > allout-chart-siblings (&optional start end)
1927 (defun allout-chart-siblings (&optional start end
)
1928 "Produce a list of locations of this and succeeding sibling topics.
1929 Effectively a top-level chart of siblings. See `allout-chart-subtree'
1930 for an explanation of charts."
1932 (if (allout-goto-prefix)
1933 (let ((chart (list (point))))
1934 (while (allout-next-sibling)
1935 (setq chart
(cons (point) chart
)))
1936 (if chart
(setq chart
(nreverse chart
)))))))
1937 ;;;_ > allout-chart-to-reveal (chart depth)
1938 (defun allout-chart-to-reveal (chart depth
)
1940 "Return a flat list of hidden points in subtree CHART, up to DEPTH.
1942 Note that point can be left at any of the points on chart, or at the
1946 (while (and (or (eq depth t
) (> depth
0))
1948 (setq here
(car chart
))
1950 (let ((further (allout-chart-to-reveal here
(or (eq depth t
)
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
)))
1957 (if (= (preceding-char) ?
\r)
1958 (setq result
(cons here result
)))
1959 (setq chart
(cdr chart
))))
1961 ;;;_ X allout-chart-spec (chart spec &optional exposing)
1962 ;; (defun allout-chart-spec (chart spec &optional exposing)
1963 ;; "Not yet \(if ever) implemented.
1965 ;; Produce exposure directives given topic/subtree CHART and an exposure SPEC.
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.
1974 ;; The produced list can have two types of entries. Bare numbers
1975 ;; indicate points in the buffer where topic headers that should be
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
1983 ;; - Lists signify the beginning and end points of regions that should
1984 ;; be flagged, and the flag to employ. (For concealment: `\(\?r\)', and
1987 ;; (cond ((listp spec)
1990 ;; (setq spec (cdr spec)))
1994 ;;;_ > allout-goto-prefix ()
1995 (defun allout-goto-prefix ()
1996 "Put point at beginning of immediately containing outline topic.
1998 Goes to most immediate subsequent topic if none immediately containing.
2000 Not sensitive to topic visibility.
2002 Returns the point at the beginning of the prefix, or nil if none."
2005 (while (and (not done
)
2006 (re-search-backward "[\n\r]" nil
1))
2008 (if (looking-at allout-regexp
)
2009 (setq done
(allout-prefix-data (match-beginning 0)
2013 (cond ((looking-at allout-regexp
)
2014 (allout-prefix-data (match-beginning 0)(match-end 0)))
2015 ((allout-next-heading))
2018 ;;;_ > allout-end-of-prefix ()
2019 (defun allout-end-of-prefix (&optional ignore-decorations
)
2020 "Position cursor at beginning of header text.
2022 If optional IGNORE-DECORATIONS is non-nil, put just after bullet,
2023 otherwise skip white space between bullet and ensuing text."
2025 (if (not (allout-goto-prefix))
2027 (let ((match-data (match-data)))
2028 (goto-char (match-end 0))
2029 (if ignore-decorations
2031 (while (looking-at "[0-9]") (forward-char 1))
2032 (if (and (not (eolp)) (looking-at "\\s-")) (forward-char 1)))
2033 (store-match-data match-data
))
2034 ;; Reestablish where we are:
2035 (allout-current-depth)))
2036 ;;;_ > allout-current-bullet-pos ()
2037 (defun allout-current-bullet-pos ()
2038 "Return position of current \(visible) topic's bullet."
2040 (if (not (allout-current-depth))
2042 (1- (match-end 0))))
2043 ;;;_ > allout-back-to-current-heading ()
2044 (defun allout-back-to-current-heading ()
2045 "Move to heading line of current topic, or beginning if already on the line."
2048 (prog1 (or (allout-on-current-heading-p)
2049 (and (re-search-backward (concat "^\\(" allout-regexp
"\\)")
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 ()
2058 "Skip forward to just before the next heading line.
2060 Returns that character position."
2062 (if (re-search-forward allout-line-boundary-regexp nil
'move
)
2063 (prog1 (goto-char (match-beginning 0))
2064 (allout-prefix-data (match-beginning 2)(match-end 2)))))
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.
2069 If optional CURRENT is true (default false), then put point at the end of
2070 the containing visible topic.
2072 Returns the value of point."
2075 (allout-back-to-current-heading)
2076 (allout-goto-prefix))
2077 (let ((level (allout-recent-depth)))
2078 (allout-next-heading)
2079 (while (and (not (eobp))
2080 (> (allout-recent-depth) level
))
2081 (allout-next-heading))
2082 (and (not (eobp)) (forward-char -
1))
2083 (and (memq (preceding-char) '(?
\n ?
\r))
2084 (memq (aref (buffer-substring (max 1 (- (point) 3)) (point)) 1)
2087 (setq allout-recent-end-of-subtree
(point))))
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.
2092 Returns the value of point."
2094 (allout-end-of-subtree t
))
2095 ;;;_ > allout-beginning-of-current-entry ()
2096 (defun allout-beginning-of-current-entry ()
2097 "When not already there, position point at beginning of current topic header.
2099 If already there, move cursor to bullet for hot-spot operation.
2100 \(See `allout-mode' doc string for details on hot-spot operation.)"
2102 (let ((start-point (point)))
2103 (allout-end-of-prefix)
2104 (if (and (interactive-p)
2105 (= (point) start-point
))
2106 (goto-char (allout-current-bullet-pos)))))
2107 ;;;_ > allout-end-of-entry ()
2108 (defun allout-end-of-entry ()
2109 "Position the point at the end of the current topics' entry."
2111 (prog1 (allout-pre-next-preface)
2112 (if (and (not (bobp))(looking-at "^$"))
2113 (forward-char -
1))))
2114 ;;;_ > allout-end-of-current-heading ()
2115 (defun allout-end-of-current-heading ()
2117 (allout-beginning-of-current-entry)
2118 (re-search-forward "[\n\r]" nil t
)
2120 (defalias 'allout-end-of-heading
'allout-end-of-current-heading
)
2121 ;;;_ > allout-get-body-text ()
2122 (defun allout-get-body-text ()
2123 "Return the unmangled body text of the topic immediately containing point."
2125 (allout-end-of-prefix)
2126 (if (not (re-search-forward "[\n\r]" nil t
))
2129 (let ((pre-body (point)))
2132 (allout-end-of-entry)
2133 (if (not (= pre-body
(point)))
2134 (buffer-substring-no-properties (1+ pre-body
) (point))))
2141 ;;;_ > allout-ascend-to-depth (depth)
2142 (defun allout-ascend-to-depth (depth)
2143 "Ascend to depth DEPTH, returning depth if successful, nil if not."
2144 (if (and (> depth
0)(<= depth
(allout-depth)))
2145 (let ((last-good (point)))
2146 (while (and (< depth
(allout-depth))
2147 (setq last-good
(point))
2148 (allout-beginning-of-level)
2149 (allout-previous-heading)))
2150 (if (= (allout-recent-depth) depth
)
2151 (progn (goto-char allout-recent-prefix-beginning
)
2153 (goto-char last-good
)
2155 (if (interactive-p) (allout-end-of-prefix))))
2156 ;;;_ > allout-ascend ()
2157 (defun allout-ascend ()
2158 "Ascend one level, returning t if successful, nil if not."
2160 (if (allout-beginning-of-level)
2161 (allout-previous-heading))
2162 (if (interactive-p) (allout-end-of-prefix))))
2163 ;;;_ > allout-descend-to-depth (depth)
2164 (defun allout-descend-to-depth (depth)
2165 "Descend to depth DEPTH within current topic.
2167 Returning depth if successful, nil if not."
2168 (let ((start-point (point))
2169 (start-depth (allout-depth)))
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
))
2178 (goto-char start-point
)
2181 ;;;_ > allout-up-current-level (arg &optional dont-complain)
2182 (defun allout-up-current-level (arg &optional dont-complain
)
2183 "Move out ARG levels from current visible topic.
2185 Positions on heading line of containing topic. Error if unable to
2186 ascend that far, or nil if unable to ascend but optional arg
2187 DONT-COMPLAIN is non-nil."
2189 (allout-back-to-current-heading)
2190 (let ((present-level (allout-recent-depth))
2194 ;; Loop for iterating arg:
2195 (while (and (> (allout-recent-depth) 1)
2199 (setq last-good
(point))
2200 ;; Loop for going back over current or greater depth:
2201 (while (and (not (< (allout-recent-depth) present-level
))
2202 (or (allout-previous-visible-heading 1)
2203 (not (setq failed present-level
)))))
2204 (setq present-level
(allout-current-depth))
2205 (setq arg
(- arg
1)))
2208 (progn (goto-char last-good
)
2209 (if (interactive-p) (allout-end-of-prefix))
2210 (if (not dont-complain
)
2211 (error "Can't ascend past outermost level")
2212 (if (interactive-p) (allout-end-of-prefix))
2214 (if (interactive-p) (allout-end-of-prefix))
2215 allout-recent-prefix-beginning
)))
2218 ;;;_ > allout-next-sibling (&optional depth backward)
2219 (defun allout-next-sibling (&optional depth backward
)
2220 "Like `allout-forward-current-level', but respects invisible topics.
2222 Traverse at optional DEPTH, or current depth if none specified.
2224 Go backward if optional arg BACKWARD is non-nil.
2226 Return depth if successful, nil otherwise."
2228 (if (and backward
(bobp))
2230 (let ((start-depth (or depth
(allout-depth)))
2231 (start-point (point))
2233 (while (and (not (if backward
(bobp) (eobp)))
2234 (if backward
(allout-previous-heading)
2235 (allout-next-heading))
2236 (> (setq last-depth
(allout-recent-depth)) start-depth
)))
2237 (if (and (not (eobp))
2238 (and (> (or last-depth
(allout-depth)) 0)
2239 (= (allout-recent-depth) start-depth
)))
2240 allout-recent-prefix-beginning
2241 (goto-char start-point
)
2242 (if depth
(allout-depth) start-depth
)
2244 ;;;_ > allout-previous-sibling (&optional depth backward)
2245 (defun allout-previous-sibling (&optional depth backward
)
2246 "Like `allout-forward-current-level' backwards, respecting invisible topics.
2248 Optional DEPTH specifies depth to traverse, default current depth.
2250 Optional BACKWARD reverses direction.
2252 Return depth if successful, nil otherwise."
2253 (allout-next-sibling depth
(not backward
))
2255 ;;;_ > allout-snug-back ()
2256 (defun allout-snug-back ()
2257 "Position cursor at end of previous topic.
2259 Presumes point is at the start of a topic prefix."
2260 (if (or (bobp) (eobp))
2263 (if (or (bobp) (not (memq (preceding-char) '(?
\n ?
\r))))
2266 (if (or (bobp) (not (memq (preceding-char) '(?
\n ?
\r))))
2269 ;;;_ > allout-beginning-of-level ()
2270 (defun allout-beginning-of-level ()
2271 "Go back to the first sibling at this level, visible or not."
2272 (allout-end-of-level 'backward
))
2273 ;;;_ > allout-end-of-level (&optional backward)
2274 (defun allout-end-of-level (&optional backward
)
2275 "Go to the last sibling at this level, visible or not."
2277 (let ((depth (allout-depth)))
2278 (while (allout-previous-sibling depth nil
))
2279 (prog1 (allout-recent-depth)
2280 (if (interactive-p) (allout-end-of-prefix)))))
2281 ;;;_ > allout-next-visible-heading (arg)
2282 (defun allout-next-visible-heading (arg)
2283 "Move to the next ARG'th visible heading line, backward if arg is negative.
2285 Move as far as possible in indicated direction \(beginning or end of
2286 buffer) if headings are exhausted."
2289 (let* ((backward (if (< arg
0) (setq arg
(* -
1 arg
))))
2290 (step (if backward -
1 1))
2291 (start-point (point))
2294 (while (> arg
0) ; limit condition
2295 (while (and (not (if backward
(bobp)(eobp))) ; boundary condition
2296 ;; Move, skipping over all those concealed lines:
2297 (< -
1 (forward-line step
))
2298 (not (setq got
(looking-at allout-regexp
)))))
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:
2303 (allout-prefix-data (match-beginning 0) (match-end 0))
2304 (allout-end-of-prefix))
2305 (prev ; Last move wasn't, but prev was:
2306 (allout-prefix-data (match-beginning 0) (match-end 0)))
2307 ((not backward
) (end-of-line) nil
))))
2308 ;;;_ > allout-previous-visible-heading (arg)
2309 (defun allout-previous-visible-heading (arg)
2310 "Move to the previous heading line.
2312 With argument, repeats or can move forward if negative.
2313 A heading line is one that starts with a `*' (or that `allout-regexp'
2316 (allout-next-visible-heading (- arg
)))
2317 ;;;_ > allout-forward-current-level (arg)
2318 (defun allout-forward-current-level (arg)
2319 "Position point at the next heading of the same level.
2321 Takes optional repeat-count, goes backward if count is negative.
2323 Returns resulting position, else nil if none found."
2325 (let ((start-depth (allout-current-depth))
2326 (start-point (point))
2328 (backward (> 0 arg
))
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
)
2337 (while (and (not (if backward
(bobp) (eobp)))
2338 (if backward
(allout-previous-visible-heading 1)
2339 (allout-next-visible-heading 1))
2340 (> (setq last-depth
(allout-recent-depth)) start-depth
)))
2341 (if (and last-depth
(= last-depth start-depth
)
2342 (not (if backward
(bobp) (eobp))))
2343 (setq last-good
(point)
2345 (setq at-boundary t
)))
2346 (if (and (not (eobp))
2348 (and (> (or last-depth
(allout-depth)) 0)
2349 (= (allout-recent-depth) start-depth
)))
2350 allout-recent-prefix-beginning
2351 (goto-char last-good
)
2352 (if (not (interactive-p))
2354 (allout-end-of-prefix)
2355 (error "Hit %s level %d topic, traversed %d of %d requested"
2356 (if backward
"first" "last")
2357 (allout-recent-depth)
2358 (- (abs start-arg
) arg
)
2359 (abs start-arg
))))))
2360 ;;;_ > allout-backward-current-level (arg)
2361 (defun allout-backward-current-level (arg)
2362 "Inverse of `allout-forward-current-level'."
2365 (let ((current-prefix-arg (* -
1 arg
)))
2366 (call-interactively 'allout-forward-current-level
))
2367 (allout-forward-current-level (* -
1 arg
))))
2372 ;;;_ = allout-post-goto-bullet
2373 (defvar allout-post-goto-bullet nil
2374 "Outline internal var, for `allout-pre-command-business' hot-spot operation.
2376 When set, tells post-processing to reposition on topic bullet, and
2377 then unset it. Set by `allout-pre-command-business' when implementing
2378 hot-spot operation, where literal characters typed over a topic bullet
2379 are mapped to the command of the corresponding control-key on the
2380 `allout-mode-map'.")
2381 (make-variable-buffer-local 'allout-post-goto-bullet
)
2382 ;;;_ > allout-post-command-business ()
2383 (defun allout-post-command-business ()
2384 "Outline `post-command-hook' function.
2386 - Implement (and clear) `allout-post-goto-bullet', for hot-spot
2389 - Decrypt topic currently being edited if it was encrypted for a save.
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."
2395 ; Apply any external change func:
2396 (if (not (allout-mode-p)) ; In allout-mode.
2398 (if allout-isearch-dynamic-expose
2399 (allout-isearch-rectification))
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.
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
))
2419 ;; prev contents denote fewer than aggregate-limit
2421 (numberp (setq prev-from
(car prev-cell
)))
2422 (numberp (setq prev-to
(cdr prev-cell
)))
2424 (> allout-undo-aggregation
(- prev-to prev-from
)))
2425 (setq buffer-undo-list
2426 (cons (cons prev-from cur-to
)
2427 (cdr (cdr (cdr buffer-undo-list
))))))))
2429 (if (and (boundp 'allout-after-save-decrypt
)
2430 allout-after-save-decrypt
)
2431 (allout-after-saves-handler))
2433 ;; Implement -post-goto-bullet, if set: (must be after undo business)
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
)))
2439 ;;;_ > allout-pre-command-business ()
2440 (defun allout-pre-command-business ()
2441 "Outline `pre-command-hook' function for outline buffers.
2442 Implements special behavior when cursor is on bullet character.
2444 When the cursor is on the bullet character, self-insert characters are
2445 reinterpreted as the corresponding control-character in the
2446 `allout-mode-map'. The `allout-mode' `post-command-hook' insures that
2447 the cursor which has moved as a result of such reinterpretation is
2448 positioned on the bullet character of the destination topic.
2450 The upshot is that you can get easy, single (ie, unmodified) key
2451 outline maneuvering operations by positioning the cursor on the bullet
2452 char. When in this mode you can use regular cursor-positioning
2453 command/keystrokes to relocate the cursor off of a bullet character to
2454 return to regular interpretation of self-insert characters."
2456 (if (not (allout-mode-p))
2457 ;; Shouldn't be invoked if not in allout-mode, but just in case:
2459 ;; Register isearch status:
2460 (if (and (boundp 'isearch-mode
) isearch-mode
)
2461 (setq allout-pre-was-isearching t
)
2462 (setq allout-pre-was-isearching nil
))
2463 ;; Hot-spot navigation provisions:
2464 (if (and (eq this-command
'self-insert-command
)
2465 (eq (point)(allout-current-bullet-pos)))
2466 (let* ((this-key-num (cond
2467 ((numberp last-command-char
)
2469 ;; Only xemacs has characterp.
2470 ((and (fboundp 'characterp
)
2472 (list last-command-char
)))
2473 (apply 'char-to-int
(list last-command-char
)))
2476 (if (zerop this-key-num
)
2478 ; Map upper-register literals
2479 ; to lower register:
2480 (if (<= 96 this-key-num
)
2481 (setq this-key-num
(- this-key-num
32)))
2482 ; Check if we have a literal:
2483 (if (and (<= 64 this-key-num
)
2484 (>= 96 this-key-num
))
2485 (setq mapped-binding
2486 (lookup-key 'allout-mode-map
2487 (concat allout-command-prefix
2488 (char-to-string (- this-key-num
2491 (setq allout-post-goto-bullet t
2492 this-command mapped-binding
)))))))
2493 ;;;_ > allout-find-file-hook ()
2494 (defun allout-find-file-hook ()
2495 "Activate `allout-mode' when `allout-auto-activation', `allout-layout' non-nil.
2497 See `allout-init' for setup instructions."
2498 (if (and allout-auto-activation
2499 (not (allout-mode-p))
2502 ;;;_ > allout-isearch-rectification
2503 (defun allout-isearch-rectification ()
2504 "Rectify outline exposure before, during, or after isearch.
2506 Called as part of `allout-post-command-business'."
2508 (let ((isearching (and (boundp 'isearch-mode
) isearch-mode
)))
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
))
2515 ;; Not and wasn't isearching:
2516 (t (setq allout-isearch-prior-pos nil
)
2517 (setq allout-isearch-did-quit nil
)))))
2518 ;;;_ = allout-isearch-was-font-lock
2519 (defvar allout-isearch-was-font-lock
2520 (and (boundp 'font-lock-mode
) font-lock-mode
))
2521 ;;;_ > allout-isearch-expose (mode)
2522 (defun allout-isearch-expose (mode)
2523 "MODE is either 'clear, 'start, 'continue, or 'final."
2524 ;; allout-isearch-prior-pos encodes exposure status of prior pos:
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
)
2530 (setq allout-isearch-was-font-lock
(and (boundp 'font-lock-mode
)
2533 (if (eq mode
'final
)
2534 (setq font-lock-mode allout-isearch-was-font-lock
))
2535 (if (and allout-isearch-prior-pos
2536 (listp allout-isearch-prior-pos
))
2537 ;; Conceal prior peek:
2538 (allout-flag-region (car (cdr allout-isearch-prior-pos
))
2539 (car (cdr (cdr allout-isearch-prior-pos
)))
2541 (if (allout-visible-p)
2542 (setq allout-isearch-prior-pos nil
)
2543 (if (not (eq mode
'final
))
2544 (setq allout-isearch-prior-pos
(cons (point) (allout-show-entry)))
2545 (if allout-isearch-did-quit
2547 (setq allout-isearch-prior-pos nil
)
2548 (allout-show-children))))
2549 (setq allout-isearch-did-quit nil
))
2550 ;;;_ > allout-enwrap-isearch ()
2551 (defun allout-enwrap-isearch ()
2552 "Impose `allout-mode' isearch-abort wrapper for dynamic exposure in isearch.
2554 The function checks to ensure that the rebinding is done only once."
2556 (add-hook 'isearch-mode-end-hook
'allout-isearch-rectification
)
2557 (if (fboundp 'allout-real-isearch-abort
)
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'"
2568 (car (cdr (cdr error
))))
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:
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
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
))))
2591 ;;; Prevent unnecessary font-lock while isearching!
2592 (defvar isearch-was-font-locking nil
)
2593 (defun isearch-inhibit-font-lock ()
2594 "Inhibit `font-lock' while isearching - for use on `isearch-mode-hook'."
2595 (if (and (allout-mode-p) (boundp 'font-lock-mode
) font-lock-mode
)
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 ()
2600 "Reenable font-lock after isearching - for use on `isearch-mode-end-hook'."
2601 (if (and (boundp 'font-lock-mode
) font-lock-mode
)
2602 (if (and (allout-mode-p) isearch-was-font-locking
)
2603 (setq isearch-was-font-locking nil
2604 font-lock-mode t
))))
2605 (add-hook 'isearch-mode-end-hook
'isearch-reenable-font-lock
)
2607 ;;;_ - Topic Format Assessment
2608 ;;;_ > allout-solicit-alternate-bullet (depth &optional current-bullet)
2609 (defun allout-solicit-alternate-bullet (depth &optional current-bullet
)
2611 "Prompt for and return a bullet char as an alternative to the current one.
2613 Offer one suitable for current depth DEPTH as default."
2615 (let* ((default-bullet (or (and (stringp current-bullet
) current-bullet
)
2616 (allout-bullet-for-depth depth
)))
2617 (sans-escapes (regexp-sans-escapes allout-bullets-string
))
2620 (goto-char (allout-current-bullet-pos))
2621 (setq choice
(solicit-char-in-string
2622 (format "Select bullet: %s ('%s' default): "
2628 (if (string= choice
"") default-bullet choice
))
2630 ;;;_ > allout-distinctive-bullet (bullet)
2631 (defun allout-distinctive-bullet (bullet)
2632 "True if BULLET is one of those on `allout-distinctive-bullets-string'."
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
)
2636 "True if current header prefix bullet is numbered bullet."
2637 (and allout-numbered-bullet
2638 (string= allout-numbered-bullet
2640 (allout-get-prefix-bullet prefix
)
2641 (allout-get-bullet)))))
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
2648 (allout-get-prefix-bullet prefix
)
2649 (allout-get-bullet)))))
2650 ;;;_ > allout-bullet-for-depth (&optional depth)
2651 (defun allout-bullet-for-depth (&optional depth
)
2652 "Return outline topic bullet suited to optional DEPTH, or current depth."
2653 ;; Find bullet in plain-bullets-string modulo DEPTH.
2654 (if allout-stylish-prefixes
2655 (char-to-string (aref allout-plain-bullets-string
2656 (%
(max 0 (- depth
2))
2657 allout-plain-bullets-string-len
)))
2658 allout-primary-bullet
)
2661 ;;;_ - Topic Production
2662 ;;;_ > allout-make-topic-prefix (&optional prior-bullet
2663 (defun allout-make-topic-prefix (&optional prior-bullet
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.
2674 "Generate a topic prefix suitable for optional arg DEPTH, or current depth.
2676 All the arguments are optional.
2678 PRIOR-BULLET indicates the bullet of the prefix being changed, or
2679 nil if none. This bullet may be preserved (other options
2680 notwithstanding) if it is on the `allout-distinctive-bullets-string',
2683 Second arg NEW indicates that a new topic is being opened after the
2684 topic at point, if non-nil. Default bullet for new topics, eg, may
2685 be set (contingent to other args) to numbered bullets if previous
2686 sibling is one. The implication otherwise is that the current topic
2687 is being adjusted - shifted or rebulleted - and we don't consider
2688 bullet or previous sibling.
2690 Third arg DEPTH forces the topic prefix to that depth, regardless of
2691 the current topics' depth.
2693 If SOLICIT is non-nil, then the choice of bullet is solicited from
2694 user. If it's a character, then that character is offered as the
2695 default, otherwise the one suited to the context \(according to
2696 distinction or depth) is offered. \(This overrides other options,
2697 including, eg, a distinctive PRIOR-BULLET.) If non-nil, then the
2698 context-specific bullet is used.
2700 Fifth arg, NUMBER-CONTROL, matters only if `allout-numbered-bullet'
2701 is non-nil *and* soliciting was not explicitly invoked. Then
2702 NUMBER-CONTROL non-nil forces prefix to either numbered or
2703 denumbered format, depending on the value of the sixth arg, INDEX.
2705 \(Note that NUMBER-CONTROL does *not* apply to level 1 topics. Sorry...)
2707 If NUMBER-CONTROL is non-nil and sixth arg INDEX is non-nil then
2708 the prefix of the topic is forced to be numbered. Non-nil
2709 NUMBER-CONTROL and nil INDEX forces non-numbered format on the
2710 bullet. Non-nil NUMBER-CONTROL and non-nil, non-number INDEX means
2711 that the index for the numbered prefix will be derived, by counting
2712 siblings back to start of level. If INDEX is a number, then that
2713 number is used as the index for the numbered prefix (allowing, eg,
2714 sequential renumbering to not require this function counting back the
2715 index for each successive sibling)."
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
2726 (depth (or depth
(allout-depth)))
2727 (header-lead allout-header-prefix
)
2730 ;; Getting value for bullet char is practically the whole job:
2733 ; Simplest situation - level 1:
2734 ((<= depth
1) (setq header-lead
"") allout-primary-bullet
)
2735 ; Simple, too: all asterisks:
2736 (allout-old-style-prefixes
2737 ;; Cheat - make body the whole thing, null out header-lead and
2739 (setq body
(make-string depth
2740 (string-to-char allout-primary-bullet
)))
2741 (setq header-lead
"")
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.)
2747 ;; Solicitation overrides numbering and other cases:
2748 ((progn (setq body
(make-string (- depth
2) ?\
))
2749 ;; The actual condition:
2751 (let* ((got (allout-solicit-alternate-bullet depth solicit
)))
2752 ;; Gotta check whether we're numbering and got a numbered bullet:
2753 (setq numbering
(and allout-numbered-bullet
2754 (not (and number-control
(not index
)))
2755 (string= got allout-numbered-bullet
)))
2756 ;; Now return what we got, regardless:
2759 ;; Numbering invoked through args:
2760 ((and allout-numbered-bullet number-control
)
2761 (if (setq numbering
(not (setq denumbering
(not index
))))
2762 allout-numbered-bullet
2763 (if (and prior-bullet
2764 (not (string= allout-numbered-bullet
2767 (allout-bullet-for-depth depth
))))
2769 ;;; Neither soliciting nor controlled numbering ;;;
2770 ;;; (may be controlled denumbering, tho) ;;;
2772 ;; Check wrt previous sibling:
2773 ((and new
; only check for new prefixes
2774 (<= depth
(allout-depth))
2775 allout-numbered-bullet
; ... & numbering enabled
2777 (let ((sibling-bullet
2779 ;; Locate correct sibling:
2780 (or (>= depth
(allout-depth))
2781 (allout-ascend-to-depth depth
))
2782 (allout-get-bullet))))
2783 (if (and sibling-bullet
2784 (string= allout-numbered-bullet sibling-bullet
))
2785 (setq numbering sibling-bullet
)))))
2787 ;; Distinctive prior bullet?
2789 (allout-distinctive-bullet prior-bullet
)
2790 ;; Either non-numbered:
2791 (or (not (and allout-numbered-bullet
2792 (string= prior-bullet allout-numbered-bullet
)))
2793 ;; or numbered, and not denumbering:
2794 (setq numbering
(not denumbering
)))
2798 ;; Else, standard bullet per depth:
2799 ((allout-bullet-for-depth depth
)))))
2805 (format "%d" (cond ((and index
(numberp index
)) index
)
2806 (new (1+ (allout-sibling-index depth
)))
2807 ((allout-sibling-index))))))
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.
2814 New topic is situated after current one, unless optional flag BEFORE
2815 is non-nil, or unless current line is complete empty (not even
2816 whitespace), in which case open is done on current line.
2818 If USE_RECENT_BULLET is true, offer to use the bullet of the prior sibling.
2822 - Creation of new topics is with respect to the visible topic
2823 containing the cursor, regardless of intervening concealed ones.
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.
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.
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
2839 having to go to its preceding sibling, and then open forward
2842 (let* ((depth (+ (allout-current-depth) relative-depth
))
2843 (opening-on-blank (if (looking-at "^\$")
2844 (not (setq before nil
))))
2845 ;; bunch o vars set while computing ref-topic
2850 (ref-topic (save-excursion
2851 (cond ((< relative-depth
0)
2852 (allout-ascend-to-depth depth
))
2853 ((>= relative-depth
1) nil
)
2854 (t (allout-back-to-current-heading)))
2855 (setq ref-depth
(allout-recent-depth))
2857 (if (> allout-recent-prefix-end
1)
2858 (allout-recent-bullet)
2860 (setq opening-numbered
2862 (and allout-numbered-bullet
2863 (or (<= relative-depth
0)
2864 (allout-descend-to-depth depth
))
2865 (if (allout-numbered-type-prefix)
2866 allout-numbered-bullet
))))
2867 (setq opening-encrypted
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
))))
2878 (if (not opening-on-blank
)
2879 ; Positioning and vertical
2880 ; padding - only if not
2883 (goto-char ref-topic
)
2884 (setq dbl-space
; Determine double space action:
2885 (or (and (<= relative-depth
0) ; not descending;
2887 ;; at b-o-b or preceded by a blank line?
2888 (or (> 0 (forward-line -
1))
2889 (looking-at "^\\s-*$")
2892 ;; succeeded by a blank line?
2893 (allout-end-of-current-subtree)
2895 (and (= ref-depth
1)
2899 ;; Don't already have following
2900 ;; vertical padding:
2901 (not (allout-pre-next-preface)))))))
2903 ; Position to prior heading,
2904 ; if inserting backwards, and
2905 ; not going outwards:
2906 (if (and before
(>= relative-depth
0))
2907 (progn (allout-back-to-current-heading)
2908 (setq doing-beginning
(bobp))
2910 (allout-previous-heading)))
2911 (if (and before
(bobp))
2912 (allout-unprotected (allout-open-line-not-read-only))))
2914 (if (<= relative-depth
0)
2915 ;; Not going inwards, don't snug up:
2919 (allout-open-line-not-read-only)
2920 (allout-open-line-not-read-only)
2921 (allout-open-line-not-read-only)))
2923 (progn (end-of-line)
2924 (allout-pre-next-preface)
2925 (while (= ?
\r (following-char))
2927 (if (not (looking-at "^$"))
2929 (allout-open-line-not-read-only))))
2930 (allout-end-of-current-subtree)))
2931 ;; Going inwards - double-space if first offspring is,
2932 ;; otherwise snug up.
2933 (end-of-line) ; So we skip any concealed progeny.
2934 (allout-pre-next-preface)
2936 ;; Blank lines between current header body and next
2937 ;; header - get to last substantive (non-white-space)
2939 (re-search-backward "[^ \t\n]" nil t
))
2941 (allout-next-heading)
2942 (if (> (allout-recent-depth) ref-depth
)
2943 ;; This is an offspring.
2944 (progn (forward-line -
1)
2945 (looking-at "^\\s-*$"))))
2946 (progn (forward-line 1)
2948 (allout-open-line-not-read-only))
2951 ;;(if doing-beginning (goto-char doing-beginning))
2953 ;; We insert a newline char rather than using open-line to
2954 ;; avoid rear-stickiness inheritence of read-only property.
2955 (progn (if (and (not (> depth ref-depth
))
2958 (allout-open-line-not-read-only))
2959 (if (> depth ref-depth
)
2961 (allout-open-line-not-read-only))
2964 (allout-open-line-not-read-only))
2966 (allout-unprotected (newline 1))))))
2968 (allout-unprotected (newline 1)))
2969 (if (and (not (eobp))
2973 (insert (concat (allout-make-topic-prefix opening-numbered
2978 ;;(if doing-beginning (save-excursion (newline (if dbl-space 2 1))))
2981 (allout-rebullet-heading (and use_recent_bullet
;;; solicit
2984 nil
;;; number-control
2990 ;;;_ . open-topic contingencies
2991 ;;;_ ; base topic - one from which open was issued
2992 ;;;_ , beginning char
2993 ;;;_ , amount of space before will be used, unless opening in place
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
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."
3007 (if (plist-get (text-properties-at (point)) 'read-only
)
3009 (remove-text-properties (point) (+ 1 (point)) '(read-only nil
)))))
3010 ;;;_ > allout-open-subtopic (arg)
3011 (defun allout-open-subtopic (arg)
3012 "Open new topic header at deeper level than the current one.
3014 Negative universal arg means to open deeper, but place the new topic
3015 prior to the current one."
3017 (allout-open-topic 1 (> 0 arg
) (< 1 arg
)))
3018 ;;;_ > allout-open-sibtopic (arg)
3019 (defun allout-open-sibtopic (arg)
3020 "Open new topic header at same level as the current one.
3022 Positive universal arg means to use the bullet of the prior sibling.
3024 Negative universal arg means to place the new topic prior to the current
3027 (allout-open-topic 0 (> 0 arg
) (not (= 1 arg
))))
3028 ;;;_ > allout-open-supertopic (arg)
3029 (defun allout-open-supertopic (arg)
3030 "Open new topic header at shallower level than the current one.
3032 Negative universal arg means to open shallower, but place the new
3033 topic prior to the current one."
3036 (allout-open-topic -
1 (> 0 arg
) (< 1 arg
)))
3038 ;;;_ - Outline Alteration
3039 ;;;_ : Topic Modification
3040 ;;;_ = allout-former-auto-filler
3041 (defvar allout-former-auto-filler nil
3042 "Name of modal fill function being wrapped by `allout-auto-fill'.")
3043 ;;;_ > allout-auto-fill ()
3044 (defun allout-auto-fill ()
3045 "`allout-mode' autofill function.
3047 Maintains outline hanging topic indentation if
3048 `allout-use-hanging-indents' is set."
3049 (let ((fill-prefix (if allout-use-hanging-indents
3050 ;; Check for topic header indentation:
3053 (if (looking-at allout-regexp
)
3054 ;; ... construct indentation to account for
3055 ;; length of topic prefix:
3056 (make-string (progn (allout-end-of-prefix)
3059 (if (or allout-former-auto-filler allout-use-hanging-indents
)
3061 ;;;_ > allout-reindent-body (old-depth new-depth &optional number)
3062 (defun allout-reindent-body (old-depth new-depth
&optional number
)
3063 "Reindent body lines which were indented at OLD-DEPTH to NEW-DEPTH.
3065 Optional arg NUMBER indicates numbering is being added, and it must
3068 Note that refill of indented paragraphs is not done."
3071 (allout-end-of-prefix)
3072 (let* ((new-margin (current-column))
3073 excess old-indent-begin old-indent-end
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
))))
3080 ;; Process lines up to (but excluding) next topic header:
3084 (and (re-search-forward "[\n\r]\\(\\s-*\\)"
3087 ;; Register the indent data, before we reset the
3088 ;; match data with a subsequent `looking-at':
3089 (setq old-indent-begin
(match-beginning 1)
3090 old-indent-end
(match-end 1))
3091 (not (looking-at allout-regexp
)))
3092 (if (> 0 (setq excess
(- (- old-indent-end old-indent-begin
)
3094 ;; Text starts left of old margin - don't adjust:
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
)
3100 (indent-to (+ new-margin excess
(current-column))))))))))
3101 ;;;_ > allout-rebullet-current-heading (arg)
3102 (defun allout-rebullet-current-heading (arg)
3103 "Solicit new bullet for current visible heading."
3105 (let ((initial-col (current-column))
3106 (on-bullet (eq (point)(allout-current-bullet-pos)))
3107 (backwards (if (< arg
0)
3108 (setq arg
(* arg -
1)))))
3110 (save-excursion (allout-back-to-current-heading)
3111 (allout-end-of-prefix)
3112 (allout-rebullet-heading t
;;; solicit
3114 nil
;;; number-control
3116 t
)) ;;; do-successors
3120 (setq initial-col nil
) ; Override positioning back to init col
3122 (allout-next-visible-heading 1)
3123 (allout-goto-prefix)
3124 (allout-next-visible-heading -
1))))
3126 (cond (on-bullet (goto-char (allout-current-bullet-pos)))
3127 (initial-col (move-to-column initial-col
)))))
3128 ;;;_ > allout-rebullet-heading (&optional solicit ...)
3129 (defun allout-rebullet-heading (&optional solicit
3135 "Adjust bullet of current topic prefix.
3137 All args are optional.
3139 If SOLICIT is non-nil, then the choice of bullet is solicited from
3140 user. If it's a character, then that character is offered as the
3141 default, otherwise the one suited to the context \(according to
3142 distinction or depth) is offered. If non-nil, then the
3143 context-specific bullet is just used.
3145 Second arg DEPTH forces the topic prefix to that depth, regardless
3146 of the topic's current depth.
3148 Third arg NUMBER-CONTROL can force the prefix to or away from
3149 numbered form. It has effect only if `allout-numbered-bullet' is
3150 non-nil and soliciting was not explicitly invoked (via first arg).
3151 Its effect, numbering or denumbering, then depends on the setting
3152 of the forth arg, INDEX.
3154 If NUMBER-CONTROL is non-nil and forth arg INDEX is nil, then the
3155 prefix of the topic is forced to be non-numbered. Null index and
3156 non-nil NUMBER-CONTROL forces denumbering. Non-nil INDEX (and
3157 non-nil NUMBER-CONTROL) forces a numbered-prefix form. If non-nil
3158 INDEX is a number, then that number is used for the numbered
3159 prefix. Non-nil and non-number means that the index for the
3160 numbered prefix will be derived by allout-make-topic-prefix.
3162 Fifth arg DO-SUCCESSORS t means re-resolve count on succeeding
3165 Cf vars `allout-stylish-prefixes', `allout-old-style-prefixes',
3166 and `allout-numbered-bullet', which all affect the behavior of
3169 (let* ((current-depth (allout-depth))
3170 (new-depth (or new-depth current-depth
))
3171 (mb allout-recent-prefix-beginning
)
3172 (me allout-recent-prefix-end
)
3173 (current-bullet (buffer-substring (- me
1) me
))
3174 (new-prefix (allout-make-topic-prefix current-bullet
3181 ;; Is new one is identical to old?
3182 (if (and (= current-depth new-depth
)
3183 (string= current-bullet
3184 (substring new-prefix
(1- (length new-prefix
)))))
3188 ;; New prefix probably different from old:
3189 ; get rid of old one:
3190 (allout-unprotected (delete-region mb me
))
3192 ; Dispense with number if
3193 ; numbered-bullet prefix:
3194 (if (and allout-numbered-bullet
3195 (string= allout-numbered-bullet current-bullet
)
3196 (looking-at "[0-9]+"))
3198 (delete-region (match-beginning 0)(match-end 0))))
3200 ; Put in new prefix:
3201 (allout-unprotected (insert new-prefix
))
3203 ;; Reindent the body if elected, margin changed, and not encrypted body:
3204 (if (and allout-reindent-bodies
3205 (not (= new-depth current-depth
))
3206 (not (allout-encrypted-topic-p)))
3207 (allout-reindent-body current-depth new-depth
))
3209 ;; Recursively rectify successive siblings of orig topic if
3210 ;; caller elected for it:
3213 (while (allout-next-sibling new-depth nil
)
3215 (cond ((numberp index
) (1+ index
))
3216 ((not number-control
) (allout-sibling-index))))
3217 (if (allout-numbered-type-prefix)
3218 (allout-rebullet-heading nil
;;; solicit
3219 new-depth
;;; new-depth
3220 number-control
;;; number-control
3222 nil
))))) ;;;(dont!)do-successors
3223 ) ; (if (and (= current-depth new-depth)...))
3224 ) ; let* ((current-depth (allout-depth))...)
3226 ;;;_ > allout-rebullet-topic (arg)
3227 (defun allout-rebullet-topic (arg)
3228 "Rebullet the visible topic containing point and all contained subtopics.
3230 Descends into invisible as well as visible topics, however.
3232 With repeat count, shift topic depth by that amount."
3234 (let ((start-col (current-column))
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..."))
3242 (allout-back-to-current-heading)
3243 (if (<= (+ (allout-recent-depth) arg
) 0)
3244 (error "Attempt to shift topic below level 1"))
3245 (allout-rebullet-topic-grunt arg
)
3246 (if (not (zerop arg
)) (message "Shifting... done.")))
3247 (move-to-column (max 0 (+ start-col arg
)))))
3248 ;;;_ > allout-rebullet-topic-grunt (&optional relative-depth ...)
3249 (defun allout-rebullet-topic-grunt (&optional relative-depth
3254 "Like `allout-rebullet-topic', but on nearest containing topic
3257 See `allout-rebullet-heading' for rebulleting behavior.
3259 All arguments are optional.
3261 First arg RELATIVE-DEPTH means to shift the depth of the entire
3264 The rest of the args are for internal recursive use by the function
3265 itself. The are STARTING-DEPTH, STARTING-POINT, and INDEX."
3267 (let* ((relative-depth (or relative-depth
0))
3268 (new-depth (allout-depth))
3269 (starting-depth (or starting-depth new-depth
))
3270 (on-starting-call (null starting-point
))
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
))
3276 (allout-sibling-index))))
3277 (moving-outwards (< 0 relative-depth
))
3278 (starting-point (or starting-point
(point))))
3280 ;; Sanity check for excessive promotion done only on starting call:
3281 (and on-starting-call
3283 (> 0 (+ starting-depth relative-depth
))
3284 (error "Attempt to shift topic out beyond level 1")) ;;; ====>
3286 (cond ((= starting-depth new-depth
)
3287 ;; We're at depth to work on this one:
3288 (allout-rebullet-heading nil
;;; solicit
3289 (+ starting-depth
;;; starting-depth
3293 ;; Every contained topic will get hit,
3294 ;; and we have to get to outside ones
3296 nil
) ;;; do-successors
3297 ;; ... and work on subsequent ones which are at greater depth:
3299 (allout-next-heading)
3300 (while (and (not (eobp))
3301 (< starting-depth
(allout-recent-depth)))
3302 (setq index
(1+ index
))
3303 (allout-rebullet-topic-grunt relative-depth
;;; relative-depth
3304 (1+ starting-depth
);;;starting-depth
3305 starting-point
;;; starting-point
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:
3311 (allout-rebullet-topic-grunt relative-depth
;;; relative-depth
3312 new-depth
;;; starting-depth
3313 starting-point
;;; starting-point
3316 (if on-starting-call
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
))
3322 (or (= (allout-recent-depth) starting-depth
)
3323 (= (allout-recent-depth) (+ starting-depth
3325 (allout-rebullet-heading nil nil nil nil t
))
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
))
3330 (allout-rebullet-heading nil nil nil nil t
)))))
3333 ;;;_ > allout-renumber-to-depth (&optional depth)
3334 (defun allout-renumber-to-depth (&optional depth
)
3335 "Renumber siblings at current depth.
3337 Affects superior topics if optional arg DEPTH is less than current depth.
3339 Returns final depth."
3341 ;; Proceed by level, processing subsequent siblings on each,
3342 ;; ascending until we get shallower than the start depth:
3344 (let ((ascender (allout-depth))
3346 (while (and (not (eobp))
3348 (>= (allout-recent-depth) depth
)
3349 (>= ascender depth
))
3350 ; Skip over all topics at
3351 ; lesser depths, which can not
3352 ; have been disturbed:
3353 (while (and (not (setq was-eobp
(eobp)))
3354 (> (allout-recent-depth) ascender
))
3355 (allout-next-heading))
3356 ; Prime ascender for ascension:
3357 (setq ascender
(1- (allout-recent-depth)))
3358 (if (>= (allout-recent-depth) depth
)
3359 (allout-rebullet-heading nil
;;; solicit
3361 nil
;;; number-control
3363 t
)) ;;; do-successors
3364 (if was-eobp
(goto-char (point-max)))))
3365 (allout-recent-depth))
3366 ;;;_ > allout-number-siblings (&optional denumber)
3367 (defun allout-number-siblings (&optional denumber
)
3368 "Assign numbered topic prefix to this topic and its siblings.
3370 With universal argument, denumber - assign default bullet to this
3371 topic and its siblings.
3373 With repeated universal argument (`^U^U'), solicit bullet for each
3374 rebulleting each topic at this level."
3379 (allout-back-to-current-heading)
3380 (allout-beginning-of-level)
3381 (let ((depth (allout-recent-depth))
3382 (index (if (not denumber
) 1))
3383 (use-bullet (equal '(16) denumber
))
3386 (allout-rebullet-heading use-bullet
;;; solicit
3388 t
;;; number-control
3390 nil
) ;;; do-successors
3391 (if index
(setq index
(1+ index
)))
3392 (setq more
(allout-next-sibling depth nil
))))))
3393 ;;;_ > allout-shift-in (arg)
3394 (defun allout-shift-in (arg)
3395 "Increase depth of current heading and any topics collapsed within it.
3397 We disallow shifts that would result in the topic having a depth more than
3398 one level greater than the immediately previous topic, to avoid containment
3399 discontinuity. The first topic in the file can be adjusted to any positive
3404 (allout-back-to-current-heading)
3406 (let* ((current-depth (allout-recent-depth))
3407 (start-point (point))
3408 (predecessor-depth (progn
3410 (allout-goto-prefix)
3411 (if (< (point) start-point
)
3412 (allout-recent-depth)
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")))))))
3419 (allout-rebullet-topic arg
))
3420 ;;;_ > allout-shift-out (arg)
3421 (defun allout-shift-out (arg)
3422 "Decrease depth of current heading and any topics collapsed within it.
3424 We disallow shifts that would result in the topic having a depth more than
3425 one level greater than the immediately previous topic, to avoid containment
3426 discontinuity. The first topic in the file can be adjusted to any positive
3430 (allout-shift-in (* arg -
1)))
3431 (allout-rebullet-topic (* arg -
1)))
3432 ;;;_ : Surgery (kill-ring) functions with special provisions for outlines:
3433 ;;;_ > allout-kill-line (&optional arg)
3434 (defun allout-kill-line (&optional arg
)
3435 "Kill line, adjusting subsequent lines suitably for outline mode."
3439 (let ((start-point (point))
3440 (leading-kill-ring-entry (car kill-ring
))
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:
3451 ;; Ah, have to watch out for adjustments:
3452 (let* ((depth (allout-depth))
3453 (start-point (point))
3455 ; Do the kill, presenting option
3456 ; for read-only text:
3458 ; Provide some feedback:
3461 ; Start with the topic
3462 ; following killed line:
3463 (if (not (looking-at allout-regexp
))
3464 (allout-next-heading))
3465 (allout-renumber-to-depth depth
))))
3466 ;; condition case handler:
3468 (goto-char start-point
)
3469 (setq binding
(where-is-internal 'allout-kill-topic nil t
))
3470 (cond ((not binding
) (setq 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:
3477 (let ((got (car kill-ring
)))
3478 (setq kill-ring
(cdr kill-ring
))
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")
3490 ;;;_ > allout-kill-topic ()
3491 (defun allout-kill-topic ()
3492 "Kill topic together with subtopics.
3494 Leaves primary topic's trailing vertical whitespace, if any."
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.
3503 (let* ((beg (prog1 (allout-back-to-current-heading)(beginning-of-line)))
3504 (depth (allout-recent-depth)))
3505 (allout-end-of-current-subtree)
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:
3513 (and (allout-next-heading)
3514 (>= (allout-recent-depth) depth
))))
3517 (allout-unprotected (kill-region beg
(point)))
3520 (allout-renumber-to-depth depth
))))
3521 ;;;_ > allout-yank-processing ()
3522 (defun allout-yank-processing (&optional arg
)
3524 "Incidental outline-specific business to be done just after text yanks.
3526 Does depth adjustment of yanked topics, when:
3528 1 the stuff being yanked starts with a valid outline header prefix, and
3529 2 it is being yanked at the end of a line which consists of only a valid
3532 Also, adjusts numbering of subsequent siblings when appropriate.
3534 Depth adjustment alters the depth of all the topics being yanked
3535 the amount it takes to make the first topic have the depth of the
3536 header into which it's being yanked.
3538 The point is left in front of yanked, adjusted topics, rather than
3539 at the end (and vice-versa with the mark). Non-adjusted yanks,
3540 however, are left exactly like normal, non-allout-specific yanks."
3543 ; Get to beginning, leaving
3544 ; region around subject:
3545 (if (< (my-mark-marker t
) (point))
3546 (exchange-point-and-mark))
3547 (let* ((subj-beg (point))
3548 (subj-end (my-mark-marker t
))
3549 ;; 'resituate' if yanking an entire topic into topic header:
3550 (resituate (and (allout-e-o-prefix-p)
3551 (looking-at (concat "\\(" allout-regexp
"\\)"))
3552 (allout-prefix-data (match-beginning 1)
3554 ;; `rectify-numbering' if resituating (where several topics may
3555 ;; be resituating) or yanking a topic into a topic slot (bol):
3556 (rectify-numbering (or resituate
3557 (and (bolp) (looking-at allout-regexp
)))))
3559 ; The yanked stuff is a topic:
3560 (let* ((prefix-len (- (match-end 1) subj-beg
))
3561 (subj-depth (allout-recent-depth))
3562 (prefix-bullet (allout-recent-bullet))
3564 ;; Nil if adjustment unnecessary, otherwise depth to which
3565 ;; adjustment should be made:
3567 (and (goto-char subj-end
)
3569 (goto-char subj-beg
)
3570 (and (looking-at allout-regexp
)
3573 (not (= (point) subj-beg
)))
3574 (looking-at allout-regexp
)
3575 (allout-prefix-data (match-beginning 0)
3577 (allout-recent-depth))))
3580 (setq rectify-numbering allout-numbered-bullet
)
3582 ; Do the adjustment:
3584 (message "... yanking") (sit-for 0)
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 "^$")
3591 (allout-unprotected (delete-char -
1)))
3592 ; Work backwards, with each
3594 ; successively excluding the
3595 ; last processed topic from
3596 ; the narrow region:
3598 (allout-back-to-current-heading)
3599 ; go as high as we can in each bunch:
3600 (while (allout-ascend-to-depth (1- (allout-depth))))
3602 (allout-rebullet-topic-grunt (- adjust-to-depth
3605 (if (setq more
(not (bobp)))
3608 (narrow-to-region subj-beg
(point))))))
3610 ;; Preserve new bullet if it's a distinctive one, otherwise
3612 (if (string-match (regexp-quote prefix-bullet
)
3613 allout-distinctive-bullets-string
)
3614 ; Delete from bullet of old to
3615 ; before bullet of new:
3618 (delete-region (point) subj-beg
)
3619 (set-marker (my-mark-marker t
) subj-end
)
3620 (goto-char subj-beg
)
3621 (allout-end-of-prefix))
3622 ; Delete base subj prefix,
3624 (delete-region (point) (+ (point)
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
3635 ; Give some preliminary feedback:
3636 (message "... reconciling numbers") (sit-for 0)
3637 ; ... and renumber, in case necessary:
3638 (goto-char subj-beg
)
3639 (if (allout-goto-prefix)
3640 (allout-rebullet-heading nil
;;; solicit
3641 (allout-depth) ;;; depth
3642 nil
;;; number-control
3647 (exchange-point-and-mark))))
3648 ;;;_ > allout-yank (&optional arg)
3649 (defun allout-yank (&optional arg
)
3650 "`allout-mode' yank, with depth and numbering adjustment of yanked topics.
3652 Non-topic yanks work no differently than normal yanks.
3654 If a topic is being yanked into a bare topic prefix, the depth of the
3655 yanked topic is adjusted to the depth of the topic prefix.
3657 1 we're yanking in an `allout-mode' buffer
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
3662 If these conditions hold then the depth of the yanked topics are all
3663 adjusted the amount it takes to make the first one at the depth of the
3664 header into which it's being yanked.
3666 The point is left in front of yanked, adjusted topics, rather than
3667 at the end (and vice-versa with the mark). Non-adjusted yanks,
3668 however, (ones that don't qualify for adjustment) are handled
3669 exactly like normal yanks.
3671 Numbering of yanked topics, and the successive siblings at the depth
3672 into which they're being yanked, is adjusted.
3674 `allout-yank-pop' works with `allout-yank' just like normal `yank-pop'
3675 works with normal `yank' in non-outline buffers."
3678 (setq this-command
'yank
)
3681 (allout-yank-processing)))
3682 ;;;_ > allout-yank-pop (&optional arg)
3683 (defun allout-yank-pop (&optional arg
)
3684 "Yank-pop like `allout-yank' when popping to bare outline prefixes.
3686 Adapts level of popped topics to level of fresh prefix.
3688 Note - prefix changes to distinctive bullets will stick, if followed
3689 by pops to non-distinctive yanks. Bug..."
3692 (setq this-command
'yank
)
3695 (allout-yank-processing)))
3697 ;;;_ - Specialty bullet functions
3698 ;;;_ : File Cross references
3699 ;;;_ > allout-resolve-xref ()
3700 (defun allout-resolve-xref ()
3701 "Pop to file associated with current heading, if it has an xref bullet.
3703 \(Works according to setting of `allout-file-xref-bullet')."
3705 (if (not allout-file-xref-bullet
)
3707 "Outline cross references disabled - no `allout-file-xref-bullet'")
3708 (if (not (string= (allout-current-bullet) allout-file-xref-bullet
))
3709 (error "Current heading lacks cross-reference bullet `%s'"
3710 allout-file-xref-bullet
)
3713 (let* ((text-start allout-recent-prefix-end
)
3714 (heading-end (progn (end-of-line) (point))))
3715 (goto-char text-start
)
3717 (if (re-search-forward "\\s-\\(\\S-*\\)" heading-end t
)
3718 (buffer-substring (match-beginning 1) (match-end 1))))))
3719 (setq file-name
(expand-file-name file-name
))
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? "
3724 (error "%s not found and can't be created" file-name
)))
3725 (condition-case failure
3726 (find-file-other-window file-name
)
3728 (error "%s not found" file-name
))
3734 ;;;_ #6 Exposure Control
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.
3740 Ie, text following flag C-m \(carriage-return) is hidden until the
3741 next C-j (newline) char.
3743 Returns 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))
3752 (setq inhibit-read-only t
)
3753 (setq buffer-undo-list t
)
3755 (setq trans from from to to trans
))
3756 (subst-char-in-region from to
3757 (if (= flag ?
\n) ?
\r ?
\n)
3759 ;; adjust character read-protection on all the affected lines.
3760 ;; we handle the region line-by-line.
3763 (setq to
(min (+ 2 (point)) (point-max)))
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]"
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))
3778 ;; Handle the end-of-line to beginning of next line:
3780 (progn (forward-char 1)
3781 (remove-text-properties (1- (point)) (point)
3782 '(read-only nil
)))))
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
)
3791 ;;;_ > allout-flag-current-subtree (flag)
3792 (defun allout-flag-current-subtree (flag)
3793 "Hide or show subtree of currently-visible topic.
3795 See `allout-flag-region' for more details."
3798 (allout-back-to-current-heading)
3799 (let ((from (point))
3800 (to (progn (allout-end-of-current-subtree) (1- (point)))))
3801 (allout-flag-region from to flag
))))
3803 ;;;_ - Topic-specific
3804 ;;;_ > allout-show-entry ()
3805 (defun allout-show-entry ()
3806 "Like `allout-show-current-entry', reveals entries nested in hidden topics.
3808 This is a way to give restricted peek at a concealed locality without the
3809 expense of exposing its context, but can leave the outline with aberrant
3810 exposure. `allout-hide-current-entry-completely' or `allout-show-offshoot'
3811 should be used after the peek to rectify the exposure."
3817 (allout-goto-prefix)
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:
3823 ;; or we're in body - include it:
3824 (max beg
(or (allout-pre-next-preface) (point))))))
3825 (allout-flag-region beg end ?
\n)
3827 ;;;_ > allout-show-children (&optional level strict)
3828 (defun allout-show-children (&optional level strict
)
3830 "If point is visible, show all direct subheadings of this heading.
3832 Otherwise, do `allout-show-to-offshoot', and then show subheadings.
3834 Optional LEVEL specifies how many levels below the current level
3835 should be shown, or all levels if t. Default is 1.
3837 Optional STRICT means don't resort to -show-to-offshoot, no matter
3838 what. This is basically so -show-to-offshoot, which is called by
3839 this function, can employ the pure offspring-revealing capabilities of
3842 Returns point at end of subtree that was opened, if any. (May get a
3843 point of non-opened subtree?)"
3847 (if (and (not strict
)
3850 (progn (allout-show-to-offshoot) ; Point's concealed, open to
3852 ;; Then recurse, but with "strict" set so we don't
3853 ;; infinite regress:
3854 (setq max-pos
(allout-show-children level t
)))
3858 (let* ((start-pt (point))
3859 (chart (allout-chart-subtree (or level
1)))
3860 (to-reveal (allout-chart-to-reveal chart
(or level
1))))
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.
3866 (allout-flag-region (point) (allout-snug-back) ?
\n)
3867 (if allout-show-bodies
3868 (progn (goto-char (car to-reveal
))
3869 (allout-show-current-entry)))))
3871 (goto-char (car to-reveal
))
3872 (allout-flag-region (point) (allout-snug-back) ?
\n)
3873 (if allout-show-bodies
3874 (progn (goto-char (car to-reveal
))
3875 (allout-show-current-entry)))
3876 (setq to-reveal
(cdr to-reveal
)))))))))
3877 ;;;_ > allout-hide-point-reconcile ()
3878 (defun allout-hide-reconcile ()
3879 "Like `allout-hide-current-entry'; hides completely if within hidden region.
3881 Specifically intended for aberrant exposure states, like entries that were
3882 exposed by `allout-show-entry' but are within otherwise concealed regions."
3885 (allout-goto-prefix)
3886 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3887 (progn (allout-pre-next-preface)
3888 (if (= ?
\r (following-char))
3892 ;;;_ > allout-show-to-offshoot ()
3893 (defun allout-show-to-offshoot ()
3894 "Like `allout-show-entry', but reveals all concealed ancestors, as well.
3896 As with `allout-hide-current-entry-completely', useful for rectifying
3897 aberrant exposure states produced by `allout-show-entry'."
3901 (let ((orig-pt (point))
3902 (orig-pref (allout-goto-prefix))
3905 (while (or bag-it
(= (preceding-char) ?
\r))
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)
3911 (allout-show-current-subtree)
3916 "allout-show-to-offshoot: "
3917 "Aberrant nesting encountered.")))
3918 (allout-show-children)
3919 (goto-char orig-pref
))
3920 (goto-char orig-pt
)))
3921 (if (allout-hidden-p)
3922 (allout-show-entry)))
3923 ;;;_ > allout-hide-current-entry ()
3924 (defun allout-hide-current-entry ()
3925 "Hide the body directly following this heading."
3927 (allout-back-to-current-heading)
3929 (allout-flag-region (point)
3930 (progn (allout-end-of-entry) (point))
3932 ;;;_ > allout-show-current-entry (&optional arg)
3933 (defun allout-show-current-entry (&optional arg
)
3935 "Show body following current heading, or hide the entry if repeat count."
3939 (allout-hide-current-entry)
3941 (allout-flag-region (point)
3942 (progn (allout-end-of-entry) (point))
3945 ;;;_ > allout-hide-current-entry-completely ()
3946 ; ... allout-hide-current-entry-completely also for isearch dynamic exposure:
3947 (defun allout-hide-current-entry-completely ()
3948 "Like `allout-hide-current-entry', but conceal topic completely.
3950 Specifically intended for aberrant exposure states, like entries that were
3951 exposed by `allout-show-entry' but are within otherwise concealed regions."
3954 (allout-goto-prefix)
3955 (allout-flag-region (if (not (bobp)) (1- (point)) (point))
3956 (progn (allout-pre-next-preface)
3957 (if (= ?
\r (following-char))
3961 ;;;_ > allout-show-current-subtree (&optional arg)
3962 (defun allout-show-current-subtree (&optional arg
)
3963 "Show everything within the current topic. With a repeat-count,
3964 expose this topic and its siblings."
3967 (if (<= (allout-current-depth) 0)
3968 ;; Outside any topics - try to get to the first:
3969 (if (not (allout-next-heading))
3971 ;; got to first, outermost topic - set to expose it and siblings:
3972 (message "Above outermost topic - exposing all.")
3973 (allout-flag-region (point-min)(point-max) ?
\n))
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
)
3980 "Close the current topic, or containing topic if this one is already closed.
3982 If this topic is closed and it's a top level topic, close this topic
3985 If optional arg JUST-CLOSE is non-nil, do not treat the parent or
3986 siblings, even if the target topic is already closed."
3989 (let ((from (point))
3990 (orig-eol (progn (end-of-line)
3991 (if (not (allout-goto-prefix))
3992 (error "No topics found")
3993 (end-of-line)(point)))))
3994 (allout-flag-current-subtree ?
\r)
3996 (if (and (= orig-eol
(progn (goto-char orig-eol
)
4000 ;; Structure didn't change - try hiding current level:
4002 (if (allout-up-current-level 1 t
)
4006 "Top-level topic already closed - closing siblings..."))
4008 (allout-expose-topic '(0 :))
4009 (message (concat msg
" Done.")))
4011 (/= (allout-recent-depth) 0))
4012 (allout-hide-current-subtree))
4014 ;;;_ > allout-show-current-branches ()
4015 (defun allout-show-current-branches ()
4016 "Show all subheadings of this heading, but not their bodies."
4019 (allout-show-children t
))
4020 ;;;_ > allout-hide-current-leaves ()
4021 (defun allout-hide-current-leaves ()
4022 "Hide the bodies of the current topic and all its offspring."
4024 (allout-back-to-current-heading)
4025 (allout-hide-region-body (point) (progn (allout-end-of-current-subtree)
4028 ;;;_ - Region and beyond
4029 ;;;_ > allout-show-all ()
4030 (defun allout-show-all ()
4031 "Show all of the text in the buffer."
4033 (message "Exposing entire buffer...")
4034 (allout-flag-region (point-min) (point-max) ?
\n)
4035 (message "Exposing entire buffer... Done."))
4036 ;;;_ > allout-hide-bodies ()
4037 (defun allout-hide-bodies ()
4038 "Hide all of buffer except headings."
4040 (allout-hide-region-body (point-min) (point-max)))
4041 ;;;_ > allout-hide-region-body (start end)
4042 (defun allout-hide-region-body (start end
)
4043 "Hide all body lines in the region, but not headings."
4046 (narrow-to-region start end
)
4047 (goto-char (point-min))
4049 (allout-flag-region (point)
4050 (progn (allout-pre-next-preface) (point)) ?
\r)
4053 (if (looking-at "[\n\r][\n\r]")
4056 ;;;_ > allout-expose-topic (spec)
4057 (defun allout-expose-topic (spec)
4058 "Apply exposure specs to successive outline topic items.
4060 Use the more convenient frontend, `allout-new-exposure', if you don't
4061 need evaluation of the arguments, or even better, the `allout-layout'
4062 variable-keyed mode-activation/auto-exposure feature of allout outline
4063 mode. See the respective documentation strings for more details.
4065 Cursor is left at start position.
4067 SPEC is either a number or a list.
4069 Successive specs on a list are applied to successive sibling topics.
4071 A simple spec \(either a number, one of a few symbols, or the null
4072 list) dictates the exposure for the corresponding topic.
4074 Non-null lists recursively designate exposure specs for respective
4075 subtopics of the current topic.
4077 The `:' repeat spec is used to specify exposure for any number of
4078 successive siblings, up to the trailing ones for which there are
4079 explicit specs following the `:'.
4081 Simple (numeric and null-list) specs are interpreted as follows:
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
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.
4091 apply prior element to all siblings at current level, *up to*
4092 those siblings that would be covered by specs following the `:'
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.)
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.
4101 \(allout-expose-topic '(-1 : 0))
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.
4105 \(allout-expose-topic '(-1 () : 1 0))
4106 Close current topic so only the immediate subtopics are shown;
4107 show the children in the second to last topic, and completely
4109 \(allout-expose-topic '(-2 : -1 *))
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."
4114 (interactive "xExposure spec: ")
4115 (if (not (listp spec
))
4117 (let ((depth (allout-depth))
4124 (setq prev-elem curr-elem
4125 curr-elem
(car spec
)
4127 (cond ; Do current element:
4128 ((null curr-elem
) nil
)
4129 ((symbolp curr-elem
)
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))
4139 ;; Expand the `repeat' spec to an explicit version,
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:
4143 (- (length (allout-chart-siblings))
4146 ;; Some residue - cover it with prev-elem:
4147 (setq spec
(append (make-list residue prev-elem
)
4149 ((numberp curr-elem
)
4150 (if (and (>= 0 curr-elem
) (allout-visible-p))
4151 (save-excursion (allout-hide-current-subtree t
)
4154 (if (> allout-recent-end-of-subtree max-pos
)
4156 allout-recent-end-of-subtree
)))))
4157 (if (> (abs curr-elem
) 0)
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
)))))
4162 (if (allout-descend-to-depth (1+ depth
))
4163 (let ((got (allout-expose-topic curr-elem
)))
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
))
4170 (allout-next-heading)))
4171 ((allout-next-sibling depth
))))
4173 ;;;_ > allout-old-expose-topic (spec &rest followers)
4174 (defun allout-old-expose-topic (spec &rest followers
)
4176 "Deprecated. Use `allout-expose-topic' \(with different schema
4179 Dictate wholesale exposure scheme for current topic, according to SPEC.
4181 SPEC is either a number or a list. Optional successive args
4182 dictate exposure for subsequent siblings of current topic.
4184 A simple spec (either a number, a special symbol, or the null list)
4185 dictates the overall exposure for a topic. Non null lists are
4186 composite specs whose first element dictates the overall exposure for
4187 a topic, with the subsequent elements in the list interpreted as specs
4188 that dictate the exposure for the successive offspring of the topic.
4190 Simple (numeric and null-list) specs are interpreted as follows:
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.
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.
4201 If the spec is a list, the first element must be a number, which
4202 dictates the exposure depth of the topic as a whole. Subsequent
4203 elements of the list are nested SPECs, dictating the specific exposure
4204 for the corresponding offspring of the topic.
4206 Optional FOLLOWERS arguments dictate exposure for succeeding siblings."
4208 (interactive "xExposure spec: ")
4209 (let ((depth (allout-current-depth))
4212 (cond ((null spec
) nil
)
4214 (if (eq spec
'*) (allout-show-current-subtree))
4215 (if (eq spec
'+) (allout-show-current-branches))
4216 (if (eq spec
'-
) (allout-show-current-entry)))
4219 (save-excursion (allout-hide-current-subtree t
)
4221 (if (or (not max-pos
)
4222 (> (point) max-pos
))
4223 (setq max-pos
(point)))
4225 (setq spec
(* -
1 spec
)))))
4227 (allout-show-children spec
)))
4229 ;(let ((got (allout-old-expose-topic (car spec))))
4230 ; (if (and got (or (not max-pos) (> got max-pos)))
4231 ; (setq max-pos got)))
4232 (let ((new-depth (+ (allout-current-depth) 1))
4234 (setq max-pos
(allout-old-expose-topic (car spec
)))
4235 (setq spec
(cdr spec
))
4237 (allout-descend-to-depth new-depth
)
4238 (not (allout-hidden-p)))
4239 (progn (setq got
(apply 'allout-old-expose-topic spec
))
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
)))
4247 (allout-next-sibling depth
)))
4248 (allout-old-expose-topic (car followers
))
4249 (setq followers
(cdr followers
)))
4251 ;;;_ > allout-new-exposure '()
4252 (defmacro allout-new-exposure
(&rest spec
)
4253 "Literal frontend for `allout-expose-topic', doesn't evaluate arguments.
4254 Some arguments that would need to be quoted in `allout-expose-topic'
4255 need not be quoted in `allout-new-exposure'.
4257 Cursor is left at start position.
4259 Use this instead of obsolete `allout-exposure'.
4262 \(allout-new-exposure (-1 () () () 1) 0)
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.
4266 \(allout-new-exposure : -1 0)
4267 Close all topics at current level to expose only their
4268 immediate children, except for the last topic at the current
4269 level, in which even its immediate children are hidden.
4270 \(allout-new-exposure -2 : -1 *)
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
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
))))
4280 ;;;_ #7 Systematic outline presentation - copying, printing, flattening
4282 ;;;_ - Mapping and processing of topics
4283 ;;;_ ( See also Subtree Charting, in Navigation code.)
4284 ;;;_ > allout-stringify-flat-index (flat-index)
4285 (defun allout-stringify-flat-index (flat-index &optional context
)
4286 "Convert list representing section/subsection/... to document string.
4288 Optional arg CONTEXT indicates interior levels to include."
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)))
4302 ;; Take care of the indentation:
4309 (1+ (truncate (if (zerop (car flat-index
))
4311 (log10 (car flat-index
)))))
4314 (setq flat-index
(cdr flat-index
)))
4315 ;; Dispose of single extra delim:
4316 (setq result
(cdr result
))))
4317 (apply 'concat result
)))
4318 ;;;_ > allout-stringify-flat-index-plain (flat-index)
4319 (defun allout-stringify-flat-index-plain (flat-index)
4320 "Convert list representing section/subsection/... to document string."
4324 (setq result
(cons (int-to-string (car flat-index
))
4326 (cons delim result
))))
4327 (setq flat-index
(cdr flat-index
)))
4328 (apply 'concat result
)))
4329 ;;;_ > allout-stringify-flat-index-indented (flat-index)
4330 (defun allout-stringify-flat-index-indented (flat-index)
4331 "Convert list representing section/subsection/... to document string."
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
)))
4342 ;; Take care of the indentation:
4349 (1+ (truncate (if (zerop (car flat-index
))
4351 (log10 (car flat-index
)))))
4354 (setq flat-index
(cdr flat-index
)))
4355 ;; Dispose of single extra delim:
4356 (setq result
(cdr result
))))
4357 (apply 'concat result
)))
4358 ;;;_ > allout-listify-exposed (&optional start end format)
4359 (defun allout-listify-exposed (&optional start end format
)
4361 "Produce a list representing exposed topics in current region.
4363 This list can then be used by `allout-process-exposed' to manipulate
4366 Optional START and END indicate bounds of region.
4368 optional arg, FORMAT, designates an alternate presentation form for
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.
4376 The elements of the list produced are lists that represents a topic
4377 header and body. The elements of that list are:
4379 - a number representing the depth of the topic,
4380 - a string representing the header-prefix, including trailing whitespace and
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."
4390 (strings prefix pad result depth new-depth out gone-out bullet beg
4395 ;; Goto initial topic, and register preceeding stuff, if any:
4396 (if (> (allout-goto-prefix) start
)
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
)))
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.
4407 (setq done
; The boundary for the current topic:
4408 (not (allout-next-visible-heading 1)))
4409 (setq new-depth
(allout-recent-depth))
4411 out
(< new-depth depth
))
4416 (while (> next
(point)) ; Get all the exposed text in
4418 (cons (buffer-substring
4420 ;To hidden text or end of line:
4422 (search-forward "\r"
4423 (save-excursion (end-of-line)
4426 (if (= (preceding-char) ?
\r)
4430 (if (< (point) next
) ; Resume from after hid text, if any.
4433 ;; Accumulate list for this topic:
4434 (setq strings
(nreverse strings
))
4438 (let ((special (if (string-match
4439 (regexp-quote bullet
)
4440 allout-distinctive-bullets-string
)
4442 (cond ((listp format
)
4444 (if allout-abbreviate-flattened-numbering
4445 (allout-stringify-flat-index format
4447 (allout-stringify-flat-index-plain
4451 ((eq format
'indent
)
4454 (concat (make-string (1+ depth
) ?
)
4455 (substring prefix -
1))
4458 (make-string depth ?
)
4460 (t (error "allout-listify-exposed: %s %s"
4461 "invalid format" format
))))
4462 (list depth prefix strings
))
4464 ;; Reasses format, if any:
4465 (if (and format
(listp format
))
4466 (cond ((= new-depth depth
)
4467 (setq format
(cons (1+ (car format
))
4469 ((> new-depth depth
) ; descending - assume by 1:
4470 (setq format
(cons 1 format
)))
4473 (while (< new-depth depth
)
4474 (setq format
(cdr format
))
4475 (setq depth
(1- depth
)))
4476 ; And increment the current one:
4478 (cons (1+ (or (car format
)
4481 ;; Put the list with first at front, to last at back:
4482 (nreverse result
))))
4483 ;;;_ > my-region-active-p ()
4484 (defmacro my-region-active-p
()
4485 (if (fboundp 'region-active-p
)
4488 ;;;_ > allout-process-exposed (&optional func from to frombuf
4490 (defun allout-process-exposed (&optional func from to frombuf tobuf
4491 format
&optional start-num
)
4492 "Map function on exposed parts of current topic; results to another buffer.
4494 All args are options; default values itemized below.
4496 Apply FUNCTION to exposed portions FROM position TO position in buffer
4497 FROMBUF to buffer TOBUF. Sixth optional arg, FORMAT, designates an
4498 alternate presentation form:
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.
4509 FUNCTION: `allout-insert-listified'
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*\"
4516 ; Resolve arguments,
4517 ; defaulting if necessary:
4518 (if (not func
) (setq func
'allout-insert-listified
))
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))))
4524 (if (not (bufferp frombuf
))
4525 ;; Specified but not a buffer - get it:
4526 (let ((got (get-buffer frombuf
)))
4528 (error (concat "allout-process-exposed: source buffer "
4531 (setq frombuf got
))))
4532 ;; not specified - default it:
4533 (setq frombuf
(current-buffer)))
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*")))
4543 (progn (set-buffer frombuf
)
4544 (allout-listify-exposed from to format
))))
4546 (mapcar func listified
)
4547 (pop-to-buffer tobuf
)))
4550 ;;;_ > allout-insert-listified (listified)
4551 (defun allout-insert-listified (listified)
4552 "Insert contents of listified outline portion in current buffer.
4554 LISTIFIED is a list representing each topic header and body:
4556 \`(depth prefix text)'
4558 or \`(depth prefix text bullet-plus)'
4560 If `bullet-plus' is specified, it is inserted just after the entire prefix."
4561 (setq listified
(cdr listified
))
4562 (let ((prefix (prog1
4564 (setq listified
(cdr listified
))))
4567 (setq listified
(cdr listified
))))
4568 (bullet-plus (car listified
)))
4570 (if bullet-plus
(insert (concat " " bullet-plus
)))
4573 (if (setq text
(cdr text
))
4576 ;;;_ > allout-copy-exposed-to-buffer (&optional arg tobuf format)
4577 (defun allout-copy-exposed-to-buffer (&optional arg tobuf format
)
4578 "Duplicate exposed portions of current outline to another buffer.
4580 Other buffer has current buffers name with \" exposed\" appended to it.
4582 With repeat count, copy the exposed parts of only the current topic.
4584 Optional second arg TOBUF is target buffer name.
4586 Optional third arg FORMAT, if non-nil, symbolically designates an
4587 alternate presentation format for the outline:
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."
4599 (setq tobuf
(get-buffer-create (concat "*" (buffer-name) " exposed*"))))
4600 (let* ((start-pt (point))
4601 (beg (if arg
(allout-back-to-current-heading) (point-min)))
4602 (end (if arg
(allout-end-of-current-subtree) (point-max)))
4603 (buf (current-buffer))
4605 (if (eq format
'flat
)
4606 (setq format
(if arg
(save-excursion
4608 (allout-topic-flat-index))
4610 (save-excursion (set-buffer tobuf
)(erase-buffer))
4611 (allout-process-exposed 'allout-insert-listified
4617 (goto-char (point-min))
4619 (goto-char start-pt
)))
4620 ;;;_ > allout-flatten-exposed-to-buffer (&optional arg tobuf)
4621 (defun allout-flatten-exposed-to-buffer (&optional arg tobuf
)
4622 "Present numeric outline of outline's exposed portions in another buffer.
4624 The resulting outline is not compatible with outline mode - use
4625 `allout-copy-exposed-to-buffer' if you want that.
4627 Use `allout-indented-exposed-to-buffer' for indented presentation.
4629 With repeat count, copy the exposed portions of only current topic.
4631 Other buffer has current buffer's name with \" exposed\" appended to
4632 it, unless optional second arg TOBUF is specified, in which case it is
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
)
4638 "Present indented outline of outline's exposed portions in another buffer.
4640 The resulting outline is not compatible with outline mode - use
4641 `allout-copy-exposed-to-buffer' if you want that.
4643 Use `allout-flatten-exposed-to-buffer' for numeric sectional presentation.
4645 With repeat count, copy the exposed portions of only current topic.
4647 Other buffer has current buffer's name with \" exposed\" appended to
4648 it, unless optional second arg TOBUF is specified, in which case it is
4651 (allout-copy-exposed-to-buffer arg tobuf
'indent
))
4653 ;;;_ - LaTeX formatting
4654 ;;;_ > allout-latex-verb-quote (string &optional flow)
4655 (defun allout-latex-verb-quote (string &optional flow
)
4656 "Return copy of STRING for literal reproduction across LaTeX processing.
4657 Expresses the original characters \(including carriage returns) of the
4658 string across LaTeX processing."
4659 (mapconcat (function
4661 (cond ((memq char
'(?
\\ ?$ ?% ?
# ?
& ?
{ ?
} ?_ ?^ ?- ?
*))
4662 (concat "\\char" (number-to-string char
) "{}"))
4663 ((= char ?
\n) "\\\\")
4664 (t (char-to-string char
)))))
4667 ;;;_ > allout-latex-verbatim-quote-curr-line ()
4668 (defun allout-latex-verbatim-quote-curr-line ()
4669 "Express line for exact \(literal) representation across LaTeX processing.
4671 Adjust line contents so it is unaltered \(from the original line)
4672 across LaTeX processing, within the context of a `verbatim'
4673 environment. Leaves point at the end of the line."
4676 (end (progn (end-of-line)(point))))
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))
4685 (goto-char (1+ (match-end 0))))))
4686 ;;;_ > allout-insert-latex-header (buffer)
4687 (defun allout-insert-latex-header (buffer)
4688 "Insert initial LaTeX commands at point in BUFFER."
4689 ;; Much of this is being derived from the stuff in appendix of E in
4690 ;; the TeXBook, pg 421.
4692 (let ((doc-style (format "\n\\documentstyle{%s}\n"
4694 (page-numbering (if allout-number-pages
4695 "\\pagestyle{empty}\n"
4697 (linesdef (concat "\\def\\beginlines{"
4698 "\\par\\begingroup\\nobreak\\medskip"
4700 " \\kern1pt\\nobreak \\obeylines \\obeyspaces "
4701 "\\everypar{\\strut}}\n"
4703 "\\kern1pt\\endgroup\\medbreak\\noindent}\n"))
4704 (titlecmd (format "\\newcommand{\\titlecmd}[1]{{%s #1}}\n"
4705 allout-title-style
))
4706 (labelcmd (format "\\newcommand{\\labelcmd}[1]{{%s #1}}\n"
4707 allout-label-style
))
4708 (headlinecmd (format "\\newcommand{\\headlinecmd}[1]{{%s #1}}\n"
4709 allout-head-line-style
))
4710 (bodylinecmd (format "\\newcommand{\\bodylinecmd}[1]{{%s #1}}\n"
4711 allout-body-line-style
))
4712 (setlength (format "%s%s%s%s"
4713 "\\newlength{\\stepsize}\n"
4714 "\\setlength{\\stepsize}{"
4717 (oneheadline (format "%s%s%s%s%s%s%s"
4718 "\\newcommand{\\OneHeadLine}[3]{%\n"
4720 "\\hspace*{#2\\stepsize}%\n"
4721 "\\labelcmd{#1}\\hspace*{.2cm}"
4722 "\\headlinecmd{#3}\\\\["
4725 (onebodyline (format "%s%s%s%s%s%s"
4726 "\\newcommand{\\OneBodyLine}[2]{%\n"
4728 "\\hspace*{#1\\stepsize}%\n"
4729 "\\bodylinecmd{#2}\\\\["
4732 (begindoc "\\begin{document}\n\\begin{center}\n")
4733 (title (format "%s%s%s%s"
4735 (allout-latex-verb-quote (if allout-title
4738 ('error
"<unnamed buffer>"))
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
4760 ;;;_ > allout-insert-latex-trailer (buffer)
4761 (defun allout-insert-latex-trailer (buffer)
4762 "Insert concluding LaTeX commands at point in BUFFER."
4764 (insert "\n\\end{document}\n"))
4765 ;;;_ > allout-latexify-one-item (depth prefix bullet text)
4766 (defun allout-latexify-one-item (depth prefix bullet text
)
4767 "Insert LaTeX commands for formatting one outline item.
4769 Args are the topics numeric DEPTH, the header PREFIX lead string, the
4770 BULLET string, and a list of TEXT strings for the body."
4771 (let* ((head-line (if text
(car text
)))
4772 (body-lines (cdr text
))
4776 (insert (concat "\\OneHeadLine{\\verb\1 "
4777 (allout-latex-verb-quote bullet
)
4782 (allout-latex-verb-quote head-line
)
4785 (if (not body-lines
)
4787 ;;(insert "\\beginlines\n")
4788 (insert "\\begin{verbatim}\n")
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,
4797 (if (and body-content
4798 (setq bop
(string-match "\\end{verbatim}" curr-line
)))
4799 (setq curr-line
(concat (substring curr-line
0 bop
)
4801 (substring curr-line bop
))))
4802 ;;(insert "|" (car body-lines) "|")
4804 (allout-latex-verbatim-quote-curr-line)
4806 (setq body-lines
(cdr body-lines
)))
4808 (setq body-content nil
)
4812 ;;(insert "\\endlines\n")
4813 (insert "\\end{verbatim}\n")
4815 ;;;_ > allout-latexify-exposed (arg &optional tobuf)
4816 (defun allout-latexify-exposed (arg &optional tobuf
)
4817 "Format current topics exposed portions to TOBUF for LaTeX processing.
4818 TOBUF defaults to a buffer named the same as the current buffer, but
4819 with \"*\" prepended and \" latex-formed*\" appended.
4821 With repeat count, copy the exposed portions of entire buffer."
4826 (get-buffer-create (concat "*" (buffer-name) " latexified*"))))
4827 (let* ((start-pt (point))
4828 (beg (if arg
(point-min) (allout-back-to-current-heading)))
4829 (end (if arg
(point-max) (allout-end-of-current-subtree)))
4830 (buf (current-buffer)))
4833 (allout-insert-latex-header tobuf
)
4834 (goto-char (point-max))
4835 (allout-process-exposed 'allout-latexify-one-item
4840 (goto-char (point-max))
4841 (allout-insert-latex-trailer tobuf
)
4842 (goto-char (point-min))
4844 (goto-char start-pt
)))
4847 ;;;_ > allout-toggle-current-subtree-encryption (&optional fetch-pass)
4848 (defun allout-toggle-current-subtree-encryption (&optional fetch-pass
)
4849 "Encrypt clear or decrypt encoded text of visibly-containing topic's contents.
4851 Optional FETCH-PASS universal argument provokes key-pair encryption with
4852 single universal argument. With doubled universal argument \(value = 16),
4853 it forces prompting for the passphrase regardless of availability from the
4854 passphrase cache. With no universal argument, the appropriate passphrase
4855 is obtained from the cache, if available, else from the user.
4857 Currently only GnuPG encryption is supported.
4859 \**NOTE WELL** that the encrypted text must be ascii-armored. For gnupg
4860 encryption, include the option ``armor'' in your ~/.gnupg/gpg.conf file.
4862 Both symmetric-key and key-pair encryption is implemented. Symmetric is
4863 the default, use a single \(x4) universal argument for keypair mode.
4865 Encrypted topic's bullet is set to a `~' to signal that the contents of the
4866 topic \(body and subtopics, but not heading) is pending encryption or
4867 encrypted. `*' asterisk immediately after the bullet signals that the body
4868 is encrypted, its' absence means the topic is meant to be encrypted but is
4869 not. When a file with topics pending encryption is saved, topics pending
4870 encryption are encrypted. See allout-encrypt-unencrypted-on-saves for
4871 auto-encryption specifics.
4873 \**NOTE WELL** that automatic encryption that happens during saves will
4874 default to symmetric encryption - you must manually \(re)encrypt key-pair
4875 encrypted topics if you want them to continue to use the key-pair cipher.
4877 Level-1 topics, with prefix consisting solely of an `*' asterisk, cannot be
4878 encrypted. If you want to encrypt the contents of a top-level topic, use
4879 \\[allout-shift-in] to increase its depth.
4883 The encryption passphrase is solicited if not currently available in the
4884 passphrase cache from a recent encryption action.
4886 The solicited passphrase is retained for reuse in a buffer-specific cache
4887 for some set period of time \(default, 60 seconds), after which the string
4888 is nulled. The passphrase cache timeout is customized by setting
4889 `pgg-passphrase-cache-expiry'.
4891 Symmetric Passphrase Hinting and Verification
4893 If the file previously had no associated passphrase, or had a different
4894 passphrase than specified, the user is prompted to repeat the new one for
4895 corroboration. A random string encrypted by the new passphrase is set on
4896 the buffer-specific variable `allout-passphrase-verifier-string', for
4897 confirmation of the passphrase when next obtained, before encrypting or
4898 decrypting anything with it. This helps avoid mistakenly shifting between
4901 If allout customization var `allout-passphrase-verifier-handling' is
4902 non-nil, an entry for `allout-passphrase-verifier-string' and its value is
4903 added to an Emacs 'local variables' section at the end of the file, which
4904 is created if necessary. That setting is for retention of the passphrase
4905 verifier across emacs sessions.
4907 Similarly, `allout-passphrase-hint-string' stores a user-provided reminder
4908 about their passphrase, and `allout-passphrase-hint-handling' specifies
4909 when the hint is presented, or if passphrase hints are disabled. If
4910 enabled \(see the `allout-passphrase-hint-handling' docstring for details),
4911 the hint string is stored in the local-variables section of the file, and
4912 solicited whenever the passphrase is changed."
4915 (allout-back-to-current-heading)
4916 (allout-toggle-subtree-encryption)
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.)
4923 Optional FETCH-PASS universal argument provokes key-pair encryption with
4924 single universal argument. With doubled universal argument \(value = 16),
4925 it forces prompting for the passphrase regardless of availability from the
4926 passphrase cache. With no universal argument, the appropriate passphrase
4927 is obtained from the cache, if available, else from the user.
4929 Currently only GnuPG encryption is supported.
4931 \**NOTE WELL** that the encrypted text must be ascii-armored. For gnupg
4932 encryption, include the option ``armor'' in your ~/.gnupg/gpg.conf file.
4934 See `allout-toggle-current-subtree-encryption' for more details."
4938 (allout-end-of-prefix t
)
4940 (if (= (allout-recent-depth) 1)
4941 (error (concat "Cannot encrypt or decrypt level 1 topics -"
4942 " shift it in to make it encryptable")))
4944 (let* ((allout-buffer (current-buffer))
4946 (after-bullet-pos (point))
4948 (progn (if (= (point-max) after-bullet-pos
)
4949 (error "no body to encrypt"))
4950 (allout-encrypted-topic-p)))
4951 (was-collapsed (if (not (re-search-forward "[\n\r]" nil t
))
4955 (subtree-beg (1+ (point)))
4956 (subtree-end (allout-end-of-subtree))
4957 (subject-text (buffer-substring-no-properties subtree-beg
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:
4967 ;; detect the type by which it is already encrypted
4969 (allout-encrypted-key-info subject-text
))
4970 (and (member fetch-pass
'(4 (4)))
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)))))
4979 (allout-encrypt-string subject-text was-encrypted
4981 for-key-type for-key-identity fetch-pass
))
4983 ;; Replace the subtree with the processed product.
4986 (set-buffer allout-buffer
)
4987 (delete-region subtree-beg subtree-end
)
4988 (insert result-text
)
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
))
5002 (insert allout-topic-encryption-bullet
)))
5004 ;; Remove the is-encrypted bullet qualifier:
5005 (progn (goto-char after-bullet-pos
)
5007 ;; Add the is-encrypted bullet qualifier:
5008 (goto-char after-bullet-pos
)
5015 ;;;_ > allout-encrypt-string (text decrypt allout-buffer key-type for-key
5016 ;;; fetch-pass &optional retried verifying
5018 (defun allout-encrypt-string (text decrypt allout-buffer key-type for-key
5019 fetch-pass
&optional retried verifying
5021 "Encrypt or decrypt message TEXT.
5023 If DECRYPT is true (default false), then decrypt instead of encrypt.
5025 FETCH-PASS (default false) forces fresh prompting for the passphrase.
5027 KEY-TYPE indicates whether to use a 'symmetric or 'keypair cipher.
5029 FOR-KEY is human readable identification of the first of the user's
5030 eligible secret keys a keypair decryption targets, or else nil.
5032 Optional RETRIED is for internal use - conveys the number of failed keys
5033 that have been solicited in sequence leading to this current call.
5035 Optional PASSPHRASE enables explicit delivery of the decryption passphrase,
5036 for verification purposes.
5038 Returns the resulting string, or nil if the transformation fails."
5042 (if (not (fboundp 'pgg-encrypt-symmetric
))
5043 (error "Allout encryption depends on a newer version of pgg"))
5045 (let* ((scheme (upcase
5046 (format "%s" (or pgg-scheme pgg-default-scheme
"GPG"))))
5047 (for-key (and (equal key-type
'keypair
)
5049 (split-string (read-string
5050 (format "%s message recipients: "
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"
5059 (if (equal key-type
'keypair
)
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
)
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
))
5070 (catch 'encryption-failed
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
)
5078 (setq passphrase
(allout-obtain-passphrase for-key
5083 retried fetch-pass
)))
5086 (insert (subst-char-in-string ?
\r ?
\n text
))
5091 ((equal key-type
'symmetric
)
5095 (pgg-decrypt (point-min) (point-max) passphrase
)
5097 (pgg-encrypt-symmetric (point-min) (point-max)
5101 (pgg-situate-output (point-min) (point-max))
5102 ;; failed - handle passphrase caching
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."))))
5109 ;; encrypt 'keypair:
5114 (pgg-encrypt for-key
5115 nil
(point-min) (point-max) passphrase
))
5118 (pgg-situate-output (point-min) (point-max))
5119 (error (pgg-remove-passphrase-from-cache target-cache-id t
)
5120 (error "encryption failed"))))
5122 ;; decrypt 'keypair:
5126 (pgg-decrypt (point-min) (point-max) passphrase
))
5129 (pgg-situate-output (point-min) (point-max))
5130 (error (pgg-remove-passphrase-from-cache target-cache-id t
)
5131 (error "decryption failed"))))
5135 (buffer-substring 1 (- (point-max) (if decrypt
0 1))))
5137 ;; validate result - non-empty
5138 (cond ((not result-text
)
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)
5147 ;; Barf if encryption yields extraordinary control chars:
5149 (string-match "[\C-a\C-k\C-o-\C-z\C-@]"
5151 (error (concat "encryption produced unusable"
5152 " non-armored text - reconfigure!")))
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
5161 ;; valid result and regular symmetric - "register"
5162 ;; passphrase with mnemonic aids/cache.
5164 (set-buffer allout-buffer
)
5166 (pgg-add-passphrase-to-cache target-cache-id
5168 (allout-update-passphrase-mnemonic-aids for-key passphrase
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.
5182 When obtaining from the user, symmetric-cipher passphrases are verified
5183 against either, if available and enabled, a random string that was
5184 encrypted against the passphrase, or else against repeated entry by the
5185 user for corroboration.
5187 FOR-KEY is the key for which the passphrase is being obtained.
5189 CACHE-ID is the cache id of the key for the passphrase.
5191 PROMPT-ID is the id for use when prompting the user.
5193 KEY-TYPE is either 'symmetric or 'keypair.
5195 ALLOUT-BUFFER is the buffer containing the entry being en/decrypted.
5197 RETRIED is the number of this attempt to obtain this passphrase.
5199 FETCH-PASS causes the passphrase to be solicited from the user, regardless
5200 of the availability of a cached copy."
5202 (if (not (equal key-type
'symmetric
))
5203 ;; do regular passphrase read on non-symmetric passphrase:
5204 (pgg-read-passphrase (format "%s passphrase%s: "
5205 (upcase (format "%s" (or pgg-scheme
5209 (format " for %s" prompt-id
)
5213 ;; Symmetric hereon:
5216 (set-buffer allout-buffer
)
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
5222 (format " [%s]" allout-passphrase-hint-string
)
5224 (retry-message (if retried
(format " (%s retry)" retried
) ""))
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
))
5229 (prompt full-prompt
)
5230 (verifier-string (allout-get-encryption-passphrase-verifier))
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
)))
5242 ;; Duplicate our handle on the passphrase so it's not clobbered by
5243 ;; deactivate-passwd memory clearing:
5244 (setq got-pass
(format "%s" got-pass
))
5246 (cond (verifier-string
5247 (save-window-excursion
5248 (if (allout-encrypt-string verifier-string
'decrypt
5249 allout-buffer
'symmetric
5250 for-key nil
0 'verifying
5252 (setq confirmation
(format "%s" got-pass
))))
5254 (if (and (not confirmation
)
5256 (concat "Passphrase differs from established"
5257 " - use new one instead? "))
5258 ;; deactivate password for subsequent
5261 (pgg-remove-passphrase-from-cache cache-id t
)
5262 (setq prompt prompt-sans-hint
)
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
5272 ;; right thing, in either case:
5273 (if (not confirmation
)
5275 (pgg-read-passphrase (concat prompt
5276 " ... confirm spelling: ")
5279 (if (equal got-pass 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))
5284 (pgg-remove-passphrase-from-cache cache-id t
)
5285 ;; recurse to this routine:
5286 (pgg-read-passphrase prompt-sans-hint cache-id t
))
5287 (pgg-remove-passphrase-from-cache cache-id t
)
5288 (error "Confirmation failed.")))
5289 ;; reduce opportunity for memory cherry-picking by zeroing duplicate:
5290 (dotimes (i (length got-pass
))
5291 (aset got-pass i
0))
5297 ;;;_ > allout-encrypted-topic-p ()
5298 (defun allout-encrypted-topic-p ()
5299 "True if the current topic is encryptable and encrypted."
5301 (allout-end-of-prefix t
)
5302 (and (string= (buffer-substring-no-properties (1- (point)) (point))
5303 allout-topic-encryption-bullet
)
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.
5312 The key type is one of 'symmetric or 'keypair.
5314 if 'keypair, and some of the user's secret keys are among those for which
5315 the message was encoded, return the identity of the first. otherwise,
5316 return nil for the second item of the pair.
5318 An error is raised if the text is not encrypted."
5319 (require 'pgg-parse
)
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
)
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
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
))
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."
5343 ;; use 20 random ascii characters, across the entire ascii range.
5345 (let ((spew (make-string 20 ?\
0)))
5346 (dotimes (i (length spew
))
5347 (aset spew i
(1+ (random 254))))
5348 (allout-encrypt-string spew nil
(current-buffer) 'symmetric
5349 nil nil
0 passphrase
))
5351 ;;;_ > allout-update-passphrase-mnemonic-aids (for-key passphrase
5353 (defun allout-update-passphrase-mnemonic-aids (for-key passphrase
5355 "Update passphrase verifier and hint strings if necessary.
5357 See `allout-passphrase-verifier-string' and `allout-passphrase-hint-string'
5360 PASSPHRASE is the passphrase being mnemonicized
5362 OUTLINE-BUFFER is the buffer of the outline being adjusted.
5364 These are used to help the user keep track of the passphrase they use for
5365 symmetric encryption in the file.
5367 Behavior is governed by `allout-passphrase-verifier-handling',
5368 `allout-passphrase-hint-handling', and also, controlling whether the values
5369 are preserved on Emacs local file variables,
5370 `allout-enable-file-variable-adjustment'."
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
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
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
)))
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
))
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.
5408 Derived from value of `allout-file-passphrase-verifier-string'."
5410 (let ((verifier-string (and (boundp 'allout-passphrase-verifier-string
)
5411 allout-passphrase-verifier-string
)))
5413 ;; Return it uncollapsed
5414 (subst-char-in-string ?\C-a ?
\n verifier-string
))
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.
5421 \"Otherwise\" includes absence of passphrase verifier."
5423 (set-buffer allout-buffer
)
5424 (and (boundp 'allout-passphrase-verifier-string
)
5425 allout-passphrase-verifier-string
5426 (allout-encrypt-string (allout-get-encryption-passphrase-verifier)
5427 'decrypt allout-buffer
'symmetric
5428 key nil
0 'verifying passphrase
)
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.
5434 EXCEPT-MARK identifies a point whose containing topics should be excluded
5435 from encryption. This supports 'except-current mode of
5436 `allout-encrypt-unencrypted-on-saves'.
5438 Such a topic has the allout-topic-encryption-bullet without an
5439 immediately following '*' that would mark the topic as being encrypted. It
5440 must also have content."
5441 (let (done got content-beg
)
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
))
5451 (goto-char (setq got
(match-beginning 0)))
5452 (if (looking-at "[\n\r]")
5459 ((not (re-search-forward "[\n\r]"))
5468 (setq content-beg
(point))
5470 (allout-end-of-subtree)
5471 (if (or (<= (point) content-beg
)
5473 (<= content-beg except-mark
)
5474 (>= (point) except-mark
)))
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.
5489 EXCEPT-MARK identifies a point whose containing topics should be excluded
5490 from encryption. This supports 'except-current mode of
5491 `allout-encrypt-unencrypted-on-saves'.
5493 If a topic that is currently being edited was encrypted, we return a list
5494 containing the location of the topic and the location of the cursor just
5495 before the topic was encrypted. This can be used, eg, to decrypt the topic
5496 and exactly resituate the cursor if this is being done as part of a file
5497 save. See `allout-encrypt-unencrypted-on-saves' for more info."
5501 (let ((current-mark (point-marker))
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))
5509 (and (boundp 'allout-encrypt-unencrypted-on-saves
)
5510 allout-encrypt-unencrypted-on-saves
5511 (setq bo-subtree
(re-search-forward "[\n\r]"))
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
)))
5521 (allout-toggle-subtree-encryption)
5522 (if (not was-modified
)
5523 (set-buffer-modified-p nil
))
5525 (if (not was-modified
)
5526 (set-buffer-modified-p nil
))
5527 (if editing-topic
(list editing-topic editing-point
))
5532 ;;;_ #9 miscellaneous
5533 ;;;_ > allout-mark-topic ()
5534 (defun allout-mark-topic ()
5535 "Put the region around topic currently containing point."
5538 (allout-goto-prefix)
5540 (allout-end-of-current-subtree)
5541 (exchange-point-and-mark))
5542 ;;;_ > outlineify-sticky ()
5543 ;; outlinify-sticky is correct spelling; provide this alias for sticklers:
5545 (defalias 'outlinify-sticky
'outlineify-sticky
)
5547 (defun outlineify-sticky (&optional arg
)
5548 "Activate outline mode and establish file var so it is started subsequently.
5550 See doc-string for `allout-layout' and `allout-init' for details on
5551 setup for auto-startup."
5558 (goto-char (point-min))
5559 (if (looking-at allout-regexp
)
5561 (allout-open-topic 2)
5562 (insert (concat "Dummy outline topic header - see"
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.
5570 Returns 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
)
5574 (goto-char (point-max))
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
)))
5579 (setq beg
(- (point) 16))
5580 (setq suffix
(buffer-substring-no-properties
5582 (progn (if (re-search-forward "[\n\r]" nil t
)
5585 (setq prefix
(buffer-substring-no-properties
5586 (progn (if (re-search-backward "[\n\r]" nil t
)
5590 (list beg prefix suffix
))
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.
5598 This activity is inhibited if either `enable-local-variables'
5599 `allout-enable-file-variable-adjustment' are nil.
5601 When enabled, an entry for the variable is created if not already present,
5602 or changed if established with a different value. The section for the file
5603 variables, itself, is created if not already present. When created, the
5604 section lines \(including the section line) exist as second-level topics in
5605 a top-level topic at the end of the file.
5607 enable-local-variables must be true for any of this to happen."
5608 (if (not (and enable-local-variables
5609 allout-enable-file-variable-adjustment
))
5612 (let ((section-data (allout-file-vars-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))
5621 (allout-open-topic 0)
5623 (insert "Local emacs vars.\n")
5624 (allout-open-topic 1)
5627 prefix
(buffer-substring-no-properties (progn
5632 (insert "Local variables:\n")
5633 (allout-open-topic 0)
5636 ;; look for existing entry or create one, leaving point for insertion
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
)
5645 (value-end (- line-end
(length suffix
))))
5646 (if (> value-end value-beg
)
5647 (delete-region value-beg value-end
)))
5651 (insert (concat prefix varname
":")))
5652 (insert (format " %S%s" value suffix
))
5657 ;;;_ > solicit-char-in-string (prompt string &optional do-defaulting)
5658 (defun solicit-char-in-string (prompt string
&optional do-defaulting
)
5659 "Solicit (with first arg PROMPT) choice of a character from string STRING.
5661 Optional arg DO-DEFAULTING indicates to accept empty input (CR)."
5663 (let ((new-prompt prompt
)
5667 (message "%s" new-prompt
)
5669 ;; We do our own reading here, so we can circumvent, eg, special
5670 ;; treatment for `?' character. (Oughta use minibuffer keymap instead.)
5672 (char-to-string (let ((cursor-in-echo-area nil
)) (read-char))))
5675 (cond ((string-match (regexp-quote got
) string
) got
)
5676 ((and do-defaulting
(string= got
"\r"))
5677 ;; Return empty string to default:
5679 ((string= got
"\C-g") (signal 'quit nil
))
5681 (setq new-prompt
(concat prompt
5687 ;; got something out of loop - return it:
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.
5694 Representations of actual backslashes - '\\\\\\\\' - are left as a
5697 Optional arg SUCCESSIVE-BACKSLASHES is used internally for recursion."
5699 (if (string= regexp
"")
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)
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
))))
5713 ;;;_ - add-hook definition for divergent emacsen
5714 ;;;_ > add-hook (hook function &optional append)
5715 (if (not (fboundp 'add-hook
))
5716 (defun add-hook (hook function
&optional append
)
5717 "Add to the value of HOOK the function FUNCTION unless already present.
5718 \(It becomes the first hook on the list unless optional APPEND is non-nil, in
5719 which case it becomes the last). HOOK should be a symbol, and FUNCTION may be
5720 any valid function. HOOK's value should be a list of functions, not a single
5721 function. 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
)))
5731 (nconc (symbol-value hook
) (list function
))
5732 (cons function
(symbol-value hook
)))))))
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.
5737 Unless optional argument INPLACE is non-nil, return a new string."
5738 (let ((i (length string
))
5739 (newstr (if inplace string
(copy-sequence string
))))
5742 (if (eq (aref newstr i
) fromchar
)
5743 (aset newstr i tochar
)))
5745 ;;;_ : my-mark-marker to accommodate divergent emacsen:
5746 (defun my-mark-marker (&optional force buffer
)
5747 "Accommodate the different signature for `mark-marker' across Emacsen.
5749 XEmacs takes two optional args, while mainline GNU Emacs does not,
5750 so pass them along when appropriate."
5751 (if (featurep 'xemacs
)
5752 (apply 'mark-marker force buffer
)
5755 ;;;_ #10 Under development
5756 ;;;_ > allout-bullet-isearch (&optional bullet)
5757 (defun allout-bullet-isearch (&optional bullet
)
5758 "Isearch \(regexp) for topic with bullet BULLET."
5761 (setq bullet
(solicit-char-in-string
5762 "ISearch for topic with bullet: "
5763 (regexp-sans-escapes allout-bullets-string
))))
5765 (let ((isearch-regexp t
)
5766 (isearch-string (concat "^"
5767 allout-header-prefix
5770 (isearch-repeat 'forward
)
5772 ;;;_ ? Re hooking up with isearch - use isearch-op-fun rather than
5773 ;;; wrapping the isearch functions.
5775 ;;;_* Local emacs vars.
5776 ;;; The following `allout-layout' local variable setting:
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).
5782 ;;;allout-layout: (0 : -1 -1 0)
5785 ;;; arch-tag: cf38fbc3-c044-450f-8bff-afed8ba5681c
5786 ;;; allout.el ends here